summaryrefslogtreecommitdiffstats
path: root/drivers/sbus/char
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /drivers/sbus/char
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'drivers/sbus/char')
-rw-r--r--drivers/sbus/char/Config.in48
-rw-r--r--drivers/sbus/char/Makefile79
-rw-r--r--drivers/sbus/char/bpp.c1091
-rw-r--r--drivers/sbus/char/bwtwo.c211
-rw-r--r--drivers/sbus/char/cg_common.h28
-rw-r--r--drivers/sbus/char/cgfourteen.c472
-rw-r--r--drivers/sbus/char/cgsix.c642
-rw-r--r--drivers/sbus/char/cgthree.c265
-rw-r--r--drivers/sbus/char/creator.c98
-rw-r--r--drivers/sbus/char/fb.h210
-rw-r--r--drivers/sbus/char/leo.c692
-rw-r--r--drivers/sbus/char/openprom.c611
-rw-r--r--drivers/sbus/char/rtc.c166
-rw-r--r--drivers/sbus/char/suncons.c2575
-rw-r--r--drivers/sbus/char/suncons_font.h258
-rw-r--r--drivers/sbus/char/sunfb.c315
-rw-r--r--drivers/sbus/char/sunkbd.c264
-rw-r--r--drivers/sbus/char/sunkeymap.c18
-rw-r--r--drivers/sbus/char/sunkeymap.map15
-rw-r--r--drivers/sbus/char/sunmouse.c131
-rw-r--r--drivers/sbus/char/sunserial.c1373
-rw-r--r--drivers/sbus/char/sunserial.h41
-rw-r--r--drivers/sbus/char/tcx.c369
-rw-r--r--drivers/sbus/char/vfc.h171
-rw-r--r--drivers/sbus/char/vfc_dev.c693
-rw-r--r--drivers/sbus/char/vfc_i2c.c319
-rw-r--r--drivers/sbus/char/vfc_i2c.h44
-rw-r--r--drivers/sbus/char/weitek.c116
28 files changed, 9355 insertions, 1960 deletions
diff --git a/drivers/sbus/char/Config.in b/drivers/sbus/char/Config.in
new file mode 100644
index 000000000..3f25aa828
--- /dev/null
+++ b/drivers/sbus/char/Config.in
@@ -0,0 +1,48 @@
+comment 'SBUS Frame Buffer support'
+bool 'Sun FB drivers appear in PROCFS' SUN_FBS_IN_PROCFS
+bool 'Load All Supported Drivers' CONFIG_SUN_FB_DISPLAY
+
+if [ "$CONFIG_SUN_FB_DISPLAY" = "n" ]; then
+ bool 'cgsix support' SUN_FB_CGSIX
+ bool 'tcx support' SUN_FB_TCX
+ bool 'cgthree support' SUN_FB_CGTHREE
+ bool 'cgfourteen support' SUN_FB_CGFOURTEEN
+ bool 'bwtwo support' SUN_FB_BWTWO
+ bool 'leo/zx support' SUN_FB_LEO
+ bool 'weitek P9X00 support' TADPOLE_FB_WEITEK
+ bool 'creator support' SUN_FB_CREATOR
+ if [ "$TADPOLE_FB_WEITEK" = "n" ]; then
+ fbs=$SUN_FB_CGSIX
+ fbs=$fbs$SUN_FB_TCX
+ fbs=$fbs$SUN_FB_CGTHREE
+ fbs=$fbs$SUN_FB_BWTWO
+ fbs=$fbs$SUN_FB_CGFOURTEEN
+ fbs=$fbs$SUN_FB_LEO
+ fbs=$fbs$TADPOLE_FB_WEITEK
+ if [ "$fbs" = "nnnnnnnn" ]; then
+ echo "Warning: You have excluded ALL FB Support"
+ echo "Notice: Enabling Generic AutoResolution"
+ define_bool SUN_FB_GENERIC y
+ fi
+ else
+ define_bool SUN_FB_GENERIC y
+ fi
+else
+ define_bool SUN_FB_CGSIX y
+ define_bool SUN_FB_TCX y
+ define_bool SUN_FB_CGTHREE y
+ define_bool SUN_FB_CGFOURTEEN y
+ define_bool SUN_FB_BWTWO y
+ define_bool SUN_FB_LEO y
+ define_bool TADPOLE_FB_WEITEK y
+ define_bool SUN_FB_CREATOR y
+fi
+
+comment 'Misc Linux/SPARC drivers'
+tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO
+tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Bidirectional parallel port support (EXPERIMENTAL)' CONFIG_SUN_BPP
+ tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX
+fi
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
index 5f3bd978b..4ce803b34 100644
--- a/drivers/sbus/char/Makefile
+++ b/drivers/sbus/char/Makefile
@@ -7,7 +7,84 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
+# Dave Redman Frame Buffer tuning support.
+# OK this is kind of ugly but it does allow drivers to be added fairly
+# easily. and you can even choose what sort of support you want.
+ifdef SUN_FB_CGSIX
+ FB_OBJS += cgsix.o
+endif
+ifdef SUN_FB_CGTHREE
+ FB_OBJS += cgthree.o
+endif
+ifdef SUN_FB_TCX
+ FB_OBJS += tcx.o
+endif
+ifdef SUN_FB_BWTWO
+ FB_OBJS += bwtwo.o
+endif
+ifdef SUN_FB_LEO
+ FB_OBJS += leo.o
+endif
+ifdef SUN_FB_CGFOURTEEN
+ FB_OBJS += cgfourteen.o
+endif
+ifdef TADPOLE_FB_WEITEK
+ FB_OBJS += weitek.o
+endif
+ifdef SUN_FB_CREATOR
+ FB_OBJS += creator.o
+endif
+#ifdef SUN_FB_FAST_ONE
+# FB_OBJS += sun_8bit_fast1.o
+#endif
+#ifdef SUN_FB_FAST_TWO
+# FB_OBJS += sun_8bit_fast2.o
+#endif
+#ifdef SUN_FB_FAST_MONO
+# FB_OBJS += sun_mono_fast1.o
+#endif
+#ifdef SUN_FB_GENERIC
+# FB_OBJS += sun_8bit_generic.o
+#endif
+
O_TARGET := sunchar.o
-O_OBJS := suncons.o sunkbd.o sunkeymap.o sunmouse.o sunserial.o
+O_OBJ := ${FB_OBJS} suncons.o sunfb.o
+O_OBJS := ${O_OBJ} sunkbd.o sunkeymap.o sunmouse.o sunserial.o
+M_OBJS :=
+
+ifeq ($(CONFIG_SUN_OPENPROMIO),y)
+O_OBJS += openprom.o
+else
+ ifeq ($(CONFIG_SUN_OPENPROMIO),m)
+ M_OBJS += openprom.o
+ endif
+endif
+
+ifeq ($(CONFIG_SUN_MOSTEK_RTC),y)
+O_OBJS += rtc.o
+else
+ ifeq ($(CONFIG_SUN_MOSTEK_RTC),m)
+ M_OBJS += rtc.o
+ endif
+endif
+
+ifeq ($(CONFIG_SUN_BPP),y)
+O_OBJS += bpp.o
+else
+ ifeq ($(CONFIG_SUN_BPP),m)
+ M_OBJS += bpp.o
+ endif
+endif
+
+ifeq ($(CONFIG_SUN_VIDEOPIX),y)
+O_OBJS += vfc.o
+else
+ ifeq ($(CONFIG_SUN_VIDEOPIX),m)
+ M_OBJS += vfc.o
+ endif
+endif
include $(TOPDIR)/Rules.make
+
+vfc.o: vfc_dev.o vfc_i2c.o
+ $(LD) -r -o vfc.o vfc_dev.o vfc_i2c.o
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
new file mode 100644
index 000000000..2fd138748
--- /dev/null
+++ b/drivers/sbus/char/bpp.c
@@ -0,0 +1,1091 @@
+/*
+ * drivers/sbus/char/bpp.c
+ *
+ * Copyright (c) 1995 Picture Elements
+ * Stephen Williams (steve@icarus.com)
+ * Gus Baldauf (gbaldauf@ix.netcom.com)
+ *
+ * Linux/SPARC port by Peter Zaitcev.
+ * Integration into SPARC tree by Tom Dyas.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+
+#include <asm/uaccess.h>
+
+#if defined(__i386__)
+# include <asm/io.h>
+# include <asm/system.h>
+# include <asm/segment.h>
+#endif
+
+#if defined(__sparc__)
+# include <linux/init.h>
+# include <linux/delay.h> /* udelay() */
+
+# include <asm/oplib.h> /* OpenProm Library */
+# include <asm/sbus.h> /* struct linux_sbus *SBus_chain */
+# include <asm/io.h> /* sparc_alloc_io() */
+#endif
+
+#include <asm/bpp.h>
+
+#define BPP_PROBE_CODE 0x55
+#define BPP_DELAY 100
+
+static const unsigned BPP_MAJOR = LP_MAJOR;
+static const char* dev_name = "bpp";
+
+/* When switching from compatability to a mode where I can read, try
+ the following mode first. */
+
+/* const unsigned char DEFAULT_ECP = 0x10; */
+static const unsigned char DEFAULT_ECP = 0x30;
+static const unsigned char DEFAULT_NIBBLE = 0x00;
+
+/*
+ * These are 1284 time constraints, in units of jiffies.
+ */
+
+static const unsigned long TIME_PSetup = 1;
+static const unsigned long TIME_PResponse = 6;
+static const unsigned long TIME_IDLE_LIMIT = 2000;
+
+/*
+ * One instance per supported subdevice...
+ */
+# define BPP_NO 3
+
+enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP };
+
+struct inst {
+ unsigned present : 1; /* True if the hardware exists */
+ unsigned enhanced : 1; /* True if the hardware in "enhanced" */
+ unsigned opened : 1; /* True if the device is opened already */
+ unsigned run_flag : 1; /* True if waiting for a repeate byte */
+
+ unsigned char direction; /* 0 --> out, 0x20 --> IN */
+ unsigned char pp_state; /* State of host controlled pins. */
+ enum IEEE_Mode mode;
+
+ unsigned char run_length;
+ unsigned char repeat_byte;
+
+ /* These members manage timeouts for programmed delays */
+ struct wait_queue *wait_queue;
+ struct timer_list timer_list;
+};
+
+static struct inst instances[BPP_NO];
+
+#if defined(__i386__)
+
+const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc };
+
+/*
+ * These are for data access.
+ * Control lines accesses are hidden in set_bits() and get_bits().
+ * The exeption is the probe procedure, which is system-dependent.
+ */
+#define bpp_outb_p(data, base) outb_p((data), (base))
+#define bpp_inb(base) inb(base)
+#define bpp_inb_p(base) inb_p(base)
+
+/*
+ * This method takes the pin values mask and sets the hardware pins to
+ * the requested value: 1 == high voltage, 0 == low voltage. This
+ * burries the annoying PC bit inversion and preserves the direction
+ * flag.
+ */
+static void set_pins(unsigned short pins, unsigned minor)
+{
+ unsigned char bits = instances[minor].direction; /* == 0x20 */
+
+ if (! (pins & BPP_PP_nStrobe)) bits |= 1;
+ if (! (pins & BPP_PP_nAutoFd)) bits |= 2;
+ if ( pins & BPP_PP_nInit) bits |= 4;
+ if (! (pins & BPP_PP_nSelectIn)) bits |= 8;
+
+ instances[minor].pp_state = bits;
+
+ outb_p(bits, base_addrs[minor]+2);
+}
+
+static unsigned short get_pins(unsigned minor)
+{
+ unsigned short bits = 0;
+
+ unsigned value = instances[minor].pp_state;
+ if (! (value & 0x01)) bits |= BPP_PP_nStrobe;
+ if (! (value & 0x02)) bits |= BPP_PP_nAutoFd;
+ if (value & 0x04) bits |= BPP_PP_nInit;
+ if (! (value & 0x08)) bits |= BPP_PP_nSelectIn;
+
+ value = inb_p(base_addrs[minor]+1);
+ if (value & 0x08) bits |= BPP_GP_nFault;
+ if (value & 0x10) bits |= BPP_GP_Select;
+ if (value & 0x20) bits |= BPP_GP_PError;
+ if (value & 0x40) bits |= BPP_GP_nAck;
+ if (! (value & 0x80)) bits |= BPP_GP_Busy;
+
+ return bits;
+}
+
+#endif /* __i386__ */
+
+#if defined(__sparc__)
+
+/*
+ * Register block
+ */
+struct bpp_regs {
+ /* DMA registers */
+ __u32 p_csr; /* DMA Control/Status Register */
+ __u32 p_addr; /* Address Register */
+ __u32 p_bcnt; /* Byte Count Register */
+ __u32 p_tst_csr; /* Test Control/Status (DMA2 only) */
+ /* Parallel Port registers */
+ __u16 p_hcr; /* Hardware Configuration Register */
+ __u16 p_ocr; /* Operation Configuration Register */
+ __u8 p_dr; /* Parallel Data Register */
+ __u8 p_tcr; /* Transfer Control Register */
+ __u8 p_or; /* Output Register */
+ __u8 p_ir; /* Input Register */
+ __u16 p_icr; /* Interrupt Control Register */
+};
+
+/* P_CSR. Bits of type RW1 are cleared with writting '1'. */
+#define P_DEV_ID_MASK 0xf0000000 /* R */
+#define P_DEV_ID_ZEBRA 0x40000000
+#define P_DEV_ID_L64854 0xa0000000 /* == NCR 89C100+89C105. Pity. */
+#define P_NA_LOADED 0x08000000 /* R NA wirtten but was not used */
+#define P_A_LOADED 0x04000000 /* R */
+#define P_DMA_ON 0x02000000 /* R DMA is not disabled */
+#define P_EN_NEXT 0x01000000 /* RW */
+#define P_TCI_DIS 0x00800000 /* RW TCI forbidden from interrupts */
+#define P_DIAG 0x00100000 /* RW Disables draining and resetting
+ of P-FIFO on loading of P_ADDR*/
+#define P_BURST_SIZE 0x000c0000 /* RW SBus burst size */
+#define P_BURST_8 0x00000000
+#define P_BURST_4 0x00040000
+#define P_BURST_1 0x00080000 /* "No burst" write */
+#define P_TC 0x00004000 /* RW1 Term Count, can be cleared when
+ P_EN_NEXT=1 */
+#define P_EN_CNT 0x00002000 /* RW */
+#define P_EN_DMA 0x00000200 /* RW */
+#define P_WRITE 0x00000100 /* R DMA dir, 1=to ram, 0=to port */
+#define P_RESET 0x00000080 /* RW */
+#define P_SLAVE_ERR 0x00000040 /* RW1 Access size error */
+#define P_INVALIDATE 0x00000020 /* W Drop P-FIFO */
+#define P_INT_EN 0x00000010 /* RW OK to P_INT_PEND||P_ERR_PEND */
+#define P_DRAINING 0x0000000c /* R P-FIFO is draining to memory */
+#define P_ERR_PEND 0x00000002 /* R */
+#define P_INT_PEND 0x00000001 /* R */
+
+/* P_HCR. Time is in increments of SBus clock. */
+#define P_HCR_TEST 0x8000 /* Allows buried counters to be read */
+#define P_HCR_DSW 0x7f00 /* Data strobe width (in ticks) */
+#define P_HCR_DDS 0x007f /* Data setup before strobe (in ticks) */
+
+/* P_OCR. */
+#define P_OCR_MEM_CLR 0x8000
+#define P_OCR_DATA_SRC 0x4000 /* ) */
+#define P_OCR_DS_DSEL 0x2000 /* ) Bidirectional */
+#define P_OCR_BUSY_DSEL 0x1000 /* ) selects */
+#define P_OCR_ACK_DSEL 0x0800 /* ) */
+#define P_OCR_EN_DIAG 0x0400
+#define P_OCR_BUSY_OP 0x0200 /* Busy operation */
+#define P_OCR_ACK_OP 0x0100 /* Ack operation */
+#define P_OCR_SRST 0x0080 /* Reset state machines. Not selfcleaning. */
+#define P_OCR_IDLE 0x0008 /* PP data transfer state machine is idle */
+#define P_OCR_V_ILCK 0x0002 /* Versatec faded. Zebra only. */
+#define P_OCR_EN_VER 0x0001 /* Enable Versatec (0 - enable). Zebra only. */
+
+/* P_TCR */
+#define P_TCR_DIR 0x08
+#define P_TCR_BUSY 0x04
+#define P_TCR_ACK 0x02
+#define P_TCR_DS 0x01 /* Strobe */
+
+/* P_OR */
+#define P_OR_V3 0x20 /* ) */
+#define P_OR_V2 0x10 /* ) on Zebra only */
+#define P_OR_V1 0x08 /* ) */
+#define P_OR_INIT 0x04
+#define P_OR_AFXN 0x02 /* Auto Feed */
+#define P_OR_SLCT_IN 0x01
+
+/* P_IR */
+#define P_IR_PE 0x04
+#define P_IR_SLCT 0x02
+#define P_IR_ERR 0x01
+
+/* P_ICR */
+#define P_DS_IRQ 0x8000 /* RW1 */
+#define P_ACK_IRQ 0x4000 /* RW1 */
+#define P_BUSY_IRQ 0x2000 /* RW1 */
+#define P_PE_IRQ 0x1000 /* RW1 */
+#define P_SLCT_IRQ 0x0800 /* RW1 */
+#define P_ERR_IRQ 0x0400 /* RW1 */
+#define P_DS_IRQ_EN 0x0200 /* RW Always on rising edge */
+#define P_ACK_IRQ_EN 0x0100 /* RW Always on rising edge */
+#define P_BUSY_IRP 0x0080 /* RW 1= rising edge */
+#define P_BUSY_IRQ_EN 0x0040 /* RW */
+#define P_PE_IRP 0x0020 /* RW 1= rising edge */
+#define P_PE_IRQ_EN 0x0010 /* RW */
+#define P_SLCT_IRP 0x0008 /* RW 1= rising edge */
+#define P_SLCT_IRQ_EN 0x0004 /* RW */
+#define P_ERR_IRP 0x0002 /* RW1 1= rising edge */
+#define P_ERR_IRQ_EN 0x0001 /* RW */
+
+volatile struct bpp_regs *base_addrs[BPP_NO];
+
+static inline void bpp_outb_p(__u8 data, volatile struct bpp_regs *base){
+ base->p_dr = data;
+}
+
+#define bpp_inb_p(base) bpp_inb(base)
+
+static inline __u8 bpp_inb(volatile struct bpp_regs *base){
+ return base->p_dr;
+}
+
+
+static void set_pins(unsigned short pins, unsigned minor)
+{
+ volatile struct bpp_regs *base = base_addrs[minor];
+ unsigned char bits_tcr = 0, bits_or = 0;
+
+ if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR;
+ if ( pins & BPP_PP_nStrobe) bits_tcr |= P_TCR_DS;
+
+ if ( pins & BPP_PP_nAutoFd) bits_or |= P_OR_AFXN;
+ if (! (pins & BPP_PP_nInit)) bits_or |= P_OR_INIT;
+ if (! (pins & BPP_PP_nSelectIn)) bits_or |= P_OR_SLCT_IN;
+
+ base->p_or = bits_or;
+ base->p_tcr = bits_tcr;
+}
+
+/*
+ * i386 people read output pins from a software image.
+ * We may get them back from hardware.
+ * Again, inversion of pins must he buried here.
+ */
+static unsigned short get_pins(unsigned minor)
+{
+ volatile struct bpp_regs *base = base_addrs[minor];
+ unsigned short bits = 0;
+ unsigned value_tcr = base->p_tcr;
+ unsigned value_ir = base->p_ir;
+ unsigned value_or = base->p_or;
+
+ if (value_tcr & P_TCR_DS) bits |= BPP_PP_nStrobe;
+ if (value_or & P_OR_AFXN) bits |= BPP_PP_nAutoFd;
+ if (! (value_or & P_OR_INIT)) bits |= BPP_PP_nInit;
+ if (! (value_or & P_OR_SLCT_IN)) bits |= BPP_PP_nSelectIn;
+
+ if (value_ir & P_IR_ERR) bits |= BPP_GP_nFault;
+ if (! (value_ir & P_IR_SLCT)) bits |= BPP_GP_Select;
+ if (! (value_ir & P_IR_PE)) bits |= BPP_GP_PError;
+ if (! (value_tcr & P_TCR_ACK)) bits |= BPP_GP_nAck;
+ if (value_tcr & P_TCR_BUSY) bits |= BPP_GP_Busy;
+
+ return bits;
+}
+
+#if 0
+/* P3 */
+static inline void bpp_snap(const char *msg, unsigned minor)
+{
+ volatile struct bpp_regs *r = base_addrs[minor];
+ printk("bpp.%s: c=%02x o=%02x i=%02x\n", msg, r->p_tcr, r->p_or, r->p_ir);
+}
+#endif
+
+#endif /* __sparc__ */
+
+/*
+ * This is TRUE if the module_init successfully loaded the module.
+ */
+#if 0
+static int loaded_flag = 0;
+#endif
+
+static void bpp_wake_up(unsigned long val)
+{ wake_up(&instances[val].wait_queue); }
+
+static void snooze(unsigned long snooze_time, unsigned minor)
+{
+ instances[minor].timer_list.expires = jiffies + snooze_time + 1;
+ instances[minor].timer_list.data = minor;
+ add_timer(&instances[minor].timer_list);
+ sleep_on (&instances[minor].wait_queue);
+}
+
+static int wait_for(unsigned short set, unsigned short clr,
+ unsigned long delay, unsigned minor)
+{
+ unsigned short pins = get_pins(minor);
+
+ unsigned long extime = 0;
+
+ /*
+ * Try a real fast scan for the first jiffy, in case the device
+ * responds real good. The first while loop guesses an expire
+ * time accounting for possible wraparound of jiffies.
+ */
+ while (extime <= jiffies) extime = jiffies + 1;
+ while ( (jiffies < extime)
+ && (((pins & set) != set) || ((pins & clr) != 0)) ) {
+ pins = get_pins(minor);
+ }
+
+ delay -= 1;
+
+ /*
+ * If my delay expired or the pins are still not where I want
+ * them, then resort to using the timer and greatly reduce my
+ * sample rate. If the peripheral is going to be slow, this will
+ * give the CPU up to some more worthy process.
+ */
+ while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) {
+
+ snooze(1, minor);
+ pins = get_pins(minor);
+ delay -= 1;
+ }
+
+ if (delay == 0) return -1;
+ else return pins;
+}
+
+/*
+ * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An
+ * errno means something broke, and I do not yet know how to fix it.
+ */
+static int negotiate(unsigned char mode, unsigned minor)
+{
+ int rc;
+ unsigned short pins = get_pins(minor);
+ if (pins & BPP_PP_nSelectIn) return -EIO;
+
+
+ /* Event 0: Write the mode to the data lines */
+ bpp_outb_p(mode, base_addrs[minor]);
+
+ snooze(TIME_PSetup, minor);
+
+ /* Event 1: Strobe the mode code into the peripheral */
+ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor);
+
+ /* Wait for Event 2: Peripheral responds as a 1284 device. */
+ rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault,
+ BPP_GP_nAck,
+ TIME_PResponse,
+ minor);
+
+ if (rc == -1) return -ETIMEDOUT;
+
+ /* Event 3: latch extensibility request */
+ set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor);
+
+ /* ... quick nap while peripheral ponders the byte i'm sending...*/
+ snooze(1, minor);
+
+ /* Event 4: restore strobe, to ACK peripheral's response. */
+ set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
+
+ /* Wait for Event 6: Peripheral latches response bits */
+ rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor);
+ if (rc == -1) return -EIO;
+
+ /* A 1284 device cannot refuse nibble mode */
+ if (mode == DEFAULT_NIBBLE) return 0;
+
+ if (pins & BPP_GP_Select) return 0;
+
+ return -EPROTONOSUPPORT;
+}
+
+static int terminate(unsigned minor)
+{
+ int rc;
+
+ /* Event 22: Request termination of 1284 mode */
+ set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
+
+ /* Wait for Events 23 and 24: ACK termination request. */
+ rc = wait_for(BPP_GP_Busy|BPP_GP_nFault,
+ BPP_GP_nAck,
+ TIME_PSetup+TIME_PResponse,
+ minor);
+
+ instances[minor].direction = 0;
+ instances[minor].mode = COMPATIBILITY;
+
+ if (rc == -1) {
+ return -EIO;
+ }
+
+ /* Event 25: Handshake by lowering nAutoFd */
+ set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor);
+
+ /* Event 26: Peripheral wiggles lines... */
+
+ /* Event 27: Peripheral sets nAck HIGH to ack handshake */
+ rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
+ if (rc == -1) {
+ set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
+ return -EIO;
+ }
+
+ /* Event 28: Finish phase by raising nAutoFd */
+ set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
+
+ return 0;
+}
+
+
+/*
+ * Allow only one process to open the device at a time.
+ */
+static int bpp_open(struct inode *inode, struct file *f)
+{
+ unsigned minor = MINOR(inode->i_rdev);
+ if (minor >= BPP_NO) return -ENODEV;
+ if (! instances[minor].present) return -ENODEV;
+ if (instances[minor].opened) return -EBUSY;
+
+ instances[minor].opened = 1;
+
+ return 0;
+}
+
+/*
+ * When the process closes the device, this method is called to clean
+ * up and reset the hardware. Always leave the device in compatibility
+ * mode as this is a reasonable place to clean up from messes made by
+ * ioctls, or other mayhem.
+ */
+static void bpp_release(struct inode *inode, struct file *f)
+{
+ unsigned minor = MINOR(inode->i_rdev);
+ instances[minor].opened = 0;
+
+ if (instances[minor].mode != COMPATIBILITY)
+ terminate(minor);
+}
+
+static long read_nibble(unsigned minor, char *c, unsigned long cnt)
+{
+ unsigned long remaining = cnt;
+ long rc;
+
+ while (remaining > 0) {
+ unsigned char byte = 0;
+ int pins;
+
+ /* Event 7: request nibble */
+ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
+
+ /* Wait for event 9: Peripher strobes first nibble */
+ pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
+ if (pins == -1) return -ETIMEDOUT;
+
+ /* Event 10: I handshake nibble */
+ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
+ if (pins & BPP_GP_nFault) byte |= 0x01;
+ if (pins & BPP_GP_Select) byte |= 0x02;
+ if (pins & BPP_GP_PError) byte |= 0x04;
+ if (pins & BPP_GP_Busy) byte |= 0x08;
+
+ /* Wait for event 11: Peripheral handshakes nibble */
+ rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
+
+ /* Event 7: request nibble */
+ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
+
+ /* Wait for event 9: Peripher strobes first nibble */
+ pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor);
+ if (rc == -1) return -ETIMEDOUT;
+
+ /* Event 10: I handshake nibble */
+ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
+ if (pins & BPP_GP_nFault) byte |= 0x10;
+ if (pins & BPP_GP_Select) byte |= 0x20;
+ if (pins & BPP_GP_PError) byte |= 0x40;
+ if (pins & BPP_GP_Busy) byte |= 0x80;
+
+ put_user_ret(byte, c, -EFAULT);
+ c += 1;
+ remaining -= 1;
+
+ /* Wait for event 11: Peripheral handshakes nibble */
+ rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
+ if (rc == -1) return -EIO;
+ }
+
+ return cnt - remaining;
+}
+
+static long read_ecp(unsigned minor, char *c, unsigned long cnt)
+{
+ unsigned long remaining;
+ long rc;
+
+ /* Turn ECP mode from forward to reverse if needed. */
+ if (! instances[minor].direction) {
+ unsigned short pins = get_pins(minor);
+
+ /* Event 38: Turn the bus around */
+ instances[minor].direction = 0x20;
+ pins &= ~BPP_PP_nAutoFd;
+ set_pins(pins, minor);
+
+ /* Event 39: Set pins for reverse mode. */
+ snooze(TIME_PSetup, minor);
+ set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
+
+ /* Wait for event 40: Peripheral ready to be strobed */
+ rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor);
+ if (rc == -1) return -ETIMEDOUT;
+ }
+
+ remaining = cnt;
+
+ while (remaining > 0) {
+
+ /* If there is a run length for a repeated byte, repeat */
+ /* that byte a few times. */
+ if (instances[minor].run_length && !instances[minor].run_flag) {
+
+ char buffer[128];
+ unsigned idx;
+ unsigned repeat = remaining < instances[minor].run_length
+ ? remaining
+ : instances[minor].run_length;
+
+ for (idx = 0 ; idx < repeat ; idx += 1)
+ buffer[idx] = instances[minor].repeat_byte;
+
+ copy_to_user_ret(c, buffer, repeat, -EFAULT);
+ remaining -= repeat;
+ c += repeat;
+ instances[minor].run_length -= repeat;
+ }
+
+ if (remaining == 0) break;
+
+
+ /* Wait for Event 43: Data active on the bus. */
+ rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
+ if (rc == -1) break;
+
+ if (rc & BPP_GP_Busy) {
+ /* OK, this is data. read it in. */
+ unsigned char byte = bpp_inb(base_addrs[minor]);
+ put_user_ret(byte, c, -EFAULT);
+ c += 1;
+ remaining -= 1;
+
+ if (instances[minor].run_flag) {
+ instances[minor].repeat_byte = byte;
+ instances[minor].run_flag = 0;
+ }
+
+ } else {
+ unsigned char byte = bpp_inb(base_addrs[minor]);
+ if (byte & 0x80) {
+ printk("bpp%d: "
+ "Ignoring ECP channel %u from device.\n",
+ minor, byte & 0x7f);
+ } else {
+ instances[minor].run_length = byte;
+ instances[minor].run_flag = 1;
+ }
+ }
+
+ /* Event 44: I got it. */
+ set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor);
+
+ /* Wait for event 45: peripheral handshake */
+ rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
+ if (rc == -1) return -ETIMEDOUT;
+
+ /* Event 46: Finish handshake */
+ set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
+
+ }
+
+
+ return cnt - remaining;
+}
+
+static long bpp_read(struct inode *inode, struct file *f,
+ char *c, unsigned long cnt)
+{
+ long rc;
+ const unsigned minor = MINOR(inode->i_rdev);
+ if (minor >= BPP_NO) return -ENODEV;
+ if (!instances[minor].present) return -ENODEV;
+
+ switch (instances[minor].mode) {
+
+ default:
+ if (instances[minor].mode != COMPATIBILITY)
+ terminate(minor);
+
+ if (instances[minor].enhanced) {
+ /* For now, do all reads with ECP-RLE mode */
+ unsigned short pins;
+
+ rc = negotiate(DEFAULT_ECP, minor);
+ if (rc < 0) break;
+
+ instances[minor].mode = ECP_RLE;
+
+ /* Event 30: set nAutoFd low to setup for ECP mode */
+ pins = get_pins(minor);
+ pins &= ~BPP_PP_nAutoFd;
+ set_pins(pins, minor);
+
+ /* Wait for Event 31: peripheral ready */
+ rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
+ if (rc == -1) return -ETIMEDOUT;
+
+ rc = read_ecp(minor, c, cnt);
+
+ } else {
+ rc = negotiate(DEFAULT_NIBBLE, minor);
+ if (rc < 0) break;
+
+ instances[minor].mode = NIBBLE;
+
+ rc = read_nibble(minor, c, cnt);
+ }
+ break;
+
+ case NIBBLE:
+ rc = read_nibble(minor, c, cnt);
+ break;
+
+ case ECP:
+ case ECP_RLE:
+ rc = read_ecp(minor, c, cnt);
+ break;
+
+ }
+
+
+ return rc;
+}
+
+/*
+ * Compatibility mode handshaking is a matter of writing data,
+ * strobing it, and waiting for the printer to stop being busy.
+ */
+static long write_compat(unsigned minor, const char *c, unsigned long cnt)
+{
+ long rc;
+ unsigned short pins = get_pins(minor);
+
+ unsigned long remaining = cnt;
+
+ while (remaining > 0) {
+ unsigned char byte;
+ c += 1;
+ get_user_ret(byte, c, -EFAULT);
+
+ rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor);
+ if (rc == -1) return -ETIMEDOUT;
+
+ bpp_outb_p(byte, base_addrs[minor]);
+ remaining -= 1;
+ /* snooze(1, minor); */
+
+ pins &= ~BPP_PP_nStrobe;
+ set_pins(pins, minor);
+
+ rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
+
+ pins |= BPP_PP_nStrobe;
+ set_pins(pins, minor);
+ }
+
+ return cnt - remaining;
+}
+
+/*
+ * Write data using ECP mode. Watch out that the port may be set up
+ * for reading. If so, turn the port around.
+ */
+static long write_ecp(unsigned minor, const char *c, unsigned long cnt)
+{
+ unsigned short pins = get_pins(minor);
+ unsigned long remaining = cnt;
+
+ if (instances[minor].direction) {
+ int rc;
+
+ /* Event 47 Request bus be turned around */
+ pins |= BPP_PP_nInit;
+ set_pins(pins, minor);
+
+ /* Wait for Event 49: Peripheral relinquished bus */
+ rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
+
+ pins |= BPP_PP_nAutoFd;
+ instances[minor].direction = 0;
+ set_pins(pins, minor);
+ }
+
+ while (remaining > 0) {
+ unsigned char byte;
+ int rc;
+
+ get_user_ret(byte, c, -EFAULT);
+
+ rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor);
+ if (rc == -1) return -ETIMEDOUT;
+
+ c += 1;
+
+ bpp_outb_p(byte, base_addrs[minor]);
+
+ pins &= ~BPP_PP_nStrobe;
+ set_pins(pins, minor);
+
+ pins |= BPP_PP_nStrobe;
+ rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
+ if (rc == -1) return -EIO;
+
+ set_pins(pins, minor);
+ }
+
+ return cnt - remaining;
+}
+
+/*
+ * Write to the peripheral. Be sensitive of the current mode. If I'm
+ * in a mode that can be turned around (ECP) then just do
+ * that. Otherwise, terminate and do my writing in compat mode. This
+ * is the safest course as any device can handle it.
+ */
+static long bpp_write(struct inode *inode, struct file *f,
+ const char *c, unsigned long cnt)
+{
+ long errno = 0;
+ unsigned minor = MINOR(inode->i_rdev);
+ if (minor >= BPP_NO) return -ENODEV;
+ if (!instances[minor].present) return -ENODEV;
+
+ switch (instances[minor].mode) {
+
+ case ECP:
+ case ECP_RLE:
+ errno = write_ecp(minor, c, cnt);
+ break;
+ case COMPATIBILITY:
+ errno = write_compat(minor, c, cnt);
+ break;
+ default:
+ terminate(minor);
+ errno = write_compat(minor, c, cnt);
+ }
+
+ return errno;
+}
+
+static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd,
+ unsigned long arg)
+{
+ int errno = 0;
+
+ unsigned minor = MINOR(inode->i_rdev);
+ if (minor >= BPP_NO) return -ENODEV;
+ if (!instances[minor].present) return -ENODEV;
+
+
+ switch (cmd) {
+
+ case BPP_PUT_PINS:
+ set_pins(arg, minor);
+ break;
+
+ case BPP_GET_PINS:
+ errno = get_pins(minor);
+ break;
+
+ case BPP_PUT_DATA:
+ bpp_outb_p(arg, base_addrs[minor]);
+ break;
+
+ case BPP_GET_DATA:
+ errno = bpp_inb_p(base_addrs[minor]);
+ break;
+
+ case BPP_SET_INPUT:
+ if (arg)
+ if (instances[minor].enhanced) {
+ unsigned short bits = get_pins(minor);
+ instances[minor].direction = 0x20;
+ set_pins(bits, minor);
+ } else {
+ errno = -ENOTTY;
+ }
+ else {
+ unsigned short bits = get_pins(minor);
+ instances[minor].direction = 0x00;
+ set_pins(bits, minor);
+ }
+ break;
+
+ default:
+ errno = -EINVAL;
+ }
+
+ return errno;
+}
+
+static struct file_operations bpp_fops = {
+ NULL, /* bpp_lseek */
+ bpp_read,
+ bpp_write,
+ NULL, /* bpp_readdir */
+ NULL, /* bpp_select */
+ bpp_ioctl,
+ NULL, /* bpp_mmap */
+ bpp_open,
+ bpp_release,
+};
+
+#if defined(__i386__)
+
+#define collectLptPorts() {}
+
+static void probeLptPort(unsigned idx)
+{
+ unsigned int testvalue;
+ const unsigned short lpAddr = base_addrs[idx];
+
+ instances[idx].present = 0;
+ instances[idx].enhanced = 0;
+ instances[idx].direction = 0;
+ instances[idx].mode = COMPATIBILITY;
+ instances[idx].wait_queue = 0;
+ instances[idx].run_length = 0;
+ instances[idx].run_flag = 0;
+ init_timer(&instances[idx].timer_list);
+ instances[idx].timer_list.function = bpp_wake_up;
+ if (check_region(lpAddr,3)) return;
+
+ /*
+ * First, make sure the instance exists. Do this by writing to
+ * the data latch and reading the value back. If the port *is*
+ * present, test to see if it supports extended-mode
+ * operation. This will be required for IEEE1284 reverse
+ * transfers.
+ */
+
+ outb_p(BPP_PROBE_CODE, lpAddr);
+ for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
+ ;
+ testvalue = inb_p(lpAddr);
+ if (testvalue == BPP_PROBE_CODE) {
+ unsigned save;
+ instances[idx].present = 1;
+
+ request_region(lpAddr,3, dev_name);
+ save = inb_p(lpAddr+2);
+ for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
+ ;
+ outb_p(save|0x20, lpAddr+2);
+ for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
+ ;
+ outb_p(~BPP_PROBE_CODE, lpAddr);
+ for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
+ ;
+ testvalue = inb_p(lpAddr);
+ if ((testvalue&0xff) == (0xff&~BPP_PROBE_CODE))
+ instances[idx].enhanced = 0;
+ else
+ instances[idx].enhanced = 1;
+ outb_p(save, lpAddr+2);
+ }
+
+ /*
+ * Leave the port in compat idle mode.
+ */
+ set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
+
+ printk("bpp%d: Port at 0x%03x: Enhanced mode %s\n", idx, base_addrs[idx],
+ instances[idx].enhanced? "SUPPORTED" : "UNAVAILABLE");
+}
+
+static inline void freeLptPort(int idx)
+{
+ release_region(base_addrs[idx], 3);
+}
+
+#endif
+
+#if defined(__sparc__)
+
+static volatile struct bpp_regs *map_bpp(struct linux_sbus_device *dev, int idx)
+{
+ volatile struct bpp_regs *regs;
+
+ /* Apply ranges to here, do not pollute Sbus devices list. */
+ struct linux_prom_registers areg;
+
+ /*
+ * PROM reports different numbers on Zebra and on DMA2.
+ * We need to figure out when to apply parent ranges.
+ * printk will show this on different machines.
+ */
+
+ areg = dev->reg_addrs[0];
+ printk("bpp%d.map_bpp: 0x%x.%p[0x%x] i=%d\n", idx,
+ areg.which_io, areg.phys_addr, areg.reg_size,
+ dev->irqs[0].pri);
+ /* IPC Zebra 1.fa200000[1c] i=2 */
+ /** prom_apply_sbus_ranges (&areg, 1); **/
+
+ regs = sparc_alloc_io (areg.phys_addr, 0,
+ sizeof(struct bpp_regs), "bpp",
+ areg.which_io, 0x0);
+
+ return regs;
+}
+
+static int collectLptPorts(void)
+{
+ struct linux_sbus *bus;
+ struct linux_sbus_device *dev;
+ int count;
+
+ count = 0;
+ for_all_sbusdev(dev, bus) {
+ if (strcmp(dev->prom_name, "SUNW,bpp") == 0) {
+ if (count >= BPP_NO) {
+ printk(KERN_NOTICE
+ "bpp: More than %d bpp ports,"
+ " rest is ignored\n", BPP_NO);
+ return count;
+ }
+ base_addrs[count] = map_bpp(dev, count);
+ count++;
+ }
+ }
+ return count;
+}
+
+static void probeLptPort(unsigned idx)
+{
+ volatile struct bpp_regs *rp = base_addrs[idx];
+ __u32 csr;
+ char *brand;
+
+ instances[idx].present = 0;
+ instances[idx].enhanced = 0;
+ instances[idx].direction = 0;
+ instances[idx].mode = COMPATIBILITY;
+ instances[idx].wait_queue = 0;
+ instances[idx].run_length = 0;
+ instances[idx].run_flag = 0;
+ init_timer(&instances[idx].timer_list);
+ instances[idx].timer_list.function = bpp_wake_up;
+
+ if (rp == 0) return;
+
+ instances[idx].present = 1;
+ instances[idx].enhanced = 1; /* Sure */
+
+ if (((csr = rp->p_csr) & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
+ udelay(20);
+ csr = rp->p_csr;
+ if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
+ printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr);
+ }
+ }
+ printk("bpp%d: reset with 0x%08x ..", idx, csr);
+ rp->p_csr = (csr | P_RESET) & ~P_INT_EN;
+ udelay(500);
+ rp->p_csr &= ~P_RESET;
+ printk(" done with csr=0x%08x ocr=0x%04x\n", rp->p_csr, rp->p_ocr);
+
+ switch (rp->p_csr & P_DEV_ID_MASK) {
+ case P_DEV_ID_ZEBRA:
+ brand = "Zebra";
+ break;
+ case P_DEV_ID_L64854:
+ brand = "DMA2";
+ break;
+ default:
+ brand = "Unknown";
+ }
+ printk("bpp%d: %s at 0x%p\n", idx, brand, rp);
+
+ /*
+ * Leave the port in compat idle mode.
+ */
+ set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
+
+ return;
+}
+
+static inline void freeLptPort(int idx)
+{
+ sparc_free_io ((void *)base_addrs[idx], sizeof(struct bpp_regs));
+}
+
+#endif
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int bpp_init(void))
+#endif
+{
+ int rc;
+ unsigned idx;
+
+ rc = collectLptPorts();
+ if (rc == 0)
+ return -ENODEV;
+
+ rc = register_chrdev(BPP_MAJOR, dev_name, &bpp_fops);
+ if (rc < 0)
+ return rc;
+
+ for (idx = 0; idx < BPP_NO; idx += 1) {
+ instances[idx].opened = 0;
+ probeLptPort(idx);
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ unsigned idx;
+
+ unregister_chrdev(BPP_MAJOR, dev_name);
+
+ for (idx = 0 ; idx < BPP_NO ; idx += 1) {
+ if (instances[idx].present)
+ freeLptPort(idx);
+ }
+}
+#endif
diff --git a/drivers/sbus/char/bwtwo.c b/drivers/sbus/char/bwtwo.c
new file mode 100644
index 000000000..be68d09c9
--- /dev/null
+++ b/drivers/sbus/char/bwtwo.c
@@ -0,0 +1,211 @@
+/* $Id: bwtwo.c,v 1.13 1997/04/14 17:04:55 jj Exp $
+ * bwtwo.c: bwtwo console driver
+ *
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/* OBio addresses for the bwtwo registers */
+#define BWTWO_REGISTER_OFFSET 0x400000
+
+struct bwtwo_regs {
+ __volatile__ struct bt_regs bt;
+ __volatile__ __u8 control;
+ __volatile__ __u8 status;
+ __volatile__ __u8 cursor_start;
+ __volatile__ __u8 cursor_end;
+ __volatile__ __u8 h_blank_start;
+ __volatile__ __u8 h_blank_end;
+ __volatile__ __u8 h_sync_start;
+ __volatile__ __u8 h_sync_end;
+ __volatile__ __u8 comp_sync_end;
+ __volatile__ __u8 v_blank_start_high;
+ __volatile__ __u8 v_blank_start_low;
+ __volatile__ __u8 v_blank_end;
+ __volatile__ __u8 v_sync_start;
+ __volatile__ __u8 v_sync_end;
+ __volatile__ __u8 xfer_holdoff_start;
+ __volatile__ __u8 xfer_holdoff_end;
+};
+
+/* Status Register Constants */
+#define BWTWO_SR_RES_MASK 0x70
+#define BWTWO_SR_1600_1280 0x50
+#define BWTWO_SR_1152_900_76_A 0x40
+#define BWTWO_SR_1152_900_76_B 0x60
+#define BWTWO_SR_ID_MASK 0x0f
+#define BWTWO_SR_ID_MONO 0x02
+#define BWTWO_SR_ID_MONO_ECL 0x03
+#define BWTWO_SR_ID_MSYNC 0x04
+
+/* Control Register Constants */
+#define BWTWO_CTL_ENABLE_INTS 0x80
+#define BWTWO_CTL_ENABLE_VIDEO 0x40
+#define BWTWO_CTL_ENABLE_TIMING 0x20
+#define BWTWO_CTL_ENABLE_CURCMP 0x10
+#define BWTWO_CTL_XTAL_MASK 0x0C
+#define BWTWO_CTL_DIVISOR_MASK 0x03
+
+/* Status Register Constants */
+#define BWTWO_STAT_PENDING_INT 0x80
+#define BWTWO_STAT_MSENSE_MASK 0x70
+#define BWTWO_STAT_ID_MASK 0x0f
+
+
+static int
+bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+ long base, fbinfo_t *fb)
+{
+ uint size, map_offset, r;
+ int map_size;
+
+ map_size = size = vma->vm_end - vma->vm_start;
+
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages */
+ vma->vm_flags |= FB_MMAP_VM_FLAGS;
+
+ /* This routine should also map the register if asked for,
+ * but we don't do that yet.
+ */
+ map_offset = get_phys ((unsigned long) fb->base);
+ r = io_remap_page_range (vma->vm_start, map_offset, map_size,
+ vma->vm_page_prot, fb->space);
+ if (r) return -EAGAIN;
+ vma->vm_inode = inode;
+ inode->i_count++;
+ return 0;
+}
+
+static void
+bwtwo_blank (fbinfo_t *fb)
+{
+ fb->info.bwtwo.regs->control &= ~BWTWO_CTL_ENABLE_VIDEO;
+}
+
+static void
+bwtwo_unblank (fbinfo_t *fb)
+{
+ fb->info.bwtwo.regs->control |= BWTWO_CTL_ENABLE_VIDEO;
+}
+
+
+static u8 bw2regs_1600[] __initdata = {
+ 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
+ 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
+ 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x21, 0
+};
+
+static u8 bw2regs_ecl[] __initdata = {
+ 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
+ 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
+ 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x20, 0
+};
+
+static u8 bw2regs_analog[] __initdata = {
+ 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
+ 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
+ 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x20, 0
+};
+
+static u8 bw2regs_76hz[] __initdata = {
+ 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
+ 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
+ 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x24, 0
+};
+
+static u8 bw2regs_66hz[] __initdata = {
+ 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
+ 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
+ 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x20, 0
+};
+
+__initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, u32 bwtwo, int bw2_io,
+ struct linux_sbus_device *sbdp))
+{
+ printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
+ fb->type.fb_cmsize = 0;
+ fb->mmap = bwtwo_mmap;
+ fb->loadcmap = 0;
+ fb->ioctl = 0;
+ fb->reset = 0;
+ fb->blank = bwtwo_blank;
+ fb->unblank = bwtwo_unblank;
+
+ fb->info.bwtwo.regs =
+ sparc_alloc_io (bwtwo + BWTWO_REGISTER_OFFSET,
+ 0, sizeof (struct bwtwo_regs),
+ "bwtwo_regs", bw2_io, 0);
+
+ if (!prom_getbool(sbdp->prom_node, "width")) {
+ /* Ugh, broken PROM didn't initialize us.
+ * Let's deal with this ourselves.
+ */
+ u8 status, mon;
+ u8 *p;
+
+ status = fb->info.bwtwo.regs->status;
+ mon = status & BWTWO_SR_RES_MASK;
+ switch (status & BWTWO_SR_ID_MASK) {
+ case BWTWO_SR_ID_MONO_ECL:
+ if (mon == BWTWO_SR_1600_1280) {
+ p = bw2regs_1600;
+ fb->type.fb_width = 1600;
+ fb->type.fb_height = 1280;
+ } else {
+ p = bw2regs_ecl;
+ }
+ break;
+ case BWTWO_SR_ID_MONO:
+ p = bw2regs_analog;
+ break;
+ case BWTWO_SR_ID_MSYNC:
+ if (mon == BWTWO_SR_1152_900_76_A ||
+ mon == BWTWO_SR_1152_900_76_B) {
+ p = bw2regs_76hz;
+ } else {
+ p = bw2regs_66hz;
+ }
+ break;
+ default:
+ prom_printf("bwtwo: can't handle SR %02x\n",
+ status);
+ prom_halt();
+ return; /* fool gcc. */
+ }
+ for ( ; *p; p += 2)
+ ((u8 *)fb->info.bwtwo.regs)[p[0]] = p[1];
+ }
+
+ if(!fb->base)
+ fb->base = (unsigned long) sparc_alloc_io(bwtwo, 0,
+ ((fb->type.fb_depth*fb->type.fb_height*fb->type.fb_width)/8),
+ "bwtwo_fbase", bw2_io, 0);
+
+ if (slot && sun_prom_console_id != slot)
+ bwtwo_blank (fb);
+}
+
diff --git a/drivers/sbus/char/cg_common.h b/drivers/sbus/char/cg_common.h
new file mode 100644
index 000000000..c4376f66c
--- /dev/null
+++ b/drivers/sbus/char/cg_common.h
@@ -0,0 +1,28 @@
+/* sun_cg_common.h
+ * contains the definitions of the structures that various sun
+ * frame buffer can use to do console driver stuff.
+ *
+ * This is not in sun_framebuffer.h because you may not want cgXX
+ * support so you wont require this.
+ *
+ */
+
+#define BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2)) /* (x / 4) * 3 */
+#define BT_D4M4(x) ((x) & ~3) /* (x / 4) * 4 */
+
+#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
+#define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
+
+struct bt_regs {
+ volatile unsigned int addr; /* address register */
+ volatile unsigned int color_map; /* color map */
+ volatile unsigned int control; /* control register */
+ volatile unsigned int cursor; /* cursor map register */
+};
+
+/* The cg3 driver, obio space addresses for mapping the cg3 stuff */
+/* We put these constants here, because the cg14 driver initially will emulate a cg3 */
+#define CG3_REGS 0x400000
+#define CG3_RAM 0x800000
+
+
diff --git a/drivers/sbus/char/cgfourteen.c b/drivers/sbus/char/cgfourteen.c
new file mode 100644
index 000000000..d42a4343c
--- /dev/null
+++ b/drivers/sbus/char/cgfourteen.c
@@ -0,0 +1,472 @@
+/* $Id: cgfourteen.c,v 1.19 1997/04/14 17:04:57 jj Exp $
+ * cgfourteen.c: Sun SparcStation console support.
+ *
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * TODO:
+ *
+ * Add the ioctls for CLUT manipulation.
+ * Map only the amount requested, not a constant amount.
+ * XBGR mapping.
+ * Add the interrupt handler.
+*/
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+
+#define CG14_MCR_INTENABLE_SHIFT 7
+#define CG14_MCR_INTENABLE_MASK 0x80
+#define CG14_MCR_VIDENABLE_SHIFT 6
+#define CG14_MCR_VIDENABLE_MASK 0x40
+#define CG14_MCR_PIXMODE_SHIFT 4
+#define CG14_MCR_PIXMODE_MASK 0x30
+#define CG14_MCR_TMR_SHIFT 2
+#define CG14_MCR_TMR_MASK 0x0c
+#define CG14_MCR_TMENABLE_SHIFT 1
+#define CG14_MCR_TMENABLE_MASK 0x02
+#define CG14_MCR_RESET_SHIFT 0
+#define CG14_MCR_RESET_MASK 0x01
+#define CG14_REV_REVISION_SHIFT 4
+#define CG14_REV_REVISION_MASK 0xf0
+#define CG14_REV_IMPL_SHIFT 0
+#define CG14_REV_IMPL_MASK 0x0f
+#define CG14_VBR_FRAMEBASE_SHIFT 12
+#define CG14_VBR_FRAMEBASE_MASK 0x00fff000
+#define CG14_VMCR1_SETUP_SHIFT 0
+#define CG14_VMCR1_SETUP_MASK 0x000001ff
+#define CG14_VMCR1_VCONFIG_SHIFT 9
+#define CG14_VMCR1_VCONFIG_MASK 0x00000e00
+#define CG14_VMCR2_REFRESH_SHIFT 0
+#define CG14_VMCR2_REFRESH_MASK 0x00000001
+#define CG14_VMCR2_TESTROWCNT_SHIFT 1
+#define CG14_VMCR2_TESTROWCNT_MASK 0x00000002
+#define CG14_VMCR2_FBCONFIG_SHIFT 2
+#define CG14_VMCR2_FBCONFIG_MASK 0x0000000c
+#define CG14_VCR_REFRESHREQ_SHIFT 0
+#define CG14_VCR_REFRESHREQ_MASK 0x000003ff
+#define CG14_VCR1_REFRESHENA_SHIFT 10
+#define CG14_VCR1_REFRESHENA_MASK 0x00000400
+#define CG14_VCA_CAD_SHIFT 0
+#define CG14_VCA_CAD_MASK 0x000003ff
+#define CG14_VCA_VERS_SHIFT 10
+#define CG14_VCA_VERS_MASK 0x00000c00
+#define CG14_VCA_RAMSPEED_SHIFT 12
+#define CG14_VCA_RAMSPEED_MASK 0x00001000
+#define CG14_VCA_8MB_SHIFT 13
+#define CG14_VCA_8MB_MASK 0x00002000
+
+#define CG14_MCR_PIXMODE_8 0
+#define CG14_MCR_PIXMODE_16 2
+#define CG14_MCR_PIXMODE_32 3
+
+struct cg14_regs{
+ volatile u8 mcr; /* Master Control Reg */
+ volatile u8 ppr; /* Packed Pixel Reg */
+ volatile u8 tms[2]; /* Test Mode Status Regs */
+ volatile u8 msr; /* Master Status Reg */
+ volatile u8 fsr; /* Fault Status Reg */
+ volatile u8 rev; /* Revision & Impl */
+ volatile u8 ccr; /* Clock Control Reg */
+ volatile u32 tmr; /* Test Mode Read Back */
+ volatile u8 mod; /* Monitor Operation Data Reg */
+ volatile u8 acr; /* Aux Control */
+ u8 xxx0[6];
+ volatile u16 hct; /* Hor Counter */
+ volatile u16 vct; /* Vert Counter */
+ volatile u16 hbs; /* Hor Blank Start */
+ volatile u16 hbc; /* Hor Blank Clear */
+ volatile u16 hss; /* Hor Sync Start */
+ volatile u16 hsc; /* Hor Sync Clear */
+ volatile u16 csc; /* Composite Sync Clear */
+ volatile u16 vbs; /* Vert Blank Start */
+ volatile u16 vbc; /* Vert Blank Clear */
+ volatile u16 vss; /* Vert Sync Start */
+ volatile u16 vsc; /* Vert Sync Clear */
+ volatile u16 xcs;
+ volatile u16 xcc;
+ volatile u16 fsa; /* Fault Status Address */
+ volatile u16 adr; /* Address Registers */
+ u8 xxx1[0xce];
+ volatile u8 pcg[0x100]; /* Pixel Clock Generator */
+ volatile u32 vbr; /* Frame Base Row */
+ volatile u32 vmcr; /* VBC Master Control */
+ volatile u32 vcr; /* VBC refresh */
+ volatile u32 vca; /* VBC Config */
+};
+
+#define CG14_CCR_ENABLE 0x04
+#define CG14_CCR_SELECT 0x02 /* HW/Full screen */
+
+struct cg14_cursor {
+ volatile u32 cpl0[32]; /* Enable plane 0 */
+ volatile u32 cpl1[32]; /* Color selection plane */
+ volatile u8 ccr; /* Cursor Control Reg */
+ u8 xxx0[3];
+ volatile u16 cursx; /* Cursor x,y position */
+ volatile u16 cursy; /* Cursor x,y position */
+ volatile u32 color0;
+ volatile u32 color1;
+ u32 xxx1[0x1bc];
+ volatile u32 cpl0i[32]; /* Enable plane 0 autoinc */
+ volatile u32 cpl1i[32]; /* Color selection autoinc */
+};
+
+struct cg14_dac {
+ volatile u8 addr; /* Address Register */
+ u8 xxx0[255];
+ volatile u8 glut; /* Gamma table */
+ u8 xxx1[255];
+ volatile u8 select; /* Register Select */
+ u8 xxx2[255];
+ volatile u8 mode; /* Mode Register */
+};
+
+struct cg14_xlut{
+ volatile u8 x_xlut [256];
+ volatile u8 x_xlutd [256];
+ u8 xxx0[0x600];
+ volatile u8 x_xlut_inc [256];
+ volatile u8 x_xlutd_inc [256];
+};
+
+/* Color look up table (clut) */
+/* Each one of these arrays hold the color lookup table (for 256
+ * colors) for each MDI page (I assume then there should be 4 MDI
+ * pages, I still wonder what they are. I have seen NeXTStep split
+ * the screen in four parts, while operating in 24 bits mode. Each
+ * integer holds 4 values: alpha value (transparency channel, thanks
+ * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue
+ *
+ * I currently use the clut instead of the Xlut
+ */
+struct cg14_clut {
+ unsigned int c_clut [256];
+ unsigned int c_clutd [256]; /* i wonder what the 'd' is for */
+ unsigned int c_clut_inc [256];
+ unsigned int c_clutd_inc [256];
+};
+
+static int
+cg14_mmap (struct inode *inode, struct file *file,
+ struct vm_area_struct *vma, long base, fbinfo_t *fb)
+{
+ uint size, page, r, map_size;
+ uint map_offset = 0;
+ uint ram_size = fb->info.cg14.ramsize;
+
+ printk ("RAMSIZE=%d\n", ram_size);
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages */
+ vma->vm_flags |= FB_MMAP_VM_FLAGS;
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ){
+ switch (vma->vm_offset+page){
+ case CG3_MMAP_OFFSET-0x7000:
+ printk ("Wee! They are mapping the register, report this to miguel@gnu.ai.mit.edu\n");
+ printk ("Mapping fb->info.regs!\n");
+ map_size = 0x7000;
+ map_offset = get_phys ((unsigned long) fb->info.cg14.regs);
+ break;
+
+ case CG3_MMAP_OFFSET:
+ map_size = size-page;
+ map_offset = get_phys ((unsigned long) fb->base);
+ break;
+
+ case MDI_PLANAR_X16_MAP:
+ map_size = ram_size/2;
+ map_offset = get_phys ((unsigned long) fb->base) | 0x2000000;
+ break;
+
+ case MDI_PLANAR_C16_MAP:
+ map_size = ram_size/2;
+ map_offset = get_phys ((unsigned long) fb->base) | 0x2800000;
+ break;
+
+ case MDI_CHUNKY_XBGR_MAP:
+ map_size = 0;
+ printk ("Woo Woo: XBGR not there yet\n");
+ break;
+
+ case MDI_CHUNKY_BGR_MAP:
+ map_size = ram_size;
+ map_offset = get_phys ((unsigned long) fb->base) | 0x1000000;
+ break;
+
+ case MDI_PLANAR_X32_MAP:
+ map_size = ram_size/4;
+ map_offset = get_phys ((unsigned long) fb->base) | 0x3000000;
+ break;
+ case MDI_PLANAR_B32_MAP:
+ map_size = ram_size/4;
+ map_offset = get_phys ((unsigned long) fb->base) | 0x3400000;
+ break;
+ case MDI_PLANAR_G32_MAP:
+ map_size = ram_size/4;
+ map_offset = get_phys ((unsigned long) fb->base) | 0x3800000;
+ break;
+ case MDI_PLANAR_R32_MAP:
+ map_size = ram_size/4;
+ map_offset = get_phys ((unsigned long) fb->base) | 0x3c00000;
+ break;
+
+ case MDI_CURSOR_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long) fb->info.cg14.cursor_regs);
+ break;
+
+ case CG14_REGS:
+ printk ("Wee! They are mapping the register, report this to miguel@gnu.ai.mit.edu\n");
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long) fb->info.cg14.regs);
+ break;
+
+ case CG14_XLUT:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long) fb->info.cg14.regs+0x3000);
+ break;
+
+ case CG14_CLUT1:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long) fb->info.cg14.regs+0x4000);
+ break;
+
+ case CG14_CLUT2:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long) fb->info.cg14.regs+0x5000);
+ break;
+
+ default:
+ map_size = 0;
+ break;
+ }
+ if (!map_size){
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+ r = io_remap_page_range (vma->vm_start+page,
+ map_offset,
+ map_size, vma->vm_page_prot,
+ fb->space);
+ if (r) return -EAGAIN;
+ page += map_size;
+ }
+ vma->vm_inode = inode;
+ inode->i_count++;
+ return 0;
+}
+
+static void
+cg14_cmap (fbinfo_t *fb, int index, int count)
+{
+ struct cg14_clut *clut = fb->info.cg14.clut;
+ int i;
+
+ for (i = index; count--; i++){
+ clut->c_clut [i] =
+ (fb->color_map CM(i,2) << 16) |
+ (fb->color_map CM(i,1) << 8) |
+ (fb->color_map CM(i,0));
+ }
+}
+
+static void
+cg14_setcursormap (fbinfo_t *fb, unsigned char *red,
+ unsigned char *green,
+ unsigned char *blue)
+{
+ struct cg14_cursor *cur = fb->info.cg14.cursor_regs;
+
+ cur->color0 = ((red[0]) | (green[0] << 8) | (blue[0] << 16));
+ cur->color1 = ((red[1]) | (green[1] << 8) | (blue[1] << 16));
+}
+
+/* Load cursor information */
+static void
+cg14_setcursor (fbinfo_t *fb)
+{
+ struct cg_cursor *c = &fb->cursor;
+ struct cg14_cursor *cur = fb->info.cg14.cursor_regs;
+
+ if (c->enable)
+ cur->ccr |= CG14_CCR_ENABLE;
+ cur->cursx = ((c->cpos.fbx - c->chot.fbx) & 0xfff);
+ cur->cursy = ((c->cpos.fby - c->chot.fby) & 0xfff);
+}
+
+/* Set cursor shape */
+static void
+cg14_setcurshape (fbinfo_t *fb)
+{
+ struct cg14_cursor *cur = fb->info.cg14.cursor_regs;
+ int i;
+
+ for (i = 0; i < 32; i++){
+ cur->cpl0 [i] = fb->cursor.bits[0][i];
+ cur->cpl1 [i] = fb->cursor.bits[1][i];
+ }
+}
+
+/* These ones are for putting the video card on 16/32 bpp */
+static int
+cg14_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
+{
+ switch (cmd){
+ case MDI_RESET: {
+ volatile unsigned char *control = &(fb->info.cg14.regs->mcr);
+ *control = (*control & ~CG14_MCR_PIXMODE_MASK);
+ }
+ break;
+
+ case MDI_GET_CFGINFO: {
+ int error;
+ struct mdi_cfginfo *mdii;
+
+ error = verify_area (VERIFY_WRITE, (void *) arg,
+ sizeof (struct mdi_cfginfo));
+ if (error)
+ return error;
+
+ mdii = (struct mdi_cfginfo *) arg;
+#if 0
+ __put_user_ret(2, &mdii->mdi_ncluts, -EFAULT);
+ switch (fb->info.cg14.regs->rev & CG14_REV_IMPL_MASK){
+ case 0:
+ case 2:
+ break;
+
+ case 1:
+ case 3:
+ __put_user_ret(3, &mdii->mdi_ncluts, -EFAULT);
+ break;
+ default:
+ printk ("Unknown implementation number\n");
+ }
+#endif
+ __put_user_ret(FBTYPE_MDICOLOR, &mdii->mdi_type, -EFAULT);
+ __put_user_ret(fb->type.fb_height, &mdii->mdi_height, -EFAULT);
+ __put_user_ret(fb->type.fb_width, &mdii->mdi_width, -EFAULT);
+ __put_user_ret(fb->info.cg14.video_mode, &mdii->mdi_mode, -EFAULT);
+ __put_user_ret(72, &mdii->mdi_pixfreq, -EFAULT); /* FIXME */
+ __put_user_ret(fb->info.cg14.ramsize, &mdii->mdi_size, -EFAULT);
+ }
+ break;
+
+ case MDI_SET_PIXELMODE: {
+ int newmode;
+ volatile u8 *control;
+
+ get_user_ret(newmode, (int *)arg, -EFAULT);
+ control = &(fb->info.cg14.regs->mcr);
+ switch (newmode){
+ case MDI_32_PIX:
+ *control = (*control & ~CG14_MCR_PIXMODE_MASK) |
+ (CG14_MCR_PIXMODE_32 << CG14_MCR_PIXMODE_SHIFT);
+ break;
+ case MDI_16_PIX:
+ *control = (*control & ~CG14_MCR_PIXMODE_MASK) | 0x20;
+ break;
+ case MDI_8_PIX:
+ *control = (*control & ~CG14_MCR_PIXMODE_MASK);
+ break;
+
+ default:
+ return -ENOSYS;
+ }
+ fb->info.cg14.video_mode = newmode;
+ }
+ break;
+
+ } /* switch */
+ return 0;
+}
+
+static void
+cg14_switch_from_graph (void)
+{
+ fbinfo_t *fb = &(fbinfo [0]);
+ struct cg14_info *cg14info = (struct cg14_info *) &fb->info.cg14;
+
+ /* Set the 8-bpp mode */
+ if (fb->open && fb->mmaped){
+ volatile char *mcr = (char *)(&cg14info->regs->mcr);
+
+ fb->info.cg14.video_mode = 8;
+ *mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK));
+ }
+}
+
+void
+cg14_reset (fbinfo_t *fb)
+{
+ volatile char *mcr = &(fb->info.cg14.regs->mcr);
+
+ *mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK));
+}
+
+__initfunc(void cg14_setup (fbinfo_t *fb, int slot, int con_node, u32 cg14, int cg14_io))
+{
+ struct cg14_info *cg14info;
+ uint bases [2];
+ unsigned long cg14regs = 0;
+ struct cg14_regs *regs = 0;
+
+ if (!cg14) {
+ prom_getproperty (con_node, "address", (char *) &bases[0], 8);
+ cg14 = bases[1];
+ cg14regs = bases[0];
+ fb->base = cg14;
+ fb->info.cg14.regs = (struct cg14_regs *) cg14regs;
+ regs = (struct cg14_regs *) cg14regs;
+ }
+
+ if (!cg14regs){
+ printk ("The PROM does not have mapped the frame buffer or the registers\n"
+ "Mr. Penguin can't use that");
+ prom_halt ();
+ }
+
+ fb->type.fb_cmsize = 256;
+ fb->mmap = cg14_mmap;
+ fb->loadcmap = cg14_cmap;
+ fb->setcursor = cg14_setcursor;
+ fb->setcursormap = cg14_setcursormap;
+ fb->setcurshape = cg14_setcurshape;
+ fb->ioctl = cg14_ioctl;
+ fb->switch_from_graph = cg14_switch_from_graph;
+ fb->postsetup = sun_cg_postsetup;
+ fb->reset = cg14_reset;
+ fb->blank = 0;
+ fb->unblank = 0;
+ fb->info.cg14.video_mode = 8;
+ fb->emulations [1] = FBTYPE_SUN3COLOR;
+ fb->type.fb_depth = 24;
+ cg14info = (struct cg14_info *) &fb->info.cg14;
+ cg14info->clut = (void *) (cg14regs + CG14_CLUT1);
+ cg14info->cursor_regs = (void *) (cg14regs + CG14_CURSORREGS);
+
+ /* If the bit is turned on, the card has 8 mb of ram, otherwise just 4 */
+ cg14info->ramsize = (regs->vca & CG14_VCA_8MB_MASK ? 8 : 4) * 1024 * 1024;
+ printk ("cgfourteen%d at 0x%8.8x with %d megs of RAM rev=%d, impl=%d\n",
+ slot, cg14, cg14info->ramsize/(1024*1024), regs->rev >> 4, regs->rev & 0xf);
+}
diff --git a/drivers/sbus/char/cgsix.c b/drivers/sbus/char/cgsix.c
new file mode 100644
index 000000000..5f91c1308
--- /dev/null
+++ b/drivers/sbus/char/cgsix.c
@@ -0,0 +1,642 @@
+/* $Id: cgsix.c,v 1.27 1997/04/14 17:04:55 jj Exp $
+ * cgsix.c: cgsix frame buffer driver
+ *
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ */
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/* Offset of interesting structures in the OBIO space */
+/*
+ * Brooktree is the video dac and is funny to program on the cg6.
+ * (it's even funnier on the cg3)
+ * The FBC could be the the frame buffer control
+ * The FHC could is the frame buffer hardware control.
+ */
+#define CG6_ROM_OFFSET 0x0
+#define CG6_BROOKTREE_OFFSET 0x200000
+#define CG6_DHC_OFFSET 0x240000
+#define CG6_ALT_OFFSET 0x280000
+#define CG6_FHC_OFFSET 0x300000
+#define CG6_THC_OFFSET 0x301000
+#define CG6_FBC_OFFSET 0x700000
+#define CG6_TEC_OFFSET 0x701000
+#define CG6_RAM_OFFSET 0x800000
+
+/* FHC definitions */
+#define CG6_FHC_FBID_SHIFT 24
+#define CG6_FHC_FBID_MASK 255
+#define CG6_FHC_REV_SHIFT 20
+#define CG6_FHC_REV_MASK 15
+#define CG6_FHC_FROP_DISABLE (1 << 19)
+#define CG6_FHC_ROW_DISABLE (1 << 18)
+#define CG6_FHC_SRC_DISABLE (1 << 17)
+#define CG6_FHC_DST_DISABLE (1 << 16)
+#define CG6_FHC_RESET (1 << 15)
+#define CG6_FHC_LITTLE_ENDIAN (1 << 13)
+#define CG6_FHC_RES_MASK (3 << 11)
+#define CG6_FHC_1024 (0 << 11)
+#define CG6_FHC_1152 (1 << 11)
+#define CG6_FHC_1280 (2 << 11)
+#define CG6_FHC_1600 (3 << 11)
+#define CG6_FHC_CPU_MASK (3 << 9)
+#define CG6_FHC_CPU_SPARC (0 << 9)
+#define CG6_FHC_CPU_68020 (1 << 9)
+#define CG6_FHC_CPU_386 (2 << 9)
+#define CG6_FHC_TEST (1 << 8)
+#define CG6_FHC_TEST_X_SHIFT 4
+#define CG6_FHC_TEST_X_MASK 15
+#define CG6_FHC_TEST_Y_SHIFT 0
+#define CG6_FHC_TEST_Y_MASK 15
+
+/* FBC mode definitions */
+#define CG6_FBC_BLIT_IGNORE 0x00000000
+#define CG6_FBC_BLIT_NOSRC 0x00100000
+#define CG6_FBC_BLIT_SRC 0x00200000
+#define CG6_FBC_BLIT_ILLEGAL 0x00300000
+#define CG6_FBC_BLIT_MASK 0x00300000
+
+#define CG6_FBC_VBLANK 0x00080000
+
+#define CG6_FBC_MODE_IGNORE 0x00000000
+#define CG6_FBC_MODE_COLOR8 0x00020000
+#define CG6_FBC_MODE_COLOR1 0x00040000
+#define CG6_FBC_MODE_HRMONO 0x00060000
+#define CG6_FBC_MODE_MASK 0x00060000
+
+#define CG6_FBC_DRAW_IGNORE 0x00000000
+#define CG6_FBC_DRAW_RENDER 0x00008000
+#define CG6_FBC_DRAW_PICK 0x00010000
+#define CG6_FBC_DRAW_ILLEGAL 0x00018000
+#define CG6_FBC_DRAW_MASK 0x00018000
+
+#define CG6_FBC_BWRITE0_IGNORE 0x00000000
+#define CG6_FBC_BWRITE0_ENABLE 0x00002000
+#define CG6_FBC_BWRITE0_DISABLE 0x00004000
+#define CG6_FBC_BWRITE0_ILLEGAL 0x00006000
+#define CG6_FBC_BWRITE0_MASK 0x00006000
+
+#define CG6_FBC_BWRITE1_IGNORE 0x00000000
+#define CG6_FBC_BWRITE1_ENABLE 0x00000800
+#define CG6_FBC_BWRITE1_DISABLE 0x00001000
+#define CG6_FBC_BWRITE1_ILLEGAL 0x00001800
+#define CG6_FBC_BWRITE1_MASK 0x00001800
+
+#define CG6_FBC_BREAD_IGNORE 0x00000000
+#define CG6_FBC_BREAD_0 0x00000200
+#define CG6_FBC_BREAD_1 0x00000400
+#define CG6_FBC_BREAD_ILLEGAL 0x00000600
+#define CG6_FBC_BREAD_MASK 0x00000600
+
+#define CG6_FBC_BDISP_IGNORE 0x00000000
+#define CG6_FBC_BDISP_0 0x00000080
+#define CG6_FBC_BDISP_1 0x00000100
+#define CG6_FBC_BDISP_ILLEGAL 0x00000180
+#define CG6_FBC_BDISP_MASK 0x00000180
+
+#define CG6_FBC_INDEX_MOD 0x00000040
+#define CG6_FBC_INDEX_MASK 0x00000030
+
+/* THC definitions */
+#define CG6_THC_MISC_REV_SHIFT 16
+#define CG6_THC_MISC_REV_MASK 15
+#define CG6_THC_MISC_RESET (1 << 12)
+#define CG6_THC_MISC_VIDEO (1 << 10)
+#define CG6_THC_MISC_SYNC (1 << 9)
+#define CG6_THC_MISC_VSYNC (1 << 8)
+#define CG6_THC_MISC_SYNC_ENAB (1 << 7)
+#define CG6_THC_MISC_CURS_RES (1 << 6)
+#define CG6_THC_MISC_INT_ENAB (1 << 5)
+#define CG6_THC_MISC_INT (1 << 4)
+#define CG6_THC_MISC_INIT 0x9f
+
+/* The contents are unknown */
+struct cg6_tec {
+ volatile int tec_matrix;
+ volatile int tec_clip;
+ volatile int tec_vdc;
+};
+
+struct cg6_thc {
+ uint thc_pad0[512];
+ volatile uint thc_hs; /* hsync timing */
+ volatile uint thc_hsdvs;
+ volatile uint thc_hd;
+ volatile uint thc_vs; /* vsync timing */
+ volatile uint thc_vd;
+ volatile uint thc_refresh;
+ volatile uint thc_misc;
+ uint thc_pad1[56];
+ volatile uint thc_cursxy; /* cursor x,y position (16 bits each) */
+ volatile uint thc_cursmask[32]; /* cursor mask bits */
+ volatile uint thc_cursbits[32]; /* what to show where mask enabled */
+};
+
+struct cg6_fbc {
+ u32 xxx0[1];
+ volatile u32 mode;
+ volatile u32 clip;
+ u32 xxx1[1];
+ volatile u32 s;
+ volatile u32 draw;
+ volatile u32 blit;
+ volatile u32 font;
+ u32 xxx2[24];
+ volatile u32 x0, y0, z0, color0;
+ volatile u32 x1, y1, z1, color1;
+ volatile u32 x2, y2, z2, color2;
+ volatile u32 x3, y3, z3, color3;
+ volatile u32 offx, offy;
+ u32 xxx3[2];
+ volatile u32 incx, incy;
+ u32 xxx4[2];
+ volatile u32 clipminx, clipminy;
+ u32 xxx5[2];
+ volatile u32 clipmaxx, clipmaxy;
+ u32 xxx6[2];
+ volatile u32 fg;
+ volatile u32 bg;
+ volatile u32 alu;
+ volatile u32 pm;
+ volatile u32 pixelm;
+ u32 xxx7[2];
+ volatile u32 patalign;
+ volatile u32 pattern[8];
+ u32 xxx8[432];
+ volatile u32 apointx, apointy, apointz;
+ u32 xxx9[1];
+ volatile u32 rpointx, rpointy, rpointz;
+ u32 xxx10[5];
+ volatile u32 pointr, pointg, pointb, pointa;
+ volatile u32 alinex, aliney, alinez;
+ u32 xxx11[1];
+ volatile u32 rlinex, rliney, rlinez;
+ u32 xxx12[5];
+ volatile u32 liner, lineg, lineb, linea;
+ volatile u32 atrix, atriy, atriz;
+ u32 xxx13[1];
+ volatile u32 rtrix, rtriy, rtriz;
+ u32 xxx14[5];
+ volatile u32 trir, trig, trib, tria;
+ volatile u32 aquadx, aquady, aquadz;
+ u32 xxx15[1];
+ volatile u32 rquadx, rquady, rquadz;
+ u32 xxx16[5];
+ volatile u32 quadr, quadg, quadb, quada;
+ volatile u32 arectx, arecty, arectz;
+ u32 xxx17[1];
+ volatile u32 rrectx, rrecty, rrectz;
+ u32 xxx18[5];
+ volatile u32 rectr, rectg, rectb, recta;
+};
+
+static void
+cg6_restore_palette (fbinfo_t *fbinfo)
+{
+ volatile struct bt_regs *bt;
+
+ bt = fbinfo->info.cg6.bt;
+ bt->addr = 0;
+ bt->color_map = 0xffffffff;
+ bt->color_map = 0xffffffff;
+ bt->color_map = 0xffffffff;
+}
+
+static void cg6_blitc(unsigned short, int, int);
+static void cg6_setw(int, int, unsigned short, int);
+static void cg6_cpyw(int, int, unsigned short *, int);
+
+#if 0
+static void cg6_fill(int, int, int *);
+#endif
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+ long base, fbinfo_t *fb)
+{
+ uint size, page, r, map_size;
+ uint map_offset = 0;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages */
+ vma->vm_flags |= FB_MMAP_VM_FLAGS;
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ){
+ switch (vma->vm_offset+page){
+ case CG6_TEC:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.cg6.tec);
+ break;
+ case CG6_FBC:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.cg6.fbc);
+ break;
+ case CG6_FHC:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.cg6.fhc);
+ break;
+ case CG6_THC:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.cg6.thc);
+ break;
+ case CG6_BTREGS:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.cg6.bt);
+ break;
+ case CG6_DHC:
+ map_size = PAGE_SIZE * 40;
+ map_offset = get_phys ((unsigned long)fb->info.cg6.dhc);
+ break;
+ case CG6_ROM:
+ map_size = PAGE_SIZE * 16;
+ map_offset = get_phys ((unsigned long)fb->info.cg6.rom);
+ break;
+ case CG6_RAM:
+ map_size = size-page;
+ map_offset = get_phys ((unsigned long) fb->base);
+ if (map_size < fb->type.fb_size)
+ map_size = fb->type.fb_size;
+ break;
+ default:
+ map_size = 0;
+ break;
+ }
+ if (!map_size){
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+ r = io_remap_page_range (vma->vm_start+page,
+ map_offset,
+ map_size, vma->vm_page_prot,
+ fb->space);
+ if (r) return -EAGAIN;
+ page += map_size;
+ }
+ vma->vm_inode = inode;
+ inode->i_count++;
+ return 0;
+}
+
+static void
+cg6_loadcmap (fbinfo_t *fb, int index, int count)
+{
+ struct bt_regs *bt = fb->info.cg6.bt;
+ int i;
+
+ bt->addr = index << 24;
+ for (i = index; count--; i++){
+ bt->color_map = fb->color_map CM(i,0) << 24;
+ bt->color_map = fb->color_map CM(i,1) << 24;
+ bt->color_map = fb->color_map CM(i,2) << 24;
+ }
+}
+
+static void
+cg6_setcursormap (fbinfo_t *fb, unsigned char *red,
+ unsigned char *green,
+ unsigned char *blue)
+{
+ struct bt_regs *bt = fb->info.cg6.bt;
+
+ bt->addr = 1 << 24;
+ bt->cursor = red[0] << 24;
+ bt->cursor = green[0] << 24;
+ bt->cursor = blue[0] << 24;
+ bt->addr = 3 << 24;
+ bt->cursor = red[1] << 24;
+ bt->cursor = green[1] << 24;
+ bt->cursor = blue[1] << 24;
+}
+
+/* Load cursor information */
+static void
+cg6_setcursor (fbinfo_t *fb)
+{
+ uint v;
+ struct cg_cursor *c = &fb->cursor;
+
+ if (c->enable){
+ v = ((c->cpos.fbx - c->chot.fbx) << 16)
+ |((c->cpos.fby - c->chot.fby) & 0xffff);
+ } else {
+ /* Magic constant to turn off the cursor */
+ v = ((65536-32) << 16) | (65536-32);
+ }
+ fb->info.cg6.thc->thc_cursxy = v;
+}
+
+/* Set cursor shape */
+static void
+cg6_setcurshape (fbinfo_t *fb)
+{
+ struct cg6_thc *thc = fb->info.cg6.thc;
+ int i;
+
+ for (i = 0; i < 32; i++){
+ thc->thc_cursmask [i] = fb->cursor.bits[0][i];
+ thc->thc_cursbits [i] = fb->cursor.bits[1][i];
+ }
+}
+
+static void
+cg6_blank (fbinfo_t *fb)
+{
+ fb->info.cg6.thc->thc_misc &= ~CG6_THC_MISC_VIDEO;
+}
+
+static void
+cg6_unblank (fbinfo_t *fb)
+{
+ fb->info.cg6.thc->thc_misc |= CG6_THC_MISC_VIDEO;
+}
+
+void
+cg6_reset (fbinfo_t *fb)
+{
+ struct cg6_info *cg6 = &(fb->info.cg6);
+ unsigned int rev, conf;
+
+ if (fb->setcursor)
+ sun_hw_hide_cursor ();
+ /* Turn off stuff in the Transform Engine. */
+ cg6->tec->tec_matrix = 0;
+ cg6->tec->tec_clip = 0;
+ cg6->tec->tec_vdc = 0;
+
+ /* Take care of bugs in old revisions. */
+ rev = (*(cg6->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
+ if (rev < 5) {
+ conf = (*(cg6->fhc) & CG6_FHC_RES_MASK) |
+ CG6_FHC_CPU_68020 | CG6_FHC_TEST |
+ (11 << CG6_FHC_TEST_X_SHIFT) |
+ (11 << CG6_FHC_TEST_Y_SHIFT);
+ if (rev < 2)
+ conf |= CG6_FHC_DST_DISABLE;
+ *(cg6->fhc) = conf;
+ }
+
+ /* Set things in the FBC. */
+ cg6->fbc->mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
+ CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
+ CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
+ CG6_FBC_BDISP_MASK);
+ cg6->fbc->mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
+ CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
+ CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
+ CG6_FBC_BDISP_0);
+ cg6->fbc->clip = 0;
+ cg6->fbc->offx = 0;
+ cg6->fbc->offy = 0;
+ cg6->fbc->clipminx = 0;
+ cg6->fbc->clipminy = 0;
+ cg6->fbc->clipmaxx = fb->type.fb_width - 1;
+ cg6->fbc->clipmaxy = fb->type.fb_height - 1;
+ /* Enable cursor in Brooktree DAC. */
+ cg6->bt->addr = 0x06 << 24;
+ cg6->bt->control |= 0x03 << 24;
+}
+
+__initfunc(void cg6_setup (fbinfo_t *fb, int slot, u32 cg6, int cg6_io))
+{
+ struct cg6_info *cg6info;
+ unsigned int rev, cpu, conf;
+
+ printk ("cgsix%d at 0x%8.8x ", slot, cg6);
+
+ /* Fill in parameters we left out */
+ fb->type.fb_cmsize = 256;
+ fb->mmap = cg6_mmap;
+ fb->loadcmap = cg6_loadcmap;
+ fb->reset = cg6_reset;
+ fb->blank = cg6_blank;
+ fb->unblank = cg6_unblank;
+ fb->setcursor = cg6_setcursor;
+ fb->setcursormap = cg6_setcursormap;
+ fb->setcurshape = cg6_setcurshape;
+ fb->postsetup = sun_cg_postsetup;
+ fb->blitc = cg6_blitc;
+ fb->setw = cg6_setw;
+ fb->cpyw = cg6_cpyw;
+
+ cg6info = (struct cg6_info *) &fb->info.cg6;
+
+ /* Map the hardware registers */
+ cg6info->bt = sparc_alloc_io (cg6+CG6_BROOKTREE_OFFSET, 0,
+ sizeof (struct bt_regs), "cgsix_dac", cg6_io, 0);
+ cg6info->fhc = sparc_alloc_io (cg6+CG6_FHC_OFFSET, 0,
+ sizeof (int), "cgsix_fhc", cg6_io, 0);
+ cg6info->thc = sparc_alloc_io (cg6+CG6_THC_OFFSET, 0,
+ sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
+ cg6info->tec = sparc_alloc_io (cg6+CG6_TEC_OFFSET, 0,
+ sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
+ cg6info->dhc = sparc_alloc_io (cg6+CG6_DHC_OFFSET, 0,
+ 0x40000, "cgsix_dhc", cg6_io, 0);
+ cg6info->fbc = sparc_alloc_io (cg6+CG6_FBC_OFFSET, 0,
+ 0x1000, "cgsix_fbc", cg6_io, 0);
+ cg6info->rom = sparc_alloc_io (cg6+CG6_ROM_OFFSET, 0,
+ 0x10000, "cgsix_rom", cg6_io, 0);
+ if (!fb->base) {
+ fb->base = (unsigned long)
+ sparc_alloc_io (cg6+CG6_RAM_OFFSET, 0,
+ fb->type.fb_size, "cgsix_ram", cg6_io, 0);
+ }
+ if (slot == sun_prom_console_id)
+ fb_restore_palette = cg6_restore_palette;
+
+ /* Initialize Brooktree DAC */
+ cg6info->bt->addr = 0x04 << 24; /* color planes */
+ cg6info->bt->control = 0xff << 24;
+ cg6info->bt->addr = 0x05 << 24;
+ cg6info->bt->control = 0x00 << 24;
+ cg6info->bt->addr = 0x06 << 24; /* overlay plane */
+ cg6info->bt->control = 0x73 << 24;
+ cg6info->bt->addr = 0x07 << 24;
+ cg6info->bt->control = 0x00 << 24;
+
+ printk("TEC Rev %x ",
+ (cg6info->thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) &
+ CG6_THC_MISC_REV_MASK);
+
+ /* Get FHC Revision */
+ conf = *(cg6info->fhc);
+
+ cpu = conf & CG6_FHC_CPU_MASK;
+ printk("CPU ");
+ if (cpu == CG6_FHC_CPU_SPARC)
+ printk("sparc ");
+ else if (cpu == CG6_FHC_CPU_68020)
+ printk("68020 ");
+ else
+ printk("386 ");
+
+ rev = conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK;
+ printk("Rev %x\n", rev);
+
+ if (slot && sun_prom_console_id == slot)
+ return;
+
+ /* Reset the cg6 */
+ cg6_reset(fb);
+
+ if (!slot) {
+ /* Enable Video */
+ cg6_unblank(fb);
+ } else {
+ cg6_blank(fb);
+ }
+}
+
+extern unsigned char vga_font[];
+
+#define GX_BLITC_START(attr) \
+ { \
+ register struct cg6_fbc *gx = fbinfo[0].info.cg6.fbc; \
+ register uint i; \
+ do { \
+ i = gx->s; \
+ } while (i & 0x10000000); \
+ gx->fg = attr & 0xf; \
+ gx->bg = (attr>>4); \
+ gx->mode = 0x140000; \
+ gx->alu = 0xe880fc30; \
+ gx->pixelm = ~(0); \
+ gx->s = 0; \
+ gx->clip = 0; \
+ gx->pm = 0xff;
+#define GX_BLITC_BODY4(count,x,y,start,action) \
+ while (count >= 4) { \
+ count -= 4; \
+ gx->incx = 0; \
+ gx->incy = 1; \
+ gx->x0 = x; \
+ gx->x1 = (x += 32) - 1; \
+ gx->y0 = y; \
+ start; \
+ for (i = 0; i < CHAR_HEIGHT; i++) { \
+ action; \
+ } \
+ }
+#define GX_BLITC_BODY1(x,y,action) \
+ gx->incx = 0; \
+ gx->incy = 1; \
+ gx->x0 = x; \
+ gx->x1 = (x += 8) - 1; \
+ gx->y0 = y; \
+ for (i = 0; i < CHAR_HEIGHT; i++) { \
+ action; \
+ }
+#define GX_BLITC_END \
+ }
+
+static void cg6_blitc(unsigned short charattr, int xoff, int yoff)
+{
+ unsigned char attrib = CHARATTR_TO_SUNCOLOR(charattr);
+ unsigned char *p = &vga_font[((unsigned char)charattr) << 4];
+ GX_BLITC_START(attrib)
+ GX_BLITC_BODY1(xoff, yoff, gx->font=((*p++) << 24))
+ GX_BLITC_END
+}
+
+static void cg6_setw(int xoff, int yoff, unsigned short c, int count)
+{
+ unsigned char attrib = CHARATTR_TO_SUNCOLOR(c);
+ unsigned char *p = &vga_font[((unsigned char)c) << 4];
+ register unsigned char *q;
+ register uint l;
+ GX_BLITC_START(attrib)
+ if (count >= 4) {
+ GX_BLITC_BODY4(count, xoff, yoff, q = p,
+ l = *q++;
+ l |= l << 8;
+ l |= l << 16;
+ gx->font=l)
+ }
+ while (count) {
+ count--;
+ q = p;
+ GX_BLITC_BODY1(xoff, yoff, gx->font=((*q++) << 24));
+ }
+ GX_BLITC_END
+}
+
+static void cg6_cpyw(int xoff, int yoff, unsigned short *p, int count)
+{
+ unsigned char attrib = CHARATTR_TO_SUNCOLOR(*p);
+ unsigned char *p1, *p2, *p3, *p4;
+ GX_BLITC_START(attrib)
+ if (count >= 4) {
+ GX_BLITC_BODY4(count, xoff, yoff,
+ p1 = &vga_font[((unsigned char)*p++) << 4];
+ p2 = &vga_font[((unsigned char)*p++) << 4];
+ p3 = &vga_font[((unsigned char)*p++) << 4];
+ p4 = &vga_font[((unsigned char)*p++) << 4],
+ gx->font=((uint)*p4++) | ((((uint)*p3++) | ((((uint)*p2++) | (((uint)*p1++) << 8)) << 8)) << 8))
+ }
+ while (count) {
+ count--;
+ p1 = &vga_font[((unsigned char)*p++) << 4];
+ GX_BLITC_BODY1(xoff, yoff, gx->font=((*p1++) << 24));
+ }
+ GX_BLITC_END
+}
+
+#define GX_FILL_START(attr) \
+ { \
+ register struct cg6_fbc *gx = fbinfo[0].info.cg6.fbc; \
+ register uint i; \
+ do { \
+ i = gx->s; \
+ } while (i & 0x10000000); \
+ gx->fg = attr & 0xf; \
+ gx->bg = 0; \
+ gx->pixelm = ~(0); \
+ gx->s = 0; \
+ gx->alu = 0xea80ff00; \
+ gx->pm = ~(0); \
+ gx->clip = 0;
+#define GX_FILL_END \
+ }
+
+#if 0
+static void cg6_fill(int attrib, int count, int *boxes)
+{
+ register int r;
+
+ attrib = 5;
+ GX_FILL_START(attrib)
+ while (count-- > 0) {
+ gx->arecty = boxes[1];
+ gx->arectx = boxes[0];
+ gx->arecty = boxes[3];
+ gx->arecty = boxes[2];
+ boxes += 4;
+ do {
+ r = gx->draw;
+ } while (r < 0 && (r & 0x20000000) );
+ }
+ GX_FILL_END
+}
+#endif
diff --git a/drivers/sbus/char/cgthree.c b/drivers/sbus/char/cgthree.c
new file mode 100644
index 000000000..ac1265c61
--- /dev/null
+++ b/drivers/sbus/char/cgthree.c
@@ -0,0 +1,265 @@
+/* $Id: cgthree.c,v 1.18 1997/04/16 17:51:09 jj Exp $
+ * cgtree.c: cg3 frame buffer driver
+ *
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Support for cgRDI added, Nov/96, jj.
+ */
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+
+/* Control Register Constants */
+#define CG3_CR_ENABLE_INTS 0x80
+#define CG3_CR_ENABLE_VIDEO 0x40
+#define CG3_CR_ENABLE_TIMING 0x20
+#define CG3_CR_ENABLE_CURCMP 0x10
+#define CG3_CR_XTAL_MASK 0x0c
+#define CG3_CR_DIVISOR_MASK 0x03
+
+/* Status Register Constants */
+#define CG3_SR_PENDING_INT 0x80
+#define CG3_SR_RES_MASK 0x70
+#define CG3_SR_1152_900_76_A 0x40
+#define CG3_SR_1152_900_76_B 0x60
+#define CG3_SR_ID_MASK 0x0f
+#define CG3_SR_ID_COLOR 0x01
+#define CG3_SR_ID_MONO 0x02
+#define CG3_SR_ID_MONO_ECL 0x03
+
+
+enum cg3_type {
+ CG3_AT_66HZ = 0,
+ CG3_AT_76HZ,
+ CG3_RDI
+};
+
+
+struct cg3_regs {
+ struct bt_regs cmap;
+ volatile u8 control;
+ volatile u8 status;
+ volatile u8 cursor_start;
+ volatile u8 cursor_end;
+ volatile u8 h_blank_start;
+ volatile u8 h_blank_end;
+ volatile u8 h_sync_start;
+ volatile u8 h_sync_end;
+ volatile u8 comp_sync_end;
+ volatile u8 v_blank_start_high;
+ volatile u8 v_blank_start_low;
+ volatile u8 v_blank_end;
+ volatile u8 v_sync_start;
+ volatile u8 v_sync_end;
+ volatile u8 xfer_holdoff_start;
+ volatile u8 xfer_holdoff_end;
+};
+
+/* The cg3 palette is loaded with 4 color values at each time */
+/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
+static void
+cg3_loadcmap (fbinfo_t *fb, int index, int count)
+{
+ struct bt_regs *bt = &fb->info.cg3.regs->cmap;
+ int *i, steps;
+
+ i = (((int *)fb->color_map) + D4M3(index));
+ steps = D4M3(index+count-1) - D4M3(index)+3;
+
+ *(volatile u8 *)&bt->addr = (u8)D4M4(index);
+ while (steps--)
+ bt->color_map = *i++;
+}
+
+/* The cg3 is presumed to emulate a cg4, I guess older programs will want that
+ * addresses above 0x4000000 are for cg3, below that it's cg4 emulation.
+ */
+static int
+cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+ long base, fbinfo_t *fb)
+{
+ uint size, page, r, map_size;
+ uint map_offset = 0;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages */
+ vma->vm_flags |= FB_MMAP_VM_FLAGS;
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ){
+ switch (vma->vm_offset+page){
+ case CG3_MMAP_OFFSET:
+ map_size = size-page;
+ map_offset = get_phys ((unsigned long) fb->base);
+ if (map_size > fb->type.fb_size)
+ map_size = fb->type.fb_size;
+ break;
+ default:
+ map_size = 0;
+ break;
+ }
+ if (!map_size){
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+ r = io_remap_page_range (vma->vm_start+page,
+ map_offset,
+ map_size, vma->vm_page_prot,
+ fb->space);
+ if (r) return -EAGAIN;
+ page += map_size;
+ }
+ vma->vm_inode = inode;
+ inode->i_count++;
+ return 0;
+}
+
+static void
+cg3_blank (fbinfo_t *fb)
+{
+ fb->info.cg3.regs->control &= ~CG3_CR_ENABLE_VIDEO;
+}
+
+static void
+cg3_unblank (fbinfo_t *fb)
+{
+ fb->info.cg3.regs->control |= CG3_CR_ENABLE_VIDEO;
+}
+
+
+static u8 cg3regvals_66hz[] __initdata = { /* 1152 x 900, 66 Hz */
+ 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
+ 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
+ 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x20, 0
+};
+
+static u8 cg3regvals_76hz[] __initdata = { /* 1152 x 900, 76 Hz */
+ 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
+ 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
+ 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x24, 0
+};
+
+static u8 cg3regvals_rdi[] __initdata = { /* 640 x 480, cgRDI */
+ 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
+ 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
+ 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x22, 0
+};
+
+static u8 *cg3_regvals[] __initdata = {
+ cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
+};
+
+static u_char cg3_dacvals[] __initdata = {
+ 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
+};
+
+
+__initfunc(void cg3_setup (fbinfo_t *fb, int slot, u32 cg3, int cg3_io,
+ struct linux_sbus_device *sbdp))
+{
+ struct cg3_info *cg3info = (struct cg3_info *) &fb->info.cg3;
+
+ if (strstr (sbdp->prom_name, "cgRDI")) {
+ char buffer[40];
+ char *p;
+ int w, h;
+
+ prom_getstring (sbdp->prom_node, "params",
+ buffer, sizeof(buffer));
+ if (*buffer) {
+ w = simple_strtoul (buffer, &p, 10);
+ if (w && *p == 'x') {
+ h = simple_strtoul (p + 1, &p, 10);
+ if (h && *p == '-') {
+ fb->type.fb_width = w;
+ fb->type.fb_height = h;
+ }
+ }
+ }
+ printk ("cgRDI%d at 0x%8.8x\n", slot, cg3);
+ cg3info->cgrdi = 1;
+ } else {
+ printk ("cgthree%d at 0x%8.8x\n", slot, cg3);
+ cg3info->cgrdi = 0;
+ }
+
+ /* Fill in parameters we left out */
+ fb->type.fb_cmsize = 256;
+ fb->mmap = cg3_mmap;
+ fb->loadcmap = cg3_loadcmap;
+ fb->postsetup = sun_cg_postsetup;
+ fb->ioctl = 0; /* no special ioctls */
+ fb->reset = 0;
+ fb->blank = cg3_blank;
+ fb->unblank = cg3_unblank;
+
+ /* Map the card registers */
+ cg3info->regs = sparc_alloc_io (cg3+CG3_REGS, 0,
+ sizeof (struct cg3_regs),"cg3_regs", cg3_io, 0);
+
+ if (!prom_getbool(sbdp->prom_node, "width")) {
+ /* Ugh, broken PROM didn't initialize us.
+ * Let's deal with this ourselves.
+ */
+ u8 status, mon;
+ enum cg3_type type;
+ u8 *p;
+
+ if (cg3info->cgrdi) {
+ type = CG3_RDI;
+ } else {
+ status = cg3info->regs->status;
+ if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
+ mon = status & CG3_SR_RES_MASK;
+ if (mon == CG3_SR_1152_900_76_A ||
+ mon == CG3_SR_1152_900_76_B)
+ type = CG3_AT_76HZ;
+ else
+ type = CG3_AT_66HZ;
+ } else {
+ prom_printf("cgthree: can't handle SR %02x\n",
+ status);
+ prom_halt();
+ return; /* fool gcc. */
+ }
+ }
+
+ for (p = cg3_regvals[type]; *p; p += 2)
+ ((u8 *)cg3info->regs)[p[0]] = p[1];
+
+ for (p = cg3_dacvals; *p; p += 2) {
+ *(volatile u8 *)&cg3info->regs->cmap.addr = p[0];
+ *(volatile u8 *)&cg3info->regs->cmap.control = p[1];
+ }
+ }
+
+ if (!fb->base){
+ fb->base=(unsigned long) sparc_alloc_io (cg3+CG3_RAM, 0,
+ fb->type.fb_size, "cg3_ram", cg3_io, 0);
+ }
+}
+
diff --git a/drivers/sbus/char/creator.c b/drivers/sbus/char/creator.c
new file mode 100644
index 000000000..193a26190
--- /dev/null
+++ b/drivers/sbus/char/creator.c
@@ -0,0 +1,98 @@
+/*
+ * creator.c: Linux/Sun Ultra Creator console support.
+ *
+ * Copyright (C) 1997 MIguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ */
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+
+__initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io))
+{
+ uint bases [2];
+ unsigned long *p;
+
+ if (!creator) {
+ prom_getproperty (con_node, "address", (char *) &bases[0], 4);
+ prom_printf ("Bases: %x %x\n", bases [0], bases [1]);
+ p = (unsigned long *) creator = bases[0];
+ fb->base = creator;
+ fb->base = 0xff168000;
+ }
+
+ fb->type.fb_cmsize = 256;
+ fb->mmap = 0;
+ fb->loadcmap = 0;
+ fb->setcursor = 0;
+ fb->setcursormap = 0;
+ fb->setcurshape = 0;
+ fb->ioctl = 0;
+ fb->switch_from_graph = 0;
+ fb->postsetup = sun_cg_postsetup;
+ fb->reset = 0;
+ fb->blank = 0;
+ fb->unblank = 0;
+ fb->type.fb_depth = 8;
+}
+/*
+ * creator.c: Linux/Sun Ultra Creator console support.
+ *
+ * Copyright (C) 1997 MIguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ */
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+
+__initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io))
+{
+ uint bases [2];
+ unsigned long *p;
+
+ if (!creator) {
+ prom_getproperty (con_node, "address", (char *) &bases[0], 4);
+ prom_printf ("Bases: %x %x\n", bases [0], bases [1]);
+ p = (unsigned long *) creator = bases[0];
+ fb->base = creator;
+ fb->base = 0xff168000;
+ }
+
+ fb->type.fb_cmsize = 256;
+ fb->mmap = 0;
+ fb->loadcmap = 0;
+ fb->setcursor = 0;
+ fb->setcursormap = 0;
+ fb->setcurshape = 0;
+ fb->ioctl = 0;
+ fb->switch_from_graph = 0;
+ fb->postsetup = sun_cg_postsetup;
+ fb->reset = 0;
+ fb->blank = 0;
+ fb->unblank = 0;
+ fb->type.fb_depth = 8;
+}
diff --git a/drivers/sbus/char/fb.h b/drivers/sbus/char/fb.h
new file mode 100644
index 000000000..029eac81b
--- /dev/null
+++ b/drivers/sbus/char/fb.h
@@ -0,0 +1,210 @@
+/* $Id: fb.h,v 1.26 1997/04/17 02:29:33 miguel Exp $
+ * fb.h: contains the definitions of the structures that various sun
+ * frame buffer can use to do console driver stuff.
+ *
+ * (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ * (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * (C) 1996 David Miller (davem@rutgers.edu)
+ * (C) 1996 Peter Zaitcev (zaitcev@lab.ipmce.su)
+ * (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#ifndef __SPARC_FB_H_
+#define __SPARC_FB_H_
+
+#include <linux/init.h>
+
+#define FRAME_BUFFERS 8
+#define CHAR_WIDTH 8
+#define CHAR_HEIGHT 16
+
+/* Change this if we run into problems if the kernel want's to free or
+ * use our frame buffer pages, never seen it though.
+ */
+#define FB_MMAP_VM_FLAGS (VM_SHM| VM_LOCKED)
+
+#undef color
+
+/* cursor status, kernel tracked copy */
+struct cg_cursor {
+ short enable; /* cursor is enabled */
+ struct fbcurpos cpos; /* position */
+ struct fbcurpos chot; /* hot-spot */
+ struct fbcurpos size; /* size of mask & image fields */
+ struct fbcurpos hwsize; /* hw max size */
+ int bits[2][32]; /* space for mask & image bits */
+ char color [6]; /* cursor colors */
+};
+
+struct cg6_info {
+ struct bt_regs *bt; /* color control */
+ struct cg6_fbc *fbc;
+ unsigned int *fhc;
+ struct cg6_tec *tec;
+ struct cg6_thc *thc;
+ void *dhc;
+ unsigned char *rom;
+};
+
+struct tcx_info {
+ struct bt_regs *bt; /* color control */
+ struct tcx_tec *tec;
+ struct tcx_thc *thc;
+ void *tcx_cplane;
+ int tcx_sizes[13];
+ long tcx_offsets[13];
+ int lowdepth;
+};
+
+struct leo_info {
+ struct leo_cursor *cursor;
+ struct leo_lc_ss0_krn *lc_ss0_krn;
+ struct leo_lc_ss0_usr *lc_ss0_usr;
+ struct leo_lc_ss1_krn *lc_ss1_krn;
+ struct leo_lc_ss1_usr *lc_ss1_usr;
+ struct leo_ld_ss0 *ld_ss0;
+ struct leo_ld_ss1 *ld_ss1;
+ struct leo_ld_gbl *ld_gbl;
+ struct leo_lx_krn *lx_krn;
+ u32 *cluts[3];
+ u8 *xlut;
+ unsigned long offset;
+};
+
+struct bwtwo_info {
+ struct bwtwo_regs *regs;
+};
+
+struct cg3_info {
+ struct cg3_regs *regs; /* brooktree (color) registers, and more */
+ int cgrdi; /* 1 if this is a cgRDI */
+};
+
+struct cg14_info {
+ struct cg14_regs *regs;
+ struct cg14_cursor *cursor_regs;
+ struct cg14_dac *dac;
+ struct cg14_xlut *xlut;
+ struct cg14_clut *clut;
+ int ramsize;
+ int video_mode;
+};
+
+typedef union
+{
+ unsigned int bt[8];
+ unsigned char ibm[8];
+} dacptr;
+
+struct weitek_info
+{
+ int p9000; /* p9000? or p9100 */
+ dacptr *dac; /* dac structures */
+ unsigned int fbsize; /* size of frame buffer */
+};
+
+/* Array holding the information for the frame buffers */
+typedef struct fbinfo {
+ union {
+ struct bwtwo_info bwtwo;
+ struct cg3_info cg3;
+ struct cg6_info cg6;
+ struct cg14_info cg14;
+ struct tcx_info tcx;
+ struct leo_info leo;
+ } info; /* per frame information */
+ int space; /* I/O space this card resides in */
+ int blanked; /* true if video blanked */
+ int open; /* is this fb open? */
+ int mmaped; /* has this fb been mmapped? */
+ int vtconsole; /* virtual console where it is opened */
+ long base; /* frame buffer base */
+ struct fbtype type; /* frame buffer type */
+ int real_type; /* real frame buffer FBTYPE* */
+ int emulations[4]; /* possible emulations (-1 N/A) */
+ int prom_node; /* node of the device in prom tree */
+ int base_depth; /* depth of fb->base piece */
+ struct cg_cursor cursor; /* kernel state of hw cursor */
+ int (*mmap)(struct inode *, struct file *, struct vm_area_struct *,
+ long fb_base, struct fbinfo *);
+ void (*loadcmap)(struct fbinfo *fb, int index, int count);
+ void (*blank)(struct fbinfo *fb);
+ void (*unblank)(struct fbinfo *fb);
+ int (*ioctl)(struct inode *, struct file *, uint, unsigned long,
+ struct fbinfo *);
+ void (*reset)(struct fbinfo *fb);
+ void (*switch_from_graph)(void);
+ void (*setcursor)(struct fbinfo *);
+ void (*setcurshape)(struct fbinfo *);
+ void (*setcursormap)(struct fbinfo *, unsigned char *,
+ unsigned char *, unsigned char *);
+ unsigned long (*postsetup)(struct fbinfo *, unsigned long);
+ void (*blitc)(unsigned short, int, int);
+ void (*setw)(int, int, unsigned short, int);
+ void (*cpyw)(int, int, unsigned short *, int);
+ void (*fill)(int, int, int *);
+ unsigned char *color_map;
+ struct openpromfs_dev proc_entry;
+} fbinfo_t;
+
+#define CM(i, j) [3*(i)+(j)]
+
+extern unsigned char reverse_color_table[];
+
+#define CHARATTR_TO_SUNCOLOR(attr) \
+ ((reverse_color_table[(attr) >> 12] << 4) | \
+ reverse_color_table[((attr) >> 8) & 0x0f])
+
+extern fbinfo_t *fbinfo;
+extern int fbinfos;
+
+struct {
+ char *name; /* prom name */
+ int width, height; /* prefered w,h match */
+ void (*fbtype)(fbinfo_t *); /* generic device type */
+ /* device specific init routine */
+ unsigned long (*fbinit)(fbinfo_t *fbinfo, unsigned int addr);
+} fb_entry;
+
+extern int fb_init(void);
+
+extern void (*fb_restore_palette)(fbinfo_t *fbinfo);
+extern void (*fb_hide_cursor)(int cursor_pos);
+extern void (*fb_set_cursor)(int oldpos, int idx);
+extern void (*fb_clear_screen)( void );
+extern void (*fb_blitc)(unsigned char *, int, unsigned int *, unsigned int);
+extern void (*fb_font_init)(unsigned char *font);
+/* All framebuffers are likely to require this info */
+
+/* Screen dimensions and color depth. */
+extern int con_depth, con_width;
+extern int con_height, con_linebytes;
+extern int ints_per_line;
+
+/* used in the mmap routines */
+extern unsigned int get_phys (unsigned long addr);
+extern int get_iospace (unsigned long addr);
+extern void render_screen(void);
+
+extern void sun_hw_hide_cursor(void);
+extern void sun_hw_set_cursor(int, int);
+extern int sun_hw_scursor(struct fbcursor *,fbinfo_t *);
+extern int sun_hw_cursor_shown;
+extern int sun_prom_console_id;
+
+extern unsigned long sun_cg_postsetup(fbinfo_t *, unsigned long);
+
+#define FB_DEV(x) (MINOR(x) / 32)
+
+extern void cg3_setup (fbinfo_t *, int, u32, int, struct linux_sbus_device *);
+extern void cg6_setup (fbinfo_t *, int, u32, int);
+extern void cg14_setup (fbinfo_t *, int, int, u32, int);
+extern void bwtwo_setup (fbinfo_t *, int, u32, int,
+ struct linux_sbus_device *);
+extern void leo_setup (fbinfo_t *, int, u32, int);
+extern void tcx_setup (fbinfo_t *, int, int, u32, struct linux_sbus_device *);
+extern void creator_setup (fbinfo_t *, int, int, unsigned long, int);
+extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
+
+#endif __SPARC_FB_H_
diff --git a/drivers/sbus/char/leo.c b/drivers/sbus/char/leo.c
new file mode 100644
index 000000000..b3ec23867
--- /dev/null
+++ b/drivers/sbus/char/leo.c
@@ -0,0 +1,692 @@
+/* $Id: leo.c,v 1.15 1997/04/14 17:04:54 jj Exp $
+ * leo.c: SUNW,leo 24/8bit frame buffer driver
+ *
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz)
+ */
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+#define LEO_OFF_LC_SS0_KRN 0x00200000
+#define LEO_OFF_LC_SS0_USR 0x00201000
+#define LEO_OFF_LC_SS1_KRN 0x01200000
+#define LEO_OFF_LC_SS1_USR 0x01201000
+#define LEO_OFF_LD_SS0 0x00400000
+#define LEO_OFF_LD_SS1 0x01400000
+#define LEO_OFF_LD_GBL 0x00401000
+#define LEO_OFF_LX_KRN 0x00600000
+#define LEO_OFF_LX_CURSOR 0x00601000
+#define LEO_OFF_SS0 0x00800000
+#define LEO_OFF_SS1 0x01800000
+#define LEO_OFF_UNK 0x00602000
+#define LEO_OFF_UNK2 0x00000000
+
+#define LEO_CUR_ENABLE 0x00000080
+#define LEO_CUR_UPDATE 0x00000030
+#define LEO_CUR_PROGRESS 0x00000006
+#define LEO_CUR_UPDATECMAP 0x00000003
+
+#define LEO_CUR_TYPE_MASK 0x00000000
+#define LEO_CUR_TYPE_IMAGE 0x00000020
+#define LEO_CUR_TYPE_CMAP 0x00000050
+
+struct leo_cursor {
+ u8 xxx0[16];
+ volatile u32 cur_type;
+ volatile u32 cur_misc;
+ volatile u32 cur_cursxy;
+ volatile u32 cur_data;
+};
+
+#define LEO_KRN_TYPE_CLUT0 0x00001000
+#define LEO_KRN_TYPE_CLUT1 0x00001001
+#define LEO_KRN_TYPE_CLUT2 0x00001002
+#define LEO_KRN_TYPE_WID 0x00001003
+#define LEO_KRN_TYPE_UNK 0x00001006
+#define LEO_KRN_TYPE_VIDEO 0x00002003
+#define LEO_KRN_TYPE_CLUTDATA 0x00004000
+#define LEO_KRN_CSR_ENABLE 0x00000008
+#define LEO_KRN_CSR_PROGRESS 0x00000004
+#define LEO_KRN_CSR_UNK 0x00000002
+#define LEO_KRN_CSR_UNK2 0x00000001
+
+struct leo_lx_krn {
+ volatile u32 krn_type;
+ volatile u32 krn_csr;
+ volatile u32 krn_value;
+};
+
+struct leo_lc_ss0_krn {
+ volatile u32 misc;
+ u8 xxx0[0x800-4];
+ volatile u32 rev;
+};
+
+struct leo_lc_ss0_usr {
+ volatile u32 csr;
+ volatile u32 attrs;
+ volatile u32 fontc;
+ volatile u32 fontc2;
+ volatile u32 extent;
+ volatile u32 src;
+ u32 xxx1[1];
+ volatile u32 copy;
+ volatile u32 fill;
+};
+
+struct leo_lc_ss1_krn {
+ u8 unknown;
+};
+
+struct leo_lc_ss1_usr {
+ u8 unknown;
+};
+
+struct leo_ld_ss0 {
+ u8 xxx0[0xe00];
+ u32 xxx1[2];
+ volatile u32 unk;
+ u32 xxx2[1];
+ volatile u32 unk2;
+ volatile u32 unk3;
+ u32 xxx3[2];
+ volatile u32 fg;
+ volatile u32 bg;
+ u8 xxx4[0x05c];
+ volatile u32 planemask;
+ volatile u32 rop;
+};
+
+#define LEO_SS1_MISC_ENABLE 0x00000001
+#define LEO_SS1_MISC_STEREO 0x00000002
+struct leo_ld_ss1 {
+ u8 xxx0[0xef4];
+ volatile u32 ss1_misc;
+};
+
+struct leo_ld_gbl {
+ u8 unknown;
+};
+
+static void leo_blitc(unsigned short, int, int);
+static void leo_setw(int, int, unsigned short, int);
+static void leo_cpyw(int, int, unsigned short *, int);
+static void leo_fill(int, int, int *);
+
+static void
+leo_restore_palette (fbinfo_t *fb)
+{
+ fb->info.leo.ld_ss1->ss1_misc &= ~(LEO_SS1_MISC_ENABLE);
+}
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+leo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+ long base, fbinfo_t *fb)
+{
+ uint size, page, r, map_size = 0;
+ uint map_offset = 0;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages */
+ vma->vm_flags |= FB_MMAP_VM_FLAGS;
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ){
+ switch (vma->vm_offset+page){
+ case LEO_SS0_MAP:
+ map_size = 0x800000;
+ map_offset = get_phys ((unsigned long)fb->base);
+ break;
+ case LEO_LC_SS0_USR_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.leo.lc_ss0_usr);
+ break;
+ case LEO_LD_SS0_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.leo.ld_ss0);
+ break;
+ case LEO_LX_CURSOR_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.leo.cursor);
+ break;
+ case LEO_SS1_MAP:
+ map_size = 0x800000;
+ map_offset = fb->info.leo.offset + LEO_OFF_SS1;
+ break;
+ case LEO_LC_SS1_USR_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.leo.lc_ss1_usr);
+ break;
+ case LEO_LD_SS1_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.leo.ld_ss1);
+ break;
+ case LEO_UNK_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = fb->info.leo.offset + LEO_OFF_UNK;
+ break;
+ case LEO_LX_KRN_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.leo.lx_krn);
+ break;
+ case LEO_LC_SS0_KRN_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.leo.lc_ss0_krn);
+ break;
+ case LEO_LC_SS1_KRN_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.leo.lc_ss1_krn);
+ break;
+ case LEO_LD_GBL_MAP:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.leo.ld_gbl);
+ break;
+ case LEO_UNK2_MAP:
+ map_size = 0x100000;
+ map_offset = fb->info.leo.offset + LEO_OFF_UNK2;
+ break;
+ }
+ if (!map_size){
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+ r = io_remap_page_range (vma->vm_start+page,
+ map_offset,
+ map_size, vma->vm_page_prot,
+ fb->space);
+ if (r) return -EAGAIN;
+ page += map_size;
+ }
+ vma->vm_inode = inode;
+ inode->i_count++;
+ return 0;
+}
+
+static void
+leo_setcursormap (fbinfo_t *fb, unsigned char *red,
+ unsigned char *green,
+ unsigned char *blue)
+{
+ struct leo_cursor *l = fb->info.leo.cursor;
+ int i;
+
+ for (i = 0; (l->cur_misc & LEO_CUR_PROGRESS) && i < 300000; i++)
+ udelay (1); /* Busy wait at most 0.3 sec */
+ if (i == 300000) return; /* Timed out - should we print some message? */
+ l->cur_type = LEO_CUR_TYPE_CMAP;
+ l->cur_data = (red[0] | (green[0]<<8) | (blue[0]<<16));
+ l->cur_data = (red[1] | (green[1]<<8) | (blue[1]<<16));
+ l->cur_misc = LEO_CUR_UPDATECMAP;
+}
+
+/* Load cursor information */
+static void
+leo_setcursor (fbinfo_t *fb)
+{
+ struct cg_cursor *c = &fb->cursor;
+ struct leo_cursor *l = fb->info.leo.cursor;
+
+ l->cur_misc &= ~LEO_CUR_ENABLE;
+ l->cur_cursxy = ((c->cpos.fbx - c->chot.fbx) & 0x7ff)
+ |(((c->cpos.fby - c->chot.fby) & 0x7ff) << 11);
+ l->cur_misc |= LEO_CUR_UPDATE;
+ if (c->enable)
+ l->cur_misc |= LEO_CUR_ENABLE;
+}
+
+/* Set cursor shape */
+static void
+leo_setcurshape (fbinfo_t *fb)
+{
+ int i, j, k;
+ u32 m, n, mask;
+ struct leo_cursor *l = fb->info.leo.cursor;
+
+ l->cur_misc &= ~LEO_CUR_ENABLE;
+ for (k = 0; k < 2; k ++) {
+ l->cur_type = (k * LEO_CUR_TYPE_IMAGE); /* LEO_CUR_TYPE_MASK is 0 */
+ for (i = 0; i < 32; i++) {
+ mask = 0;
+ m = fb->cursor.bits[k][i];
+ /* mask = m with reversed bit order */
+ for (j = 0, n = 1; j < 32; j++, n <<= 1)
+ if (m & n)
+ mask |= (0x80000000 >> j);
+ l->cur_data = mask;
+ }
+ }
+ l->cur_misc |= LEO_CUR_ENABLE;
+}
+
+static void
+leo_blank (fbinfo_t *fb)
+{
+ fb->info.leo.lx_krn->krn_type = LEO_KRN_TYPE_VIDEO;
+ fb->info.leo.lx_krn->krn_csr &= ~LEO_KRN_CSR_ENABLE;
+}
+
+static void
+leo_unblank (fbinfo_t *fb)
+{
+ fb->info.leo.lx_krn->krn_type = LEO_KRN_TYPE_VIDEO;
+ if (!(fb->info.leo.lx_krn->krn_csr & LEO_KRN_CSR_ENABLE))
+ fb->info.leo.lx_krn->krn_csr |= LEO_KRN_CSR_ENABLE;
+}
+
+static int leo_wait (struct leo_lx_krn *lx_krn)
+{
+ int i;
+ for (i = 0; (lx_krn->krn_csr & LEO_KRN_CSR_PROGRESS) && i < 300000; i++)
+ udelay (1); /* Busy wait at most 0.3 sec */
+ if (i == 300000) return -EFAULT; /* Timed out - should we print some message? */
+ return 0;
+}
+
+static int
+leo_wid_get (fbinfo_t *fb, struct fb_wid_list *wl)
+{
+ struct leo_lx_krn *lx_krn = fb->info.leo.lx_krn;
+ struct fb_wid_item *wi;
+ int i, j;
+ u32 l;
+
+ lx_krn->krn_type = LEO_KRN_TYPE_WID;
+ i = leo_wait (lx_krn);
+ if (i) return i;
+ lx_krn->krn_csr &= ~LEO_KRN_CSR_UNK2;
+ lx_krn->krn_csr |= LEO_KRN_CSR_UNK;
+ lx_krn->krn_type = LEO_KRN_TYPE_WID;
+ i = leo_wait (lx_krn);
+ if (i) return i;
+ for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) {
+ switch (wi->wi_type) {
+ case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break;
+ case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break;
+ default: return -EINVAL;
+ }
+ wi->wi_attrs = 0xffff;
+ lx_krn->krn_type = 0x5800 + j;
+ l = lx_krn->krn_value;
+ for (j = 0; j < 32; j++)
+ wi->wi_values [j] = l;
+ }
+ return 0;
+}
+
+static int
+leo_wid_put (fbinfo_t *fb, struct fb_wid_list *wl)
+{
+ struct leo_lx_krn *lx_krn = fb->info.leo.lx_krn;
+ struct fb_wid_item *wi;
+ int i, j;
+
+ lx_krn->krn_type = LEO_KRN_TYPE_WID;
+ i = leo_wait (lx_krn);
+ if (i) return i;
+ for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) {
+ switch (wi->wi_type) {
+ case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break;
+ case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break;
+ default: return -EINVAL;
+ }
+ lx_krn->krn_type = 0x5800 + j;
+ lx_krn->krn_value = wi->wi_values[0];
+ }
+ return 0;
+}
+
+static int leo_clutstore (fbinfo_t *fb, int clutid)
+{
+ int i;
+ u32 *clut = fb->info.leo.cluts [clutid];
+ struct leo_lx_krn *lx_krn = fb->info.leo.lx_krn;
+
+ lx_krn->krn_type = LEO_KRN_TYPE_CLUT0 + clutid;
+ i = leo_wait (lx_krn);
+ if (i) return i;
+ lx_krn->krn_type = LEO_KRN_TYPE_CLUTDATA;
+ for (i = 0; i < 256; i++)
+ lx_krn->krn_value = *clut++; /* Throw colors there :)) */
+ lx_krn->krn_type = LEO_KRN_TYPE_CLUT0 + clutid;
+ lx_krn->krn_csr |= (LEO_KRN_CSR_UNK|LEO_KRN_CSR_UNK2);
+ return 0;
+}
+
+static int leo_clutpost (fbinfo_t *fb, struct leo_clut *lc)
+{
+ int xlate = 0, i;
+ u32 *clut;
+ u8 *xlut = fb->info.leo.xlut;
+
+ switch (lc->clutid) {
+ case 0:
+ case 1:
+ case 2: break;
+ case 3: return -EINVAL; /* gamma clut - not yet implemented */
+ case 4: return -EINVAL; /* degamma clut - not yet implemented */
+ default: return -EINVAL;
+ }
+ clut = fb->info.leo.cluts [lc->clutid] + lc->offset;
+ for (i = 0; i < lc->count; i++)
+ *clut++ = xlate ?
+ ((xlut[(u8)(lc->red[i])])|(xlut[(u8)(lc->green[i])]<<8)|(xlut[(u8)(lc->blue[i])]<<16)) :
+ (((u8)(lc->red[i]))|(((u8)(lc->green[i]))<<8)|(((u8)(lc->blue[i]))<<16));
+ return leo_clutstore (fb, lc->clutid);
+}
+
+static int leo_clutread (fbinfo_t *fb, struct leo_clut *lc)
+{
+ int i;
+ u32 u;
+ struct leo_lx_krn *lx_krn = fb->info.leo.lx_krn;
+
+ if (lc->clutid >= 3) return -EINVAL;
+ lx_krn->krn_type = LEO_KRN_TYPE_CLUT0 + lc->clutid;
+ i = leo_wait (lx_krn);
+ if (i) return i;
+ lx_krn->krn_csr &= ~LEO_KRN_CSR_UNK2;
+ lx_krn->krn_csr |= LEO_KRN_CSR_UNK;
+ i = leo_wait (lx_krn);
+ if (i) return i;
+ lx_krn->krn_type = LEO_KRN_TYPE_CLUTDATA;
+ for (i = 0; i < lc->offset; i++)
+ u = lx_krn->krn_value;
+ for (i = 0; i < lc->count; i++) {
+ u = lx_krn->krn_value;
+ lc->red [i] = u;
+ lc->green [i] = (u >> 8);
+ lc->blue [i] = (u >> 16);
+ }
+ return 0;
+}
+
+static void
+leo_loadcmap (fbinfo_t *fb, int index, int count)
+{
+ u32 *clut = ((u32 *)fb->info.leo.cluts [0]) + index;
+ int i;
+
+ for (i = index; count--; i++)
+ *clut++ = ((fb->color_map CM(i,0))) |
+ ((fb->color_map CM(i,1)) << 8) |
+ ((fb->color_map CM(i,2)) << 16);
+ leo_clutstore (fb, 0);
+}
+
+/* Handle leo-specific ioctls */
+static int
+leo_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
+{
+ int i;
+
+ switch (cmd) {
+ case FBIO_WID_GET:
+ i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct fb_wid_list));
+ if (i) return i;
+ if (((struct fb_wid_list *)arg)->wl_count != 1 ||
+ !((struct fb_wid_list *)arg)->wl_list) return -EINVAL;
+ i = verify_area (VERIFY_WRITE, (void *)(((struct fb_wid_list *)arg)->wl_list),
+ ((struct fb_wid_list *)arg)->wl_count * sizeof (struct fb_wid_item));
+ if (i) return i;
+ return leo_wid_get (fb, (struct fb_wid_list *)arg);
+ case FBIO_WID_PUT:
+ i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct fb_wid_list));
+ if (i) return i;
+ if (((struct fb_wid_list *)arg)->wl_count != 1 ||
+ !((struct fb_wid_list *)arg)->wl_list) return -EINVAL;
+ i = verify_area (VERIFY_WRITE, (void *)(((struct fb_wid_list *)arg)->wl_list),
+ ((struct fb_wid_list *)arg)->wl_count * sizeof (struct fb_wid_item));
+ if (i) return i;
+ return leo_wid_put (fb, (struct fb_wid_list *)arg);
+ case LEO_CLUTPOST:
+ i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct leo_clut));
+ if (i) return i;
+ i = ((struct leo_clut *)arg)->offset + ((struct leo_clut *)arg)->count;
+ if (i <= 0 || i > 256) return -EINVAL;
+ i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->red, ((struct leo_clut *)arg)->count);
+ if (i) return i;
+ i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->green, ((struct leo_clut *)arg)->count);
+ if (i) return i;
+ i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->blue, ((struct leo_clut *)arg)->count);
+ if (i) return i;
+ return leo_clutpost (fb, (struct leo_clut *)arg);
+ case LEO_CLUTREAD:
+ i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct leo_clut));
+ if (i) return i;
+ i = ((struct leo_clut *)arg)->offset + ((struct leo_clut *)arg)->count;
+ if (i <= 0 || i > 256) return -EINVAL;
+ i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->red, ((struct leo_clut *)arg)->count);
+ if (i) return i;
+ i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->green, ((struct leo_clut *)arg)->count);
+ if (i) return i;
+ i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->blue, ((struct leo_clut *)arg)->count);
+ if (i) return i;
+ return leo_clutread (fb, (struct leo_clut *)arg);
+
+ default:
+ return -ENOSYS;
+ }
+}
+
+static void
+leo_reset (fbinfo_t *fb)
+{
+ if (fb->setcursor)
+ sun_hw_hide_cursor ();
+}
+
+
+__initfunc(static unsigned long leo_postsetup (fbinfo_t *fb, unsigned long memory_start))
+{
+ fb->info.leo.cluts[0] = (u32 *)(memory_start);
+ fb->info.leo.cluts[1] = (u32 *)(memory_start+256*4);
+ fb->info.leo.cluts[2] = (u32 *)(memory_start+256*4*2);
+ fb->info.leo.xlut = (u8 *)(memory_start+256*4*3);
+ fb->color_map = (u8 *)(memory_start+256*4*3+256);
+ return memory_start + (256*4*3) + 256 + 256*3;
+}
+
+__initfunc(void leo_setup (fbinfo_t *fb, int slot, u32 leo, int leo_io))
+{
+ struct leo_info *leoinfo;
+ int i;
+ struct fb_wid_item wi;
+ struct fb_wid_list wl;
+
+ printk ("leo%d at 0x%8.8x ", slot, leo);
+
+ /* Fill in parameters we left out */
+ fb->type.fb_size = 0x800000; /* 8MB */
+ fb->type.fb_cmsize = 256;
+ fb->mmap = leo_mmap;
+ fb->loadcmap = leo_loadcmap;
+ fb->postsetup = leo_postsetup;
+ fb->ioctl = (void *)leo_ioctl;
+ fb->reset = leo_reset;
+ fb->blank = leo_blank;
+ fb->unblank = leo_unblank;
+ fb->setcursor = leo_setcursor;
+ fb->setcursormap = leo_setcursormap;
+ fb->setcurshape = leo_setcurshape;
+ fb->blitc = leo_blitc;
+ fb->setw = leo_setw;
+ fb->cpyw = leo_cpyw;
+ fb->fill = leo_fill;
+ fb->base_depth = 0;
+
+ leoinfo = (struct leo_info *) &fb->info.leo;
+
+ memset (leoinfo, 0, sizeof(struct leo_info));
+
+ leoinfo->offset = leo;
+ /* Map the hardware registers */
+ leoinfo->lc_ss0_krn = sparc_alloc_io(leo + LEO_OFF_LC_SS0_KRN, 0,
+ PAGE_SIZE,"leo_lc_ss0_krn", fb->space, 0);
+ leoinfo->lc_ss0_usr = sparc_alloc_io(leo + LEO_OFF_LC_SS0_USR, 0,
+ PAGE_SIZE,"leo_lc_ss0_usr", fb->space, 0);
+ leoinfo->lc_ss1_krn = sparc_alloc_io(leo + LEO_OFF_LC_SS1_KRN, 0,
+ PAGE_SIZE,"leo_lc_ss1_krn", fb->space, 0);
+ leoinfo->lc_ss1_usr = sparc_alloc_io(leo + LEO_OFF_LC_SS1_USR, 0,
+ PAGE_SIZE,"leo_lc_ss1_usr", fb->space, 0);
+ leoinfo->ld_ss0 = sparc_alloc_io(leo + LEO_OFF_LD_SS0, 0,
+ PAGE_SIZE,"leo_ld_ss0", fb->space, 0);
+ leoinfo->ld_ss1 = sparc_alloc_io(leo + LEO_OFF_LD_SS1, 0,
+ PAGE_SIZE,"leo_ld_ss1", fb->space, 0);
+ leoinfo->ld_gbl = sparc_alloc_io(leo + LEO_OFF_LD_GBL, 0,
+ PAGE_SIZE,"leo_ld_gbl", fb->space, 0);
+ leoinfo->lx_krn = sparc_alloc_io(leo + LEO_OFF_LX_KRN, 0,
+ PAGE_SIZE,"leo_lx_krn", fb->space, 0);
+ leoinfo->cursor = sparc_alloc_io(leo + LEO_OFF_LX_CURSOR, 0,
+ sizeof(struct leo_cursor),"leo_lx_crsr", fb->space, 0);
+ fb->base = (long)sparc_alloc_io(leo + LEO_OFF_SS0, 0,
+ 0x800000,"leo_ss0", fb->space, 0);
+
+ leoinfo->ld_ss0->unk = 0xffff;
+ leoinfo->ld_ss0->unk2 = 0;
+ leoinfo->ld_ss0->unk3 = (fb->type.fb_width - 1) | ((fb->type.fb_height - 1) << 16);
+ wl.wl_count = 1;
+ wl.wl_list = &wi;
+ wi.wi_type = FB_WID_DBL_8;
+ wi.wi_index = 0;
+ wi.wi_values [0] = 0x2c0;
+ leo_wid_put (fb, &wl);
+ wi.wi_index = 1;
+ wi.wi_values [0] = 0x30;
+ leo_wid_put (fb, &wl);
+ wi.wi_index = 2;
+ wi.wi_values [0] = 0x20;
+ leo_wid_put (fb, &wl);
+
+ leoinfo->ld_ss1->ss1_misc |= LEO_SS1_MISC_ENABLE;
+
+ leoinfo->ld_ss0->fg = 0x30703;
+ leoinfo->ld_ss0->planemask = 0xff000000;
+ leoinfo->ld_ss0->rop = 0xd0840;
+ leoinfo->lc_ss0_usr->extent = (fb->type.fb_width-1) | ((fb->type.fb_height-1) << 11);
+ i = leoinfo->lc_ss0_usr->attrs;
+ leoinfo->lc_ss0_usr->fill = (0) | ((0) << 11) | ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0);
+ do {
+ i = leoinfo->lc_ss0_usr->csr;
+ } while (i & 0x20000000);
+
+ if (slot == sun_prom_console_id)
+ fb_restore_palette = leo_restore_palette;
+
+ printk("Cmd Rev %d\n",
+ (leoinfo->lc_ss0_krn->rev >> 28));
+
+ /* Reset the leo */
+ leo_reset(fb);
+
+ if (!slot)
+ /* Enable Video */
+ leo_unblank (fb);
+ else if (slot != sun_prom_console_id)
+ leo_blank (fb);
+}
+
+extern unsigned char vga_font [];
+
+#define GX_BLITC_START(attr,x,y,count) \
+ { \
+ register struct leo_lc_ss0_usr *us = fbinfo[0].info.leo.lc_ss0_usr; \
+ register struct leo_ld_ss0 *ss = fbinfo[0].info.leo.ld_ss0; \
+ register u32 i; \
+ do { \
+ i = us->csr; \
+ } while (i & 0x20000000); \
+ ss->fg = (attr & 0xf) << 24; \
+ ss->bg = (attr >> 4) << 24; \
+ ss->rop = 0x310040; \
+ ss->planemask = 0xff000000; \
+ us->fontc2 = 0xFFFFFFFE; \
+ us->attrs = 4; \
+ us->fontc = 0xFF000000;
+#define GX_BLITC_END \
+ }
+
+static void leo_blitc(unsigned short charattr, int xoff, int yoff)
+{
+ unsigned char attrib = CHARATTR_TO_SUNCOLOR(charattr);
+ unsigned char *p = &vga_font[((unsigned char)charattr) << 4];
+ u32 *u = ((u32 *)fbinfo[0].base) + (yoff << 11) + xoff;
+ GX_BLITC_START(attrib, xoff, yoff, 1)
+ for (i = 0; i < CHAR_HEIGHT; i++, u += 2048)
+ *u = (*p++) << 24;
+ GX_BLITC_END
+}
+
+static void leo_setw(int xoff, int yoff, unsigned short c, int count)
+{
+ unsigned char attrib = CHARATTR_TO_SUNCOLOR(c);
+ unsigned char *p = &vga_font[((unsigned char)c) << 4];
+ register unsigned char *q;
+ u32 *u = ((u32 *)fbinfo[0].base) + (yoff << 11) + xoff;
+ GX_BLITC_START(attrib, xoff, yoff, count)
+ while (count-- > 0) {
+ q = p;
+ for (i = 0; i < CHAR_HEIGHT; i++, u += 2048)
+ *u = (*q++) << 24;
+ u += 8 - (CHAR_HEIGHT * 2048);
+ }
+ GX_BLITC_END
+}
+
+static void leo_cpyw(int xoff, int yoff, unsigned short *p, int count)
+{
+ unsigned char attrib = CHARATTR_TO_SUNCOLOR(*p);
+ register unsigned char *q;
+ u32 *u = ((u32 *)fbinfo[0].base) + (yoff << 11) + xoff;
+ GX_BLITC_START(attrib, xoff, yoff, count)
+ while (count-- > 0) {
+ q = &vga_font[((unsigned char)*p++) << 4];
+ for (i = 0; i < CHAR_HEIGHT; i++, u += 2048)
+ *u = (*q++) << 24;
+ u += 8 - (CHAR_HEIGHT * 2048);
+ }
+ GX_BLITC_END
+}
+
+static void leo_fill(int attrib, int count, int *boxes)
+{
+ register struct leo_lc_ss0_usr *us = fbinfo[0].info.leo.lc_ss0_usr;
+ register struct leo_ld_ss0 *ss = fbinfo[0].info.leo.ld_ss0;
+ register u32 i;
+ do {
+ i = us->csr;
+ } while (i & 0x20000000);
+ ss->unk = 0xffff;
+ ss->unk2 = 0;
+ ss->unk3 = (fbinfo[0].type.fb_width - 1) | ((fbinfo[0].type.fb_height - 1) << 16);
+ ss->fg = ((attrib & 0xf)<<24) | 0x030703;
+ ss->planemask = 0xff000000;
+ ss->rop = 0xd0840;
+ while (count-- > 0) {
+ us->extent = ((boxes[2] - boxes[0] - 1) & 0x7ff) | (((boxes[3] - boxes[1] - 1) & 0x7ff) << 11);
+ i = us->attrs;
+ us->fill = (boxes[0] & 0x7ff) | ((boxes[1] & 0x7ff) << 11) | ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0);
+ }
+}
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
new file mode 100644
index 000000000..548abb601
--- /dev/null
+++ b/drivers/sbus/char/openprom.c
@@ -0,0 +1,611 @@
+/*
+ * Linux/SPARC PROM Configuration Driver
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ * This character device driver allows user programs to access the
+ * PROM device tree. It is compatible with the SunOS /dev/openprom
+ * driver and the NetBSD /dev/openprom driver. The SunOS eeprom
+ * utility works without any modifications.
+ *
+ * The driver uses a minor number under the misc device major. The
+ * file read/write mode determines the type of access to the PROM.
+ * Interrupts are disabled whenever the driver calls into the PROM for
+ * sanity's sake.
+ */
+
+/* This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define PROMLIB_INTERNAL
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/openpromio.h>
+
+
+/* Private data kept by the driver for each descriptor. */
+typedef struct openprom_private_data
+{
+ int current_node; /* Current node for SunOS ioctls. */
+ int lastnode; /* Last valid node used by BSD ioctls. */
+} DATA;
+
+/* ID of the PROM node containing all of the EEPROM options. */
+static int options_node = 0;
+
+/*
+ * Copy an openpromio structure into kernel space from user space.
+ * This routine does error checking to make sure that all memory
+ * accesses are within bounds. A pointer to the allocated openpromio
+ * structure will be placed in "*opp_p". Return value is the length
+ * of the user supplied buffer.
+ */
+static int copyin(struct openpromio *info, struct openpromio **opp_p)
+{
+ int bufsize;
+
+ if (!info || !opp_p)
+ return -EFAULT;
+
+ get_user_ret(bufsize, &info->oprom_size, -EFAULT);
+
+ if (bufsize == 0 || bufsize > OPROMMAXPARAM)
+ return -EINVAL;
+
+ if (!(*opp_p = kmalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
+ return -ENOMEM;
+ memset(*opp_p, 0, sizeof(int) + bufsize + 1);
+
+ if (copy_from_user(&(*opp_p)->oprom_array,
+ &info->oprom_array, bufsize)) {
+ kfree(*opp_p);
+ return -EFAULT;
+ }
+ return bufsize;
+}
+
+static int getstrings(struct openpromio *info, struct openpromio **opp_p)
+{
+ int n, bufsize;
+ char c;
+
+ if (!info || !opp_p)
+ return -EFAULT;
+
+ if (!(*opp_p = kmalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL)))
+ return -ENOMEM;
+
+ memset(*opp_p, 0, sizeof(int) + OPROMMAXPARAM + 1);
+ (*opp_p)->oprom_size = 0;
+
+ n = bufsize = 0;
+ while ((n < 2) && (bufsize < OPROMMAXPARAM)) {
+ if (get_user(c, &info->oprom_array[bufsize])) {
+ kfree(*opp_p);
+ return -EFAULT;
+ }
+ if (c == '\0')
+ n++;
+ (*opp_p)->oprom_array[bufsize++] = c;
+ }
+ if (!n) {
+ kfree(*opp_p);
+ return -EINVAL;
+ }
+ return bufsize;
+}
+
+/*
+ * Copy an openpromio structure in kernel space back to user space.
+ */
+static int copyout(void *info, struct openpromio *opp, int len)
+{
+ copy_to_user_ret(info, opp, len, -EFAULT);
+ return 0;
+}
+
+/*
+ * SunOS and Solaris /dev/openprom ioctl calls.
+ */
+static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg, int node)
+{
+ DATA *data = (DATA *) file->private_data;
+ char buffer[OPROMMAXPARAM+1], *buf;
+ struct openpromio *opp;
+ unsigned long flags;
+ int bufsize, len, error = 0;
+
+ if (cmd == OPROMSETOPT)
+ bufsize = getstrings((void *)arg, &opp);
+ else
+ bufsize = copyin((void *)arg, &opp);
+
+ if (bufsize < 0)
+ return bufsize;
+
+ switch (cmd) {
+ case OPROMGETOPT:
+ case OPROMGETPROP:
+ save_and_cli(flags);
+ len = prom_getproplen(node, opp->oprom_array);
+ restore_flags(flags);
+
+ if (len <= 0 || len > bufsize) {
+ error = copyout((void *)arg, opp, sizeof(int));
+ break;
+ }
+
+ save_and_cli(flags);
+ len = prom_getproperty(node, opp->oprom_array, buffer, bufsize);
+ restore_flags(flags);
+
+ memcpy(opp->oprom_array, buffer, len);
+ opp->oprom_array[len] = '\0';
+ opp->oprom_size = len;
+
+ error = copyout((void *)arg, opp, sizeof(int) + bufsize);
+ break;
+
+ case OPROMNXTOPT:
+ case OPROMNXTPROP:
+ save_and_cli(flags);
+ buf = prom_nextprop(node, opp->oprom_array);
+ restore_flags(flags);
+
+ len = strlen(buf);
+ if (len == 0 || len + 1 > bufsize) {
+ error = copyout((void *)arg, opp, sizeof(int));
+ break;
+ }
+
+ memcpy(opp->oprom_array, buf, len);
+ opp->oprom_array[len] = '\0';
+ opp->oprom_size = ++len;
+
+ error = copyout((void *)arg, opp, sizeof(int) + bufsize);
+ break;
+
+ case OPROMSETOPT:
+ case OPROMSETOPT2:
+ buf = opp->oprom_array + strlen(opp->oprom_array) + 1;
+ len = opp->oprom_array + bufsize - buf;
+
+ printk(KERN_DEBUG "OPROMSETOPT%s %s='%s'\n",
+ (cmd == OPROMSETOPT) ? "" : "2", opp->oprom_array, buf);
+
+ save_and_cli(flags);
+ error = prom_setprop(options_node, opp->oprom_array,
+ buf, len);
+ restore_flags(flags);
+
+ if (error <= 0)
+ error = -EINVAL;
+ break;
+
+ case OPROMNEXT:
+ case OPROMCHILD:
+ if (bufsize < sizeof(int)) {
+ error = -EINVAL;
+ break;
+ }
+
+ node = *((int *) opp->oprom_array);
+
+ save_and_cli(flags);
+ if (cmd == OPROMNEXT)
+ node = __prom_getsibling(node);
+ else
+ node = __prom_getchild(node);
+ restore_flags(flags);
+
+ data->current_node = node;
+ *((int *)opp->oprom_array) = node;
+ opp->oprom_size = sizeof(int);
+
+ error = copyout((void *)arg, opp, bufsize + sizeof(int));
+ break;
+
+ case OPROMGETBOOTARGS:
+ save_and_cli(flags);
+ buf = prom_getbootargs();
+ restore_flags(flags);
+
+ len = strlen(buf);
+
+ if (len > bufsize) {
+ error = -EINVAL;
+ break;
+ }
+
+ strcpy(opp->oprom_array, buf);
+ opp->oprom_size = len;
+
+ error = copyout((void *)arg, opp, bufsize + sizeof(int));
+ break;
+
+ case OPROMU2P:
+ case OPROMGETCONS:
+ case OPROMGETFBNAME:
+ printk(KERN_INFO "openprom_sunos_ioctl: unimplemented ioctl\n");
+ error = -EINVAL;
+ break;
+ default:
+ printk(KERN_INFO "openprom_sunos_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg);
+ error = -EINVAL;
+ break;
+ }
+
+ kfree(opp);
+ return error;
+}
+
+
+/* Return nonzero if a specific node is in the PROM device tree. */
+static int intree(int root, int node)
+{
+ for (; root != 0; root = prom_getsibling(root))
+ if (root == node || intree(prom_getchild(root),node))
+ return 1;
+ return 0;
+}
+
+/* Return nonzero if a specific node is "valid". */
+static int goodnode(int n, DATA *data)
+{
+ if (n == data->lastnode || n == prom_root_node || n == options_node)
+ return 1;
+ if (n == 0 || n == -1 || !intree(prom_root_node,n))
+ return 0;
+ data->lastnode = n;
+ return 1;
+}
+
+/* Copy in a whole string from userspace into kernelspace. */
+static int copyin_string(char *user, size_t len, char **ptr)
+{
+ char *tmp;
+
+ tmp = kmalloc(len + 1, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ if(copy_from_user(tmp, user, len)) {
+ kfree(tmp);
+ return -EFAULT;
+ }
+
+ tmp[len] = '\0';
+
+ *ptr = tmp;
+
+ return 0;
+}
+
+/*
+ * NetBSD /dev/openprom ioctl calls.
+ */
+static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ DATA *data = (DATA *) file->private_data;
+ struct opiocdesc op;
+ unsigned long flags;
+ int error, node, len;
+ char *str, *tmp;
+
+ switch (cmd) {
+ case OPIOCGET:
+ copy_from_user_ret(&op, (void *)arg, sizeof(op), -EFAULT);
+
+ if (!goodnode(op.op_nodeid,data))
+ return -EINVAL;
+
+ error = copyin_string(op.op_name, op.op_namelen, &str);
+ if (error)
+ return error;
+
+ save_and_cli(flags);
+ len = prom_getproplen(op.op_nodeid,str);
+ restore_flags(flags);
+
+ if (len > op.op_buflen) {
+ kfree(str);
+ return -ENOMEM;
+ }
+
+ op.op_buflen = len;
+
+ if (len <= 0) {
+ kfree(str);
+ /* Verified by the above copy_from_user_ret */
+ __copy_to_user_ret((void *)arg, &op,
+ sizeof(op), -EFAULT);
+ return 0;
+ }
+
+ tmp = kmalloc(len + 1, GFP_KERNEL);
+ if (!tmp) {
+ kfree(str);
+ return -ENOMEM;
+ }
+
+ save_and_cli(flags);
+ prom_getproperty(op.op_nodeid, str, tmp, len);
+ restore_flags(flags);
+
+ tmp[len] = '\0';
+
+ error = __copy_to_user((void *)arg, &op, sizeof(op));
+ if (!error)
+ error = copy_to_user(op.op_buf, tmp, len);
+
+ kfree(tmp);
+ kfree(str);
+
+ return error;
+
+ case OPIOCNEXTPROP:
+ copy_from_user_ret(&op, (void *)arg, sizeof(op), -EFAULT);
+
+ if (!goodnode(op.op_nodeid,data))
+ return -EINVAL;
+
+ error = copyin_string(op.op_name, op.op_namelen, &str);
+ if (error)
+ return error;
+
+ save_and_cli(flags);
+ tmp = prom_nextprop(op.op_nodeid,str);
+ restore_flags(flags);
+
+ if (tmp) {
+ len = strlen(tmp);
+ if (len > op.op_buflen)
+ len = op.op_buflen;
+ else
+ op.op_buflen = len;
+ } else {
+ len = op.op_buflen = 0;
+ }
+
+ error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(op));
+ if (error) {
+ kfree(str);
+ return error;
+ }
+
+ error = verify_area(VERIFY_WRITE, op.op_buf, len);
+ if (error) {
+ kfree(str);
+ return error;
+ }
+
+ error = __copy_to_user((void *)arg, &op, sizeof(op));
+ if (!error) error = __copy_to_user(op.op_buf, tmp, len);
+
+ kfree(str);
+
+ return error;
+
+ case OPIOCSET:
+ copy_from_user_ret(&op, (void *)arg, sizeof(op), -EFAULT);
+
+ if (!goodnode(op.op_nodeid,data))
+ return -EINVAL;
+
+ error = copyin_string(op.op_name, op.op_namelen, &str);
+ if (error)
+ return error;
+
+ error = copyin_string(op.op_buf, op.op_buflen, &tmp);
+ if (error) {
+ kfree(str);
+ return error;
+ }
+
+ save_and_cli(flags);
+ len = prom_setprop(op.op_nodeid,str,tmp,op.op_buflen+1);
+ restore_flags(flags);
+
+ if (len != op.op_buflen)
+ return -EINVAL;
+
+ kfree(str);
+ kfree(tmp);
+
+ return 0;
+
+ case OPIOCGETOPTNODE:
+ copy_to_user_ret((void *)arg, &options_node,
+ sizeof(int), -EFAULT);
+ return 0;
+
+ case OPIOCGETNEXT:
+ case OPIOCGETCHILD:
+ copy_from_user_ret(&node, (void *)arg, sizeof(int), -EFAULT);
+
+ save_and_cli(flags);
+ if (cmd == OPIOCGETNEXT)
+ node = __prom_getsibling(node);
+ else
+ node = __prom_getchild(node);
+ restore_flags(flags);
+
+ __copy_to_user_ret((void *)arg, &node, sizeof(int), -EFAULT);
+
+ return 0;
+
+ default:
+ printk(KERN_INFO "openprom_bsd_ioctl: cmd 0x%X\n", cmd);
+ return -EINVAL;
+
+ }
+}
+
+
+/*
+ * Handoff control to the correct ioctl handler.
+ */
+static int openprom_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ DATA *data = (DATA *) file->private_data;
+
+ switch (cmd) {
+ case OPROMGETOPT:
+ case OPROMNXTOPT:
+ if ((file->f_mode & FMODE_READ) == 0)
+ return -EPERM;
+ return openprom_sunos_ioctl(inode, file, cmd, arg,
+ options_node);
+
+ case OPROMSETOPT:
+ case OPROMSETOPT2:
+ if ((file->f_mode & FMODE_WRITE) == 0)
+ return -EPERM;
+ return openprom_sunos_ioctl(inode, file, cmd, arg,
+ options_node);
+
+ case OPROMNEXT:
+ case OPROMCHILD:
+ case OPROMGETPROP:
+ case OPROMNXTPROP:
+ if ((file->f_mode & FMODE_READ) == 0)
+ return -EPERM;
+ return openprom_sunos_ioctl(inode, file, cmd, arg,
+ data->current_node);
+
+ case OPROMU2P:
+ case OPROMGETCONS:
+ case OPROMGETFBNAME:
+ case OPROMGETBOOTARGS:
+ if ((file->f_mode & FMODE_READ) == 0)
+ return -EPERM;
+ return openprom_sunos_ioctl(inode, file, cmd, arg, 0);
+
+ case OPIOCGET:
+ case OPIOCNEXTPROP:
+ case OPIOCGETOPTNODE:
+ case OPIOCGETNEXT:
+ case OPIOCGETCHILD:
+ if ((file->f_mode & FMODE_READ) == 0)
+ return -EBADF;
+ return openprom_bsd_ioctl(inode,file,cmd,arg);
+
+ case OPIOCSET:
+ if ((file->f_mode & FMODE_WRITE) == 0)
+ return -EBADF;
+ return openprom_bsd_ioctl(inode,file,cmd,arg);
+
+ default:
+ printk("openprom_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg);
+ return -EINVAL;
+ }
+}
+
+static long long openprom_lseek(struct inode * inode, struct file * file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static int openprom_open(struct inode * inode, struct file * file)
+{
+ DATA *data;
+
+ data = (DATA *) kmalloc(sizeof(DATA), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->current_node = prom_root_node;
+ data->lastnode = prom_root_node;
+ file->private_data = (void *)data;
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int openprom_release(struct inode * inode, struct file * file)
+{
+ kfree_s(file->private_data, sizeof(DATA));
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static struct file_operations openprom_fops = {
+ openprom_lseek,
+ NULL, /* openprom_read */
+ NULL, /* openprom_write */
+ NULL, /* openprom_readdir */
+ NULL, /* openprom_poll */
+ openprom_ioctl,
+ NULL, /* openprom_mmap */
+ openprom_open,
+ openprom_release
+};
+
+static struct miscdevice openprom_dev = {
+ SUN_OPENPROM_MINOR, "openprom", &openprom_fops
+};
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int openprom_init(void))
+#endif
+{
+ unsigned long flags;
+ int error;
+
+ error = misc_register(&openprom_dev);
+ if (error) {
+ printk(KERN_ERR "openprom: unable to get misc minor\n");
+ return error;
+ }
+
+ save_and_cli(flags);
+ options_node = prom_getchild(prom_root_node);
+ options_node = prom_searchsiblings(options_node,"options");
+ restore_flags(flags);
+
+ if (options_node == 0 || options_node == -1) {
+ printk(KERN_ERR "openprom: unable to find options node\n");
+ misc_deregister(&openprom_dev);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ misc_deregister(&openprom_dev);
+}
+#endif
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
new file mode 100644
index 000000000..e0fbf2569
--- /dev/null
+++ b/drivers/sbus/char/rtc.c
@@ -0,0 +1,166 @@
+/* $Id: rtc.c,v 1.10 1997/04/03 08:47:55 davem Exp $
+ *
+ * Linux/SPARC Real Time Clock Driver
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ *
+ * This is a little driver that lets a user-level program access
+ * the SPARC Mostek real time clock chip. It is no use unless you
+ * use the modified clock utility.
+ *
+ * Get the modified clock utility from:
+ * ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <asm/mostek.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/rtc.h>
+
+static int rtc_busy = 0;
+
+/* Retrieve the current date and time from the real time clock. */
+void get_rtc_time(struct rtc_time *t)
+{
+ register struct mostek48t02 *regs = mstk48t02_regs;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ regs->creg |= MSTK_CREG_READ;
+
+ t->sec = MSTK_REG_SEC(regs);
+ t->min = MSTK_REG_MIN(regs);
+ t->hour = MSTK_REG_HOUR(regs);
+ t->dow = MSTK_REG_DOW(regs);
+ t->dom = MSTK_REG_DOM(regs);
+ t->month = MSTK_REG_MONTH(regs);
+ t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
+
+ regs->creg &= ~MSTK_CREG_READ;
+ restore_flags(flags);
+}
+
+/* Set the current date and time inthe real time clock. */
+void set_rtc_time(struct rtc_time *t)
+{
+ register struct mostek48t02 *regs = mstk48t02_regs;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ regs->creg |= MSTK_CREG_WRITE;
+
+ MSTK_SET_REG_SEC(regs,t->sec);
+ MSTK_SET_REG_MIN(regs,t->min);
+ MSTK_SET_REG_HOUR(regs,t->hour);
+ MSTK_SET_REG_DOW(regs,t->dow);
+ MSTK_SET_REG_DOM(regs,t->dom);
+ MSTK_SET_REG_MONTH(regs,t->month);
+ MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO);
+
+ regs->creg &= ~MSTK_CREG_WRITE;
+ restore_flags(flags);
+}
+
+static long long rtc_lseek(struct inode *inode, struct file *file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rtc_time rtc_tm;
+
+ switch (cmd)
+ {
+ case RTCGET:
+ get_rtc_time(&rtc_tm);
+
+ copy_to_user_ret((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time), -EFAULT);
+
+ return 0;
+
+
+ case RTCSET:
+ if (!suser())
+ return -EPERM;
+
+ copy_from_user_ret(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time), -EFAULT);
+
+ set_rtc_time(&rtc_tm);
+
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+ if (rtc_busy)
+ return -EBUSY;
+
+ rtc_busy = 1;
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+ rtc_busy = 0;
+ return 0;
+}
+
+static struct file_operations rtc_fops = {
+ rtc_lseek,
+ NULL, /* rtc_read */
+ NULL, /* rtc_write */
+ NULL, /* rtc_readdir */
+ NULL, /* rtc_poll */
+ rtc_ioctl,
+ NULL, /* rtc_mmap */
+ rtc_open,
+ rtc_release
+};
+
+static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int rtc_init(void))
+#endif
+{
+ int error;
+
+ error = misc_register(&rtc_dev);
+ if (error) {
+ printk(KERN_ERR "rtc: unable to get misc minor\n");
+ return error;
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ misc_deregister(&rtc_dev);
+}
+#endif
diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c
index 48adfd152..20b65c658 100644
--- a/drivers/sbus/char/suncons.c
+++ b/drivers/sbus/char/suncons.c
@@ -1,8 +1,13 @@
-/* suncons.c: Sun SparcStation console support.
+/* $Id: suncons.c,v 1.61 1997/04/17 02:29:36 miguel Exp $
+ *
+ * suncons.c: Sun SparcStation console support.
*
* Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su)
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*
* Added font loading Nov/21, Miguel de Icaza (miguel@nuclecu.unam.mx)
* Added render_screen and faster scrolling Nov/27, miguel
@@ -11,14 +16,23 @@
* Added cgsix and bwtwo drivers Jan/96, miguel
* Added 4m, and cg3 driver Feb/96, miguel
* Fixed the cursor on color displays Feb/96, miguel.
- *
* Cleaned up the detection code, generic 8bit depth display
- * code, Mar/96 miguel
+ * code, Mar/96 miguel
+ * Hacked support for cg14 video cards -- Apr/96, miguel.
+ * Color support for cg14 video cards -- May/96, miguel.
+ * Code split, Dave Redman, May/96
+ * Be more VT change friendly, May/96, miguel.
+ * Support for hw cursor and graphics acceleration, Jun/96, jj.
+ * Added TurboGX+ detection (cgthree+), Aug/96, Iain Lea (iain@sbs.de)
+ * Added TCX support (8/24bit), Aug/96, jj.
+ * Support for multiple framebuffers, Sep/96, jj.
+ * Fix bwtwo inversion and handle inverse monochrome cells in
+ * sun_blitc, Nov/96, ecd.
+ * Fix sun_blitc and screen size on displays other than 1152x900,
+ * 128x54 chars, Nov/96, jj.
+ * Fix cursor spots left on some non-accelerated fbs, changed
+ * software cursor to be like the hw one, Nov/96, jj.
*
- * This file contains the frame buffer device drivers.
- * Each driver is kept together in case we would like to
- * split this file.
- *
* Much of this driver is derived from the DEC TGA driver by
* Jay Estabrook who has done a nice job with the console
* driver abstraction btw.
@@ -29,23 +43,12 @@
* since not all Sparcs have the hardware to do it.
*
* TODO:
- * do not use minor to index into instances of the frame buffer,
- * since the numbers assigned to us are not consecutive.
- *
* do not blank the screen when frame buffer is mapped.
*
- * Change the detection loop to use more than one video card.
*/
-/* Define this one if you are debugging something in X, it will not disable the console output */
-/* #define DEBUGGING_X */
-/* See also: sparc/keyboard.c: CODING_NEW_DRIVER */
-
-#define GRAPHDEV_MAJOR 29
-
-#define FRAME_BUFFERS 1
-
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
@@ -59,9 +62,11 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/bitops.h>
@@ -69,7 +74,7 @@
#include <asm/sbus.h>
#include <asm/fbio.h>
#include <asm/io.h>
-#include <asm/pgtsun4c.h> /* for the sun4c_nocache */
+#include <asm/smp.h>
#include "../../char/kbd_kern.h"
#include "../../char/vt_kern.h"
@@ -77,51 +82,53 @@
#include "../../char/selection.h"
#include "../../char/console_struct.h"
+#include "fb.h"
+
#define cmapsz 8192
+#include "suncons_font.h"
+#include <asm/linux_logo.h>
+
+fbinfo_t *fbinfo;
+int fbinfos;
+
+#define ASM_BLITC
+
+int sun_hw_cursor_shown = 0;
+
+void sun_hw_hide_cursor(void);
+void sun_hw_set_cursor(int,int);
+
extern void register_console(void (*proc)(const char *));
extern void console_print(const char *);
+extern void putconsxy(int, char *);
extern unsigned char vga_font[];
-extern int graphics_on;
extern int serial_console;
-
-/* Based upon what the PROM tells us, we can figure out where
- * the console is currently located. The situation can be either
- * of the following two scenarios:
- *
- * 1) Console i/o is done over the serial line, ttya or ttyb
- * 2) Console output on frame buffer (video card) and input
- * coming from the keyboard/mouse which each use a zilog8530
- * serial channel a piece.
- */
+char *console_fb_path = NULL; /* Set in setup.c */
/* The following variables describe a Sparc console. */
-/* From the PROM */
-static char con_name[40];
-
/* Screen dimensions and color depth. */
static int con_depth, con_width, con_height, con_type;
-static int con_linebytes;
-
/* Base address of first line. */
static unsigned char *con_fb_base;
/* Screen parameters: we compute those at startup to make the code faster */
static int chars_per_line; /* number of bytes per line */
static int ints_per_line; /* number of ints per line */
-static int skip_bytes; /* number of bytes we skip for the y margin */
+static int ints_per_cursor; /* 14 * ints_per_line */
+static int skip_bytes; /* number of bytes we skip for the y margin + x_margin */
static int x_margin, y_margin; /* the x and y margins */
static int bytes_per_row; /* bytes used by one screen line (of 16 scan lines) */
+int sun_prom_console_id = 0;
/* Functions used by the SPARC dependent console code
- * to perform the restore_palette function.
+ * to perform the fb_restore_palette function.
*/
-static void (*restore_palette)(void);
+void (*fb_restore_palette)(fbinfo_t *fbinfo);
void set_palette (void);
-
/* Our screen looks like at 1152 X 900:
*
* 0,0
@@ -157,9 +164,66 @@ void set_palette (void);
((NICE_X_MARGIN) + (((cindex)&127))))
-#define COLOR_FBUF_OFFSET(cindex) \
- (((skip_bytes) + (((cindex)>>7) * bytes_per_row)) + \
- ((x_margin) + (((cindex)&127) << 3)))
+#define COLOR_FBUF_OFFSET(cindex) (*color_fbuf_offset)(cindex)
+
+/* These four routines are optimizations for the _generic routine for
+ * the most common cases.
+ * I guess doing twice sll is much faster than doing .mul, sra faster
+ * than doing .div, and the disadvantage that someone has to call it
+ * (it cannot be inline) runs away, 'cause otherwise it would have to
+ * call .mul anyway.
+ * The shifting + addition only routines won't eat any stack frame :))
+ * Names come from width, screen_num_columns.
+ */
+static int
+color_fbuf_offset_1280_144 (int cindex)
+{
+ register int i = (cindex/144);
+ /* (1280 * CHAR_HEIGHT) == 101.0000.0000.0000 */
+ return skip_bytes + (i << 14) + (i << 12) + ((cindex % 144) << 3);
+}
+
+static int
+color_fbuf_offset_1152_128 (int cindex)
+{
+ register int i = (cindex>>7);
+ /* (1152 * CHAR_HEIGHT) == 100.1000.0000.0000 */
+ return skip_bytes + (i << 14) + (i << 11) + ((cindex & 127) << 3);
+}
+
+static int
+color_fbuf_offset_1024_128 (int cindex)
+{
+ register int i = (cindex>>7);
+ /* (1024 * CHAR_HEIGHT) == 100.0000.0000.0000 */
+ return skip_bytes + (i << 14) + ((cindex & 127) << 3);
+}
+
+static int
+color_fbuf_offset_800_96 (int cindex)
+{
+ register int i = (cindex / 96);
+ /* (800 * CHAR_HEIGHT) == 11.0010.0000.0000 */
+ return skip_bytes + (i<<13) + (i<<12) + (i<<9) + ((cindex % 96)<<3);
+}
+
+static int
+color_fbuf_offset_640_80 (int cindex)
+{
+ register int i = (cindex/80);
+ /* (640 * CHAR_HEIGHT) == 10.1000.0000.0000 */
+ return skip_bytes + (i << 13) + (i << 11) + ((cindex % 80) << 3);
+}
+
+static int
+color_fbuf_offset_generic (int cindex)
+{
+ return skip_bytes + (cindex / video_num_columns) * bytes_per_row + ((cindex % video_num_columns) << 3);
+}
+
+static int (*color_fbuf_offset)(int) = color_fbuf_offset_generic;
+
+static int do_accel = 0;
void
__set_origin(unsigned short offset)
@@ -175,64 +239,55 @@ __set_origin(unsigned short offset)
* Hide the cursor from view, during blanking, usually...
*/
static int cursor_pos = -1;
+
+static unsigned int under_cursor[4];
+
void
hide_cursor(void)
{
unsigned long flags;
int j;
- save_flags(flags); cli();
+ if (fbinfo[0].setcursor) {
+ sun_hw_hide_cursor();
+ return;
+ }
+
+ if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+ return; /* Don't paint anything on fb which is not ours,
+ but turn off the hw cursor in such case */
+
+ __save_and_cli(flags);
if(cursor_pos == -1) {
- restore_flags (flags);
+ __restore_flags (flags);
return;
}
- /* We just zero out the area for now. Certain graphics
- * cards like the cg6 have a hardware cursor that we could
- * use, but this is an optimization for some time later.
- */
switch (con_depth){
case 1: {
unsigned char *dst;
dst = (unsigned char *)((unsigned long)con_fb_base +
FBUF_OFFSET(cursor_pos));
for(j = 0; j < CHAR_HEIGHT; j++, dst += CHARS_PER_LINE)
- *dst = ~(0);
+ *dst = ~(*dst);
break;
}
case 8: {
- unsigned long *dst;
- const int ipl = ints_per_line;
+ unsigned int *dst;
- dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(cursor_pos));
- for(j = 0; j < CHAR_HEIGHT; j++, dst += ipl) {
- *dst = ~(0UL);
- *(dst + 1) = ~(0UL);
- }
+ dst = (unsigned int *)((unsigned long)con_fb_base +
+ COLOR_FBUF_OFFSET(cursor_pos)) + ints_per_cursor;
+ dst[0] = under_cursor[0];
+ dst[1] = under_cursor[1];
+ dst[ints_per_line] = under_cursor[2];
+ dst[ints_per_line+1] = under_cursor[3];
break;
}
default:
break;
}
- restore_flags(flags);
-}
-
-/* The idea is the following:
- * we only use the colors in the range 0..15, and we only
- * setup the palette on that range, so we better keep the
- * pixel inversion using those colors, that's why we have
- * those constants below.
- */
-inline static void
-cursor_reverse (long *dst, int height, const int ints_on_line)
-{
- int j;
-
- for (j = 0; j < height; j++){
- *dst = ~(*dst) & 0x0f0f0f0f;
- *(dst+1) = ~(*(dst+1)) & 0x0f0f0f0f;
- dst += ints_on_line;
- }
+ cursor_pos = -1;
+ __restore_flags(flags);
}
void
@@ -244,19 +299,33 @@ set_cursor(int currcons)
if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
return;
+#if 0
+/* This is a nop anyway */
if (__real_origin != __origin)
__set_origin(__real_origin);
+#endif
+
+ if (fbinfo[0].setcursor) {
+ if (!deccm)
+ hide_cursor();
+ else {
+ idx = (pos - video_mem_base) >> 1;
+
+ sun_hw_set_cursor(x_margin + ((idx % video_num_columns) << 3), y_margin + ((idx / video_num_columns) * CHAR_HEIGHT));
+ }
+ return;
+ }
- save_flags(flags); cli();
+ __save_and_cli(flags);
idx = (pos - video_mem_base) >> 1;
oldpos = cursor_pos;
- cursor_pos = idx;
if (!deccm) {
hide_cursor ();
- restore_flags (flags);
+ __restore_flags (flags);
return;
}
+ cursor_pos = idx;
switch (con_depth){
case 1: {
unsigned char *dst, *opos;
@@ -275,25 +344,37 @@ set_cursor(int currcons)
break;
}
case 8: {
- unsigned long *dst, *opos;
- dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(idx));
- opos = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(oldpos));
+ unsigned int *dst, *opos;
+ dst = (unsigned int *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(idx)) + ints_per_cursor;
- if(oldpos != -1)
- cursor_reverse(opos, CHAR_HEIGHT, ints_per_line);
- cursor_reverse (dst, CHAR_HEIGHT, ints_per_line);
+ if(oldpos != -1) {
+ opos = (unsigned int *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(oldpos)) + ints_per_cursor;
+ opos[0] = under_cursor[0];
+ opos[1] = under_cursor[1];
+ opos[ints_per_line] = under_cursor[2];
+ opos[ints_per_line+1] = under_cursor[3];
+ }
+ under_cursor[0] = dst[0];
+ under_cursor[1] = dst[1];
+ under_cursor[2] = dst[ints_per_line];
+ under_cursor[3] = dst[ints_per_line+1];
+ dst[0] = 0x00000000;
+ dst[1] = 0x00000000;
+ dst[ints_per_line] = 0x00000000;
+ dst[ints_per_line+1] = 0x00000000;
break;
}
default:
}
- restore_flags(flags);
+ __restore_flags(flags);
}
/*
* Render the current screen
- * Only used at startup to avoid the caching that is being done in selection.h
+ * Only used at startup and when switching from KD_GRAPHICS to KD_TEXT
+ * to avoid the caching that is being done in selection.h
*/
-static void
+void
render_screen(void)
{
int count;
@@ -301,13 +382,71 @@ render_screen(void)
count = video_num_columns * video_num_lines;
contents = (unsigned short *) video_mem_base;
-
+
for (;count--; contents++)
sun_blitc (*contents, (unsigned long) contents);
}
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+__initfunc(void serial_finish_init(void (*printfunc)(const char *)))
+{
+ char buffer[2048];
+
+ sprintf (buffer, linux_serial_image, UTS_RELEASE);
+ (*printfunc)(buffer);
+}
+
+__initfunc(void con_type_init_finish(void))
+{
+ int i, cpu;
+ char *p = con_fb_base + skip_bytes;
+ char q[2] = {0,5};
+ int currcons = 0;
+ unsigned short *ush;
+
+ if (serial_console)
+ return;
+ if (con_type == FBTYPE_SUNLEO) {
+ int rects [4];
+
+ rects [0] = 0;
+ rects [1] = 0;
+ rects [2] = con_width;
+ rects [3] = con_height;
+ (*fbinfo[0].fill)(reverse_color_table[0], 1, rects);
+ return; /* Dunno how to display logo on leo/zx yet */
+ }
+ if (con_depth == 8 && fbinfo[0].loadcmap) {
+ for (i = 0; i < LINUX_LOGO_COLORS; i++) {
+ fbinfo[0].color_map CM(i+32,0) = linux_logo_red [i];
+ fbinfo[0].color_map CM(i+32,1) = linux_logo_green [i];
+ fbinfo[0].color_map CM(i+32,2) = linux_logo_blue [i];
+ }
+ (*fbinfo [0].loadcmap)(&fbinfo [0], 0, LINUX_LOGO_COLORS + 32);
+ for (i = 0; i < 80; i++, p += chars_per_line){
+ for (cpu = 0; cpu < linux_num_cpus; cpu++){
+ memcpy (p + (cpu * 88), linux_logo + 80 * i, 80);
+ }
+ }
+ } else if (con_depth == 1) {
+ for (i = 0; i < 80; i++, p += chars_per_line)
+ memcpy (p, linux_logo_bw + 10 * i, 10);
+ }
+ putconsxy(0, q);
+ ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20 + 11 * (linux_num_cpus - 1);
+
+ p = linux_logo_banner;
+ for (; *p; p++, ush++) {
+ *ush = (attr << 8) + *p;
+ sun_blitc (*ush, (unsigned long) ush);
+ }
+ for (i = 0; i < 5; i++) {
+ ush = (unsigned short *) video_mem_base + i * video_num_columns;
+ memset (ush, 0, 20);
+ }
+}
+
+__initfunc(unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc))
{
can_do_color = (con_type != FBTYPE_SUN2BW);
@@ -315,7 +454,7 @@ con_type_init(unsigned long kmem_start, const char **display_desc)
*display_desc = "SUN";
if (!serial_console) {
- /* If we fall back to PROM than our output have to remain readable. */
+ /* If we fall back to PROM then our output have to remain readable. */
prom_putchar('\033'); prom_putchar('['); prom_putchar('H');
/*
@@ -324,8 +463,6 @@ con_type_init(unsigned long kmem_start, const char **display_desc)
video_mem_base = kmem_start;
kmem_start += video_screen_size;
video_mem_term = kmem_start;
-
- render_screen();
}
return kmem_start;
}
@@ -364,31 +501,37 @@ set_scrmem(int currcons, long offset)
int
set_get_font(char * arg, int set, int ch512)
{
- int error, i, line;
+ int i, line;
if (!arg)
return -EINVAL;
- error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg,
- ch512 ? 2* cmapsz : cmapsz);
- if (error)
- return error;
/* download the current font */
if (!set){
- memset (arg, 0, cmapsz);
- for (i = 0; i < 256; i++)
- for (line = 0; line < CHAR_HEIGHT; line++)
- put_user (vga_font [i], arg+(i*32+line));
+ if(clear_user(arg, cmapsz))
+ return -EFAULT;
+ for (i = 0; i < 256; i++) {
+ for (line = 0; line < CHAR_HEIGHT; line++) {
+ unsigned char value = vga_font[i];
+
+ /* Access checked by the above clear_user */
+ __put_user_ret (value, (arg + (i * 32 + line)),
+ -EFAULT);
+ }
+ }
return 0;
}
/* set the font */
- for (i = 0; i < 256; i++)
+
+ if (verify_area (VERIFY_READ, arg, 256 * CHAR_HEIGHT)) return -EFAULT;
+ for (i = 0; i < 256; i++) {
for (line = 0; line < CHAR_HEIGHT; line++){
- vga_font [i*CHAR_HEIGHT + line] = (get_user (arg + (i * 32 + line)));
- if (con_depth == 1)
- vga_font [i*CHAR_HEIGHT + line] = vga_font [i*CHAR_HEIGHT + line];
+ unsigned char value;
+ __get_user_ret(value, (arg + (i * 32 + line)),-EFAULT);
+ vga_font [i*CHAR_HEIGHT + line] = value;
}
+ }
return 0;
}
@@ -411,20 +554,23 @@ set_get_cmap(unsigned char * arg, int set)
{
int i;
- i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
- if (i)
- return i;
-
+ if(set)
+ i = VERIFY_READ;
+ else
+ i = VERIFY_WRITE;
+ if(verify_area(i, arg, (16 * 3 * sizeof(unsigned char))))
+ return -EFAULT;
for (i=0; i<16; i++) {
if (set) {
- default_red[i] = get_user(arg++) ;
- default_grn[i] = get_user(arg++) ;
- default_blu[i] = get_user(arg++) ;
+ __get_user_ret(default_red[i], (arg+0),-EFAULT);
+ __get_user_ret(default_grn[i], (arg+1),-EFAULT);
+ __get_user_ret(default_blu[i], (arg+2),-EFAULT);
} else {
- put_user (default_red[i], arg++) ;
- put_user (default_grn[i], arg++) ;
- put_user (default_blu[i], arg++) ;
+ __put_user_ret(default_red[i], (arg+0),-EFAULT);
+ __put_user_ret(default_grn[i], (arg+1),-EFAULT);
+ __put_user_ret(default_blu[i], (arg+2),-EFAULT);
}
+ arg += 3;
}
if (set) {
for (i=0; i<MAX_NR_CONSOLES; i++)
@@ -442,14 +588,99 @@ set_get_cmap(unsigned char * arg, int set)
return 0;
}
-
void
sun_clear_screen(void)
{
- memset (con_fb_base, (con_depth == 1 ? ~(0) : (0)),
- (con_depth * con_height * con_width) / 8);
+ if (fbinfo[0].fill) {
+ int rects [4];
+
+ rects [0] = 0;
+ rects [1] = 0;
+ rects [2] = con_width;
+ rects [3] = con_height;
+ (*fbinfo[0].fill)(reverse_color_table[0], 1, rects);
+ } else if (fbinfo[0].base && fbinfo[0].base_depth)
+ memset (con_fb_base,
+ (con_depth == 1) ? ~(0) : reverse_color_table[0],
+ (con_depth * con_height * con_width) / 8);
/* also clear out the "shadow" screen memory */
memset((char *)video_mem_base, 0, (video_mem_term - video_mem_base));
+ cursor_pos = -1;
+}
+
+void
+sun_clear_fb(int n)
+{
+ if (!n) sun_clear_screen ();
+#if 0
+/* This makes in some configurations serious problems.
+ * Who cares if other screens are cleared?
+ */
+ else if (fbinfo[n].fill) {
+ int rects [4];
+
+ rects [0] = 0;
+ rects [1] = 0;
+ rects [2] = fbinfo[n].type.fb_width;
+ rects [3] = fbinfo[n].type.fb_height;
+ (*fbinfo[n].fill)(reverse_color_table[0], 1, rects);
+ }
+#endif
+ else if (fbinfo[n].base && fbinfo[n].base_depth) {
+ memset((void *)fbinfo[n].base,
+ (fbinfo[n].base_depth == 1) ?
+ ~(0) : reverse_color_table[0],
+ (fbinfo[n].base_depth * fbinfo[n].type.fb_height
+ * fbinfo[n].type.fb_width) / 8);
+ }
+}
+
+void
+sun_clear_margin(void)
+{
+ int h, he, i;
+ unsigned char *p;
+
+ if (fbinfo[0].fill) {
+ int rects [16];
+
+ memset (rects, 0, sizeof (rects));
+ rects [2] = con_width;
+ rects [3] = y_margin;
+ rects [5] = y_margin;
+ rects [6] = x_margin;
+ rects [7] = con_height;
+ rects [8] = con_width - x_margin;
+ rects [9] = y_margin;
+ rects [10] = con_width;
+ rects [11] = con_height;
+ rects [12] = x_margin;
+ rects [13] = con_height - y_margin;
+ rects [14] = con_width - x_margin;
+ rects [15] = con_height;
+ (*fbinfo[0].fill)(reverse_color_table[0], 4, rects);
+ } else {
+ memset (con_fb_base,
+ (con_depth == 1) ? ~(0) : reverse_color_table[0],
+ skip_bytes - (x_margin<<1));
+ memset (con_fb_base + chars_per_line * con_height
+ - skip_bytes + (x_margin<<1),
+ (con_depth == 1) ? ~(0) : reverse_color_table[0],
+ skip_bytes - (x_margin<<1));
+ he = con_height - 2 * y_margin;
+ i = 2 * x_margin;
+ if (con_depth == 1) {
+ for (p = con_fb_base+skip_bytes-(x_margin<<1), h = 0;
+ h <= he; p += chars_per_line, h++)
+ memset (p, ~(0), i);
+ } else {
+ for (p = con_fb_base+skip_bytes-(x_margin<<1), h = 0;
+ h <= he; p += chars_per_line, h++)
+ memset (p, reverse_color_table[0], i);
+ }
+ }
+ if (fbinfo [0].switch_from_graph)
+ (*fbinfo [0].switch_from_graph)();
}
/*
@@ -459,9 +690,11 @@ sun_clear_screen(void)
void vesa_blank(void)
{
}
+
void vesa_unblank(void)
{
}
+
void set_vesa_blanking(const unsigned long arg)
{
}
@@ -470,242 +703,16 @@ void vesa_powerdown(void)
{
}
-#undef color
-/* cg6 cursor status, kernel tracked copy */
-struct cg6_cursor {
- short enable; /* cursor is enabled */
- struct fbcurpos cpos; /* position */
- struct fbcurpos chot; /* hot-spot */
- struct fbcurpos size; /* size of mask & image fields */
- int bits[2][32]; /* space for mask & image bits */
- char color [6]; /* cursor colors */
-};
-
-struct cg6_info {
- struct bt_regs *bt; /* color control */
- void *fbc;
- struct cg6_fhc *fhc;
- struct cg6_tec *tec;
- struct cg6_thc *thc;
- struct cg6_cursor cursor; /* cursor control */
- void *dhc;
-};
-
-struct bwtwo_info {
- struct bwtwo_regs *regs;
+/*
+ * We permutate the colors, so we match the PROM's idea of
+ * black and white.
+ */
+unsigned char reverse_color_table[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
};
-struct cg3_info {
- struct bt_regs *bt; /* brooktree (color) registers */
-};
-
-/* Array holding the information for the frame buffers */
-typedef struct {
- union {
- struct bwtwo_info bwtwo;
- struct cg3_info cg3;
- struct cg6_info cg6;
- } info; /* per frame information */
- int space; /* I/O space this card resides in */
- int blanked; /* true if video blanked */
- int open; /* is this fb open? */
- int mmaped; /* has this fb been mmapped? */
- int vtconsole; /* virtual console where it is opened */
- long base; /* frame buffer base */
- struct fbtype type; /* frame buffer type */
- int (*mmap)(struct inode *, struct file *, struct vm_area_struct *, long fb_base, void *);
- void (*loadcmap)(void *this, int index, int count);
- void (*blank)(void *this);
- void (*unblank)(void *this);
- int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long, void *);
-} fbinfo_t;
-
-static fbinfo_t fbinfo [FRAME_BUFFERS];
-
-/* We need to keep a copy of the color map to answer ioctl requests */
-static union {
- unsigned char map[256][3]; /* reasonable way to access */
- unsigned int raw[256*3/4]; /* hardware wants it like this */
-} color_map;
-
-#define FB_MMAP_VM_FLAGS (VM_SHM| VM_LOCKED)
-
-static int
-fb_open (struct inode * inode, struct file * file)
-{
- int minor = MINOR (inode->i_rdev);
-
- if (minor >= FRAME_BUFFERS)
- return -EBADF;
- if (fbinfo [minor].open)
- return -EBUSY;
- fbinfo [minor].open = 1;
- fbinfo [minor].mmaped = 0;
- return 0;
-}
-
-static int
-fb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- int minor = MINOR (inode->i_rdev);
- fbinfo_t *fb;
- struct fbcmap *cmap;
- int i;
-
- if (minor >= FRAME_BUFFERS)
- return -EBADF;
- fb = &fbinfo [minor];
-
- switch (cmd){
- case FBIOGTYPE: /* return frame buffer type */
- i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbtype));
- if (i) return i;
- *(struct fbtype *)arg = (fb->type);
- break;
- case FBIOGATTR:{
- struct fbgattr *fba = (struct fbgattr *) arg;
-
- i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
- if (i) return i;
- fba->real_type = fb->type.fb_type;
- fba->owner = 0;
- fba->fbtype = fb->type;
- fba->sattr.flags = 0;
- fba->sattr.emu_type = fb->type.fb_type;
- fba->sattr.dev_specific [0] = -1;
- fba->emu_types [0] = fb->type.fb_type;
- fba->emu_types [1] = -1;
- break;
- }
- case FBIOSVIDEO:
- i = verify_area(VERIFY_READ, (void *)arg, sizeof(int));
- if (i) return i;
-
- if (*(int *)arg){
- if (!fb->blanked || !fb->unblank)
- break;
- (*fb->unblank)(fb);
- fb->blanked = 0;
- } else {
- if (fb->blanked || !fb->blank)
- break;
- (*fb->blank)(fb);
- fb->blanked = 1;
- }
- break;
- case FBIOGVIDEO:
- i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (int));
- if (i) return i;
- *(int *) arg = fb->blanked;
- break;
- case FBIOPUTCMAP: { /* load color map entries */
- char *rp, *gp, *bp;
- int end, count;;
-
- if (!fb->loadcmap)
- return -EINVAL;
- i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
- if (i) return i;
- cmap = (struct fbcmap *) arg;
- count = cmap->count;
- if ((cmap->index < 0) || (cmap->index > 255))
- return -EINVAL;
- if (cmap->index + count > 256)
- count = 256 - cmap->index;
- i = verify_area (VERIFY_READ, rp = cmap->red, cmap->count);
- if (i) return i;
- i = verify_area (VERIFY_READ, gp = cmap->green, cmap->count);
- if (i) return i;
- i = verify_area (VERIFY_READ, bp = cmap->blue, cmap->count);
- if (i) return i;
-
- end = cmap->index + count;
- for (i = cmap->index; i < end; i++){
- color_map.map [i][0] = *rp++;
- color_map.map [i][1] = *gp++;
- color_map.map [i][2] = *bp++;
- }
- (*fb->loadcmap)(fb, cmap->index, count);
- break;
- }
-
- default:
- if (fb->ioctl){
- i = fb->ioctl (inode, file, cmd, arg, fb);
- if (i == -EINVAL)
- printk ("[[FBIO: %8.8x]]\n", cmd);
- return i;
- }
- printk ("[[FBIO: %8.8x]]\n", cmd);
- return -EINVAL;
- }
- return 0;
-}
-
-static void
-fb_close (struct inode * inode, struct file *filp)
-{
- int minor = MINOR(inode->i_rdev);
- struct fbcursor cursor;
-
- if (minor >= FRAME_BUFFERS)
- return;
- if (fbinfo [minor].open)
- fbinfo [minor].open = 0;
- vt_cons [fbinfo [minor].vtconsole]->vc_mode = KD_TEXT;
-
- /* Leaving graphics mode, turn off the cursor */
- graphics_on = 0;
- if (fbinfo [minor].mmaped)
- sun_clear_screen ();
- cursor.set = FB_CUR_SETCUR;
- cursor.enable = 0;
- fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor);
- set_palette ();
- render_screen ();
- return;
-}
-
-static int
-fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
-{
- int minor = MINOR (inode->i_rdev);
- fbinfo_t *fb;
-
- if (minor >= FRAME_BUFFERS)
- return -ENXIO;
- /* FIXME: the fg_console below should actually be the
- * console on which the invoking process is running
- */
- if (vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
- return -ENXIO;
- fbinfo [minor].vtconsole = fg_console;
- fb = &fbinfo [minor];
-
- if (fb->mmap){
- int v;
-
- v = (*fb->mmap)(inode, file, vma, fb->base, fb);
- if (v) return v;
- fbinfo [minor].mmaped = 1;
- vt_cons [fg_console]->vc_mode = KD_GRAPHICS;
- graphics_on = 1;
- return 0;
- } else
- return -ENXIO;
-}
-
-static struct file_operations graphdev_fops =
-{
- NULL, /* lseek */
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* select */
- fb_ioctl,
- fb_mmap,
- fb_open, /* open */
- fb_close, /* close */
+static unsigned char sparc_color_table[] = {
+ 15, 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11
};
/* Call the frame buffer routine for setting the palette */
@@ -720,518 +727,65 @@ set_palette (void)
/* First keep color_map with the palette colors */
for (i = 0; i < 16; i++){
- j = color_table [i];
- color_map.map [i][0] = default_red [j];
- color_map.map [i][1] = default_grn [j];
- color_map.map [i][2] = default_blu [j];
+ j = sparc_color_table [i];
+ fbinfo[0].color_map CM(i,0) = default_red [j];
+ fbinfo[0].color_map CM(i,1) = default_grn [j];
+ fbinfo[0].color_map CM(i,2) = default_blu [j];
}
(*fbinfo [0].loadcmap)(&fbinfo [0], 0, 16);
}
}
-/* Called when returning to prom */
void
-console_restore_palette (void)
-{
- if (restore_palette)
- (*restore_palette) ();
-}
-
-/* This routine should be moved to srmmu.c */
-static __inline__ unsigned int
-srmmu_get_pte (unsigned long addr)
-{
- register unsigned long entry;
-
- __asm__ __volatile__("\n\tlda [%1] %2,%0\n\t" :
- "=r" (entry):
- "r" ((addr & 0xfffff000) | 0x400), "i" (ASI_M_FLUSH_PROBE));
- return entry;
-}
-
-unsigned int
-get_phys (unsigned int addr)
-{
- switch (sparc_cpu_model){
- case sun4c:
- return sun4c_get_pte (addr) << PAGE_SHIFT;
- case sun4m:
- return ((srmmu_get_pte (addr) & 0xffffff00) << 4);
- default:
- panic ("get_phys called for unsupported cpu model\n");
- return 0;
- }
-}
-
-/* CG6 support code */
-
-/* Offset of interesting structures in the OBIO space */
-/*
- * Brooktree is the video dac and is funny to program on the cg6.
- * (it's even funnier on the cg3)
- * The FBC could be the the frame buffer control
- * The FHC could be the frame buffer hardware control.
- */
-#define CG6_ROM_OFFSET 0x0
-#define CG6_BROOKTREE_OFFSET 0x200000
-#define CG6_DHC_OFFSET 0x240000
-#define CG6_ALT_OFFSET 0x280000
-#define CG6_FHC_OFFSET 0x300000
-#define CG6_THC_OFFSET 0x301000
-#define CG6_FBC_OFFSET 0x700000
-#define CG6_TEC_OFFSET 0x701000
-#define CG6_RAM_OFFSET 0x800000
-
-struct bt_regs {
- unsigned int addr; /* address register */
- unsigned int color_map; /* color map */
- unsigned int control; /* control register */
- unsigned int cursor; /* cursor map register */
-};
-
-/* The contents are unknown */
-struct cg6_tec {
- int tec_matrix;
- int tec_clip;
- int tec_vdc;
-};
-
-struct cg6_thc {
- unsigned int thc_xxx0[512]; /* ??? */
- unsigned int thc_hsync1; /* hsync timing */
- unsigned int thc_hsync2;
- unsigned int thc_hsync3;
- unsigned int thc_vsync1; /* vsync timing */
- unsigned int thc_vsync2;
- unsigned int thc_refresh;
- unsigned int thc_misc;
- unsigned int thc_xxx1[56];
- unsigned int thc_cursxy; /* cursor x,y position (16 bits each) */
- unsigned int thc_cursmask[32]; /* cursor mask bits */
- unsigned int thc_cursbits[32]; /* what to show where mask enabled */
-};
-
-static void
-cg6_restore_palette (void)
-{
- volatile struct bt_regs *bt;
-
- bt = fbinfo [0].info.cg6.bt;
- bt->addr = 0;
- bt->color_map = 0xffffffff;
- bt->color_map = 0xffffffff;
- bt->color_map = 0xffffffff;
-}
-
-/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
-/* So, we just mmap the things that are being asked for */
-static int
-cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
- unsigned int size, page, r, map_size;
- unsigned int map_offset = 0;
- fbinfo_t *fb = (fbinfo_t *) xx;
-
- size = vma->vm_end - vma->vm_start;
- if (vma->vm_offset & ~PAGE_MASK)
- return -ENXIO;
-
- /* To stop the swapper from even considering these pages */
- vma->vm_flags |= FB_MMAP_VM_FLAGS;
-
- /* Each page, see which map applies */
- for (page = 0; page < size; ){
- switch (vma->vm_offset+page){
- case CG6_TEC:
- map_size = PAGE_SIZE;
- map_offset = get_phys ((uint)fb->info.cg6.tec);
- break;
- case CG6_FBC:
- map_size = PAGE_SIZE;
- map_offset = get_phys ((uint)fb->info.cg6.fbc);
- break;
- case CG6_FHC:
- map_size = PAGE_SIZE;
- map_offset = get_phys ((uint)fb->info.cg6.fhc);
- break;
- case CG6_THC:
- map_size = PAGE_SIZE;
- map_offset = get_phys ((uint)fb->info.cg6.thc);
- break;
- case CG6_BTREGS:
- map_size = PAGE_SIZE;
- map_offset = get_phys ((uint)fb->info.cg6.bt);
- break;
-
- case CG6_DHC:
- map_size = PAGE_SIZE * 40;
- map_offset = get_phys ((uint)fb->info.cg6.dhc);
- break;
-
- case CG6_ROM:
- map_size = 0;
- break;
-
- case CG6_RAM:
- map_size = size-page;
- map_offset = get_phys ((uint) con_fb_base);
- if (map_size < fb->type.fb_size)
- map_size = fb->type.fb_size;
- break;
- default:
- map_size = 0;
- break;
- }
- if (!map_size){
- page += PAGE_SIZE;
- continue;
- }
- r = io_remap_page_range (vma->vm_start+page,
- map_offset,
- map_size, vma->vm_page_prot,
- fb->space);
- if (r) return -EAGAIN;
- page += map_size;
- }
- vma->vm_inode = inode;
- inode->i_count++;
- return 0;
-}
-
-#define BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2)) /* (x / 4) * 3 */
-#define BT_D4M4(x) ((x) & ~3) /* (x / 4) * 4 */
-
-static void
-cg6_loadcmap (void *fbinfo, int index, int count)
-{
- fbinfo_t *fb = (fbinfo_t *) fbinfo;
- struct bt_regs *bt = fb->info.cg6.bt;
- int i;
-
- bt->addr = index << 24;
- for (i = index; count--; i++){
- bt->color_map = color_map.map [i][0] << 24;
- bt->color_map = color_map.map [i][1] << 24;
- bt->color_map = color_map.map [i][2] << 24;
- }
-}
-
-/* Load cursor information */
-static void
-cg6_setcursor (struct cg6_info *info)
-{
- unsigned int v;
- struct cg6_cursor *c = &info->cursor;
-
- if (c->enable){
- v = ((c->cpos.fbx - c->chot.fbx) << 16)
- |((c->cpos.fby - c->chot.fby) & 0xffff);
- } else {
- /* Magic constant to turn off the cursor */
- v = ((65536-32) << 16) | (65536-32);
- }
- info->thc->thc_cursxy = v;
-}
-
-#undef pos
-static int
-cg6_scursor (struct fbcursor *cursor, fbinfo_t *fb)
+set_other_palette (int n)
{
- int op = cursor->set;
- volatile struct cg6_thc *thc = fb->info.cg6.thc;
- struct cg6_cursor *cursor_info = &fb->info.cg6.cursor;
- int i, bytes = 0;
-
- if (op & FB_CUR_SETSHAPE){
- if ((unsigned int) cursor->size.fbx > 32)
- return -EINVAL;
- if ((unsigned int) cursor->size.fby > 32)
- return -EINVAL;
- bytes = (cursor->size.fby * 32)/8;
- i = verify_area (VERIFY_READ, cursor->image, bytes);
- if (i) return i;
- i = verify_area (VERIFY_READ, cursor->mask, bytes);
- if (i) return i;
- }
- if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
- if (op & FB_CUR_SETCUR)
- cursor_info->enable = cursor->enable;
- if (op & FB_CUR_SETPOS)
- cursor_info->cpos = cursor->pos;
- if (op & FB_CUR_SETHOT)
- cursor_info->chot = cursor->hot;
- cg6_setcursor (&fb->info.cg6);
+ if (!n) {
+ set_palette ();
+ return;
}
- if (op & FB_CUR_SETSHAPE){
- unsigned int u;
-
- cursor_info->size = cursor->size;
- memset ((void *)&cursor_info->bits, 0, sizeof (cursor_info->size));
- memcpy (cursor_info->bits [0], cursor->mask, bytes);
- memcpy (cursor_info->bits [1], cursor->image, bytes);
- u = ~0;
- if (cursor_info->size.fbx < 32)
- u = ~(u >> cursor_info->size.fbx);
- for (i = 0; i < 32; i++){
- int m = cursor_info->bits [0][i] & u;
- thc->thc_cursmask [i] = m;
- thc->thc_cursbits [i] = m & cursor_info->bits [1][i];
- }
+ if (fbinfo [n].loadcmap){
+ fbinfo[n].color_map CM(0,0) = 0;
+ fbinfo[n].color_map CM(0,1) = 0;
+ fbinfo[n].color_map CM(0,2) = 0;
+ (*fbinfo [n].loadcmap)(&fbinfo [n], 0, 1);
}
- return 0;
-}
-
-/* Handle cg6-specific ioctls */
-static int
-cg6_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
-{
- int i;
-
- switch (cmd){
- case FBIOGCURMAX:
- i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbcurpos));
- if (i) return i;
- ((struct fbcurpos *) arg)->fbx = 32;
- ((struct fbcurpos *) arg)->fby = 32;
- break;
-
- case FBIOSVIDEO:
- /* vesa_blank and vesa_unblank could do the job on fb [0] */
- break;
-
- case FBIOSCURSOR:
- return cg6_scursor ((struct fbcursor *) arg, fb);
-
- case FBIOSCURPOS:
- /*
- i= verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcurpos));
- if (i) return i;
- */
- fb->info.cg6.cursor.cpos = *(struct fbcurpos *)arg;
- cg6_setcursor (&fb->info.cg6);
- break;
- default:
- return -EINVAL;
- }
- return 0;
}
-static void
-cg6_setup (int slot, unsigned int cg6, int cg6_io)
+/* Called when returning to prom */
+void
+console_restore_palette (void)
{
- struct cg6_info *cg6info;
-
- printk ("cgsix%d at 0x%8.8x\n", slot, (unsigned int) cg6);
-
- /* Fill in parameters we left out */
- fbinfo [slot].type.fb_cmsize = 256;
- fbinfo [slot].mmap = cg6_mmap;
- fbinfo [slot].loadcmap = cg6_loadcmap;
- fbinfo [slot].ioctl = (void *) cg6_ioctl;
- fbinfo [slot].blank = 0;
- fbinfo [slot].unblank = 0;
-
- cg6info = (struct cg6_info *) &fbinfo [slot].info.cg6;
-
- /* Map the hardware registers */
- cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0,
- sizeof (struct bt_regs),"cgsix_dac", cg6_io, 0);
- cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0,
- sizeof (int), "cgsix_fhc", cg6_io, 0);
- cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0,
- sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
- cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0,
- sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
- cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0,
- 0x40000, "cgsix_dhc", cg6_io, 0);
- cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0,
- 0x1000, "cgsix_fbc", cg6_io, 0);
- if (!con_fb_base){
- con_fb_base = sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0,
- fbinfo [slot].type.fb_size, "cgsix_ram", cg6_io, 0);
- }
- if (!slot)
- restore_palette = cg6_restore_palette;
+ if (fb_restore_palette)
+ (*fb_restore_palette) (&fbinfo[0]);
}
-/* The cg3 driver, obio space addresses for mapping the cg3 stuff */
-#define CG3_REGS 0x400000
-#define CG3_RAM 0x800000
-#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
-#define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
-
-/* The cg3 palette is loaded with 4 color values at each time */
-/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
-static void
-cg3_loadcmap (void *fbinfo, int index, int count)
+unsigned int
+get_phys (unsigned long addr)
{
- fbinfo_t *fb = (fbinfo_t *) fbinfo;
- struct bt_regs *bt = fb->info.cg3.bt;
- int *i, steps;
-
- i = &color_map.raw [D4M3(index)];
- steps = D4M3(index+count-1) - D4M3(index)+3;
- bt->addr = D4M4(index);
- while (steps--)
- bt->color_map = *i++;
+ return __get_phys(addr);
}
-/* The cg3 is presumed to emulate a cg4, I guess older programs will want that */
-/* addresses above 0x4000000 are for cg3, below that it's cg4 emulation */
-static int
-cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
+int
+get_iospace (unsigned long addr)
{
- unsigned int size, page, r, map_size;
- unsigned int map_offset = 0;
- fbinfo_t *fb = (fbinfo_t *) xx;
-
- size = vma->vm_end - vma->vm_start;
- if (vma->vm_offset & ~PAGE_MASK)
- return -ENXIO;
-
- /* To stop the swapper from even considering these pages */
- vma->vm_flags |= FB_MMAP_VM_FLAGS;
-
- /* Each page, see which map applies */
- for (page = 0; page < size; ){
- switch (vma->vm_offset+page){
- case CG3_MMAP_OFFSET:
- map_size = size-page;
- map_offset = get_phys ((uint) con_fb_base);
- if (map_size > fb->type.fb_size)
- map_size = fb->type.fb_size;
- break;
- default:
- map_size = 0;
- break;
- }
- if (!map_size){
- page += PAGE_SIZE;
- continue;
- }
- r = io_remap_page_range (vma->vm_start+page,
- map_offset,
- map_size, vma->vm_page_prot,
- fb->space);
- if (r) return -EAGAIN;
- page += map_size;
- }
- vma->vm_inode = inode;
- inode->i_count++;
- return 0;
+ return __get_iospace(addr);
}
-static void
-cg3_setup (int slot, unsigned int cg3, int cg3_io)
+__initfunc(unsigned long sun_cg_postsetup(fbinfo_t *fb, unsigned long start_mem))
{
- struct cg3_info *cg3info;
-
- printk ("cgthree%d at 0x%8.8x\n", slot, cg3);
-
- /* Fill in parameters we left out */
- fbinfo [slot].type.fb_cmsize = 256;
- fbinfo [slot].mmap = cg3_mmap;
- fbinfo [slot].loadcmap = cg3_loadcmap;
- fbinfo [slot].ioctl = 0; /* no special ioctls */
-
- cg3info = (struct cg3_info *) &fbinfo [slot].info.cg3;
-
- /* Map the card registers */
- cg3info->bt = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
- sizeof (struct bt_regs),"cg3_bt", cg3_io, 0);
-
- if (!con_fb_base){
- con_fb_base=sparc_alloc_io ((void*) cg3+CG3_RAM, 0,
- fbinfo [slot].type.fb_size, "cg3_ram", cg3_io, 0);
- }
+ fb->color_map = (char *)start_mem;
+ return start_mem + 256*3;
}
-/* OBio addresses for the bwtwo registers */
-#define BWTWO_REGISTER_OFFSET 0x400000
-
-struct bwtwo_regs {
- char unknown [16];
-#define BWTWO_ENABLE_VIDEO 0x40
- unsigned char control;
- char unknown2 [15];
+static char *known_cards [] __initdata = {
+ "cgsix", "cgthree", "cgRDI", "cgthree+", "bwtwo", "SUNW,tcx",
+ "cgfourteen", "SUNW,leo", "SUNW,ffb", 0
};
-
-static int
-bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
- unsigned int size, map_offset, r;
- fbinfo_t *fb = (fbinfo_t *) xx;
- int map_size;
-
- map_size = size = vma->vm_end - vma->vm_start;
-
- if (vma->vm_offset & ~PAGE_MASK)
- return -ENXIO;
-
- /* To stop the swapper from even considering these pages */
- vma->vm_flags |= FB_MMAP_VM_FLAGS;
- printk ("base=%8.8xl start=%8.8xl size=%x offset=%8.8x\n",
- (unsigned int) base,
- (unsigned int) vma->vm_start, size,
- (unsigned int) vma->vm_offset);
-
- /* This routine should also map the register if asked for, but we don't do that yet */
- map_offset = get_phys ((uint) con_fb_base);
- r = io_remap_page_range (vma->vm_start, map_offset, map_size, vma->vm_page_prot,
- fb->space);
- if (r) return -EAGAIN;
- vma->vm_inode = inode;
- inode->i_count++;
- return 0;
-}
-
-static void
-bwtwo_blank (void *xx)
-{
- fbinfo_t *fb = (fbinfo_t *) xx;
-
- fb->info.bwtwo.regs->control &= ~BWTWO_ENABLE_VIDEO;
-}
-
-static void
-bwtwo_unblank (void *xx)
-{
- fbinfo_t *fb = (fbinfo_t *) xx;
- fb->info.bwtwo.regs->control |= BWTWO_ENABLE_VIDEO;
-}
-
-static void
-bwtwo_setup (int slot, unsigned int bwtwo, int bw2_io)
-{
- printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
- fbinfo [slot].type.fb_cmsize = 2;
- fbinfo [slot].mmap = bwtwo_mmap;
- fbinfo [slot].loadcmap = 0;
- fbinfo [slot].ioctl = 0;
- fbinfo [slot].blank = bwtwo_blank;
- fbinfo [slot].unblank = bwtwo_unblank;
- fbinfo [slot].info.bwtwo.regs = sparc_alloc_io ((void *) bwtwo+BWTWO_REGISTER_OFFSET,
- 0, sizeof (struct bwtwo_regs), "bwtwo_regs", bw2_io, 0);
-}
-
-static void
-cg14_setup (int slot, unsigned int cg14, int cg14_io)
-{
- printk ("cgfourteen%d at 0x%8.8x\n", slot, cg14);
- fbinfo [slot].type.fb_cmsize = 256;
- fbinfo [slot].mmap = 0;
- fbinfo [slot].loadcmap = 0;
- fbinfo [slot].ioctl = 0;
- fbinfo [slot].blank = 0;
- fbinfo [slot].unblank = 0;
-}
-
-static char *known_cards [] = {
- "cgsix", "cgthree", "bwtwo", "SUNW,tcx", "cgfourteen", 0
+static char *v0_known_cards [] __initdata = {
+ "cgsix", "cgthree", "cgRDI", "cgthree+", "bwtwo", 0
};
-static int
-known_card (char *name)
+__initfunc(static int known_card (char *name, char **known_cards))
{
int i;
@@ -1246,19 +800,20 @@ static struct {
int resx, resy;
int x_margin, y_margin;
} scr_def [] = {
- { 1, 1152, 900, 8, 18 },
+ { 8, 1280, 1024, 64, 80 },
+ { 8, 1152, 1024, 64, 80 },
{ 8, 1152, 900, 64, 18 },
- { 8, 1280, 1024, 96, 80 },
{ 8, 1024, 768, 0, 0 },
+ { 8, 800, 600, 16, 12 },
+ { 8, 640, 480, 0, 0 },
+ { 1, 1152, 900, 8, 18 },
{ 0 },
};
-static int
-cg14_present(void)
+__initfunc(static int cg14_present(void))
{
int root, n;
- prom_printf ("Looking for cg14\n");
root = prom_getchild (prom_root_node);
if ((n = prom_searchsiblings (root, "obio")) == 0)
return 0;
@@ -1266,21 +821,211 @@ cg14_present(void)
n = prom_getchild (n);
if ((n = prom_searchsiblings (n, "cgfourteen")) == 0)
return 0;
- prom_printf ("Cg14 found!\n");
return n;
}
-static int
-sparc_console_probe(void)
+__initfunc(static int creator_present (void))
+{
+ int root, n;
+
+ root = prom_getchild (prom_root_node);
+ if ((n = prom_searchsiblings (root, "SUNW,ffb")) == 0)
+ return 0;
+ return n;
+}
+
+__initfunc(static void
+ sparc_framebuffer_setup(int primary, int con_node,
+ int type, struct linux_sbus_device *sbdp,
+ uint base, unsigned long con_base, int prom_fb,
+ int parent_node))
{
- int propl, con_node, i;
- struct linux_sbus_device *sbdp;
- unsigned int fbbase = 0xb001b001;
- int fbiospace = 0;
- int cg14 = 0;
-
- /* XXX The detection code needs to support multiple video cards in one system */
- con_node = 0;
+ static int frame_buffers = 1;
+ int n, i;
+ int linebytes;
+ uint io = 0;
+ char *p;
+
+ if (primary)
+ n = 0;
+ else {
+ if (frame_buffers == FRAME_BUFFERS)
+ return; /* Silently ignore */
+ n = frame_buffers++;
+ }
+
+ if (prom_fb) sun_prom_console_id = n;
+
+ if (sbdp)
+ io = sbdp->reg_addrs [0].which_io;
+
+ /* Fill in common fb information */
+ fbinfo [n].type.fb_type = type;
+ fbinfo [n].real_type = type;
+ fbinfo [n].prom_node = con_node;
+ memset (&(fbinfo [n].emulations), 0xff, sizeof (fbinfo [n].emulations));
+ fbinfo [n].type.fb_height = prom_getintdefault(con_node, "height", 900);
+ fbinfo [n].type.fb_width = prom_getintdefault(con_node, "width", 1152);
+ fbinfo [n].type.fb_depth = (type == FBTYPE_SUN2BW) ? 1 : 8;
+ linebytes = prom_getint(con_node, "linebytes");
+ if (linebytes == -1) linebytes = fbinfo [n].type.fb_width;
+ fbinfo [n].type.fb_size = PAGE_ALIGN((linebytes) * (fbinfo [n].type.fb_height));
+ fbinfo [n].space = io;
+ fbinfo [n].blanked = 0;
+ if (con_base >= PAGE_OFFSET)
+ fbinfo [n].base = con_base;
+ else
+ fbinfo [n].base = 0;
+ fbinfo [n].cursor.hwsize.fbx = 32;
+ fbinfo [n].cursor.hwsize.fby = 32;
+ fbinfo [n].proc_entry.node = parent_node;
+ fbinfo [n].proc_entry.rdev = MKDEV(GRAPHDEV_MAJOR, n);
+ fbinfo [n].proc_entry.mode = S_IFCHR | S_IRUSR | S_IWUSR;
+ prom_getname (con_node, fbinfo [n].proc_entry.name, 32 - 3);
+ p = strchr (fbinfo [n].proc_entry.name, 0);
+ sprintf (p, ":%d", n);
+
+ /* Should be filled in for supported video cards */
+ fbinfo [n].mmap = 0;
+ fbinfo [n].loadcmap = 0;
+ fbinfo [n].ioctl = 0;
+ fbinfo [n].reset = 0;
+ fbinfo [n].blank = 0;
+ fbinfo [n].unblank = 0;
+ fbinfo [n].setcursor = 0;
+ fbinfo [n].base_depth = fbinfo [n].type.fb_depth;
+
+ /* Per card setup */
+ switch (fbinfo [n].type.fb_type){
+#ifdef SUN_FB_CGTHREE
+ case FBTYPE_SUN3COLOR:
+ cg3_setup (&fbinfo [n], n, base, io, sbdp);
+ break;
+#endif
+#ifdef SUN_FB_TCX
+ case FBTYPE_TCXCOLOR:
+ tcx_setup (&fbinfo [n], n, con_node, base, sbdp);
+ break;
+#endif
+#ifdef SUN_FB_CGSIX
+ case FBTYPE_SUNFAST_COLOR:
+ cg6_setup (&fbinfo [n], n, base, io);
+ break;
+#endif
+#ifdef SUN_FB_BWTWO
+ case FBTYPE_SUN2BW:
+ bwtwo_setup (&fbinfo [n], n, base, io, sbdp);
+ break;
+#endif
+#ifdef SUN_FB_CGFOURTEEN
+ case FBTYPE_MDICOLOR:
+ cg14_setup (&fbinfo [n], n, con_node, base, io);
+ break;
+#endif
+#ifdef SUN_FB_LEO
+ case FBTYPE_SUNLEO:
+ leo_setup (&fbinfo [n], n, base, io);
+ break;
+#endif
+#ifdef SUN_FB_CREATOR
+ case FBTYPE_CREATOR:
+ creator_setup (&fbinfo [n], n, con_node, base, io);
+ break;
+#endif
+ default:
+ fbinfo [n].type.fb_type = FBTYPE_NOTYPE;
+ return;
+ }
+
+ if (n)
+ return;
+
+ /* Code below here is just executed for the first frame buffer */
+ con_type = type;
+ con_height = fbinfo [n].type.fb_height;
+ con_width = fbinfo [n].type.fb_width;
+ con_depth = (type == FBTYPE_SUN2BW) ? 1 : 8;
+ for (i = 0; scr_def [i].depth; i++){
+ if ((scr_def [i].resx != con_width) ||
+ (scr_def [i].resy != con_height))
+ continue;
+ if (scr_def [i].depth != con_depth)
+ continue;
+ x_margin = scr_def [i].x_margin;
+ y_margin = scr_def [i].y_margin;
+ chars_per_line = (con_width * con_depth) / 8;
+ skip_bytes = chars_per_line * y_margin + x_margin;
+ ints_per_line = chars_per_line / 4;
+ ints_per_cursor = 14 * ints_per_line;
+ bytes_per_row = CHAR_HEIGHT * chars_per_line;
+ ORIG_VIDEO_COLS = con_width / 8 -
+ 2 * x_margin / con_depth;
+ ORIG_VIDEO_LINES = (con_height - 2 * y_margin) / 16;
+ switch (chars_per_line) {
+ case 1280:
+ if (ORIG_VIDEO_COLS == 144)
+ color_fbuf_offset =
+ color_fbuf_offset_1280_144;
+ break;
+ case 1152:
+ if (ORIG_VIDEO_COLS == 128)
+ color_fbuf_offset =
+ color_fbuf_offset_1152_128;
+ break;
+ case 1024:
+ if (ORIG_VIDEO_COLS == 128)
+ color_fbuf_offset =
+ color_fbuf_offset_1024_128;
+ break;
+ case 800:
+ if (ORIG_VIDEO_COLS == 96)
+ color_fbuf_offset =
+ color_fbuf_offset_800_96;
+ break;
+ case 640:
+ if (ORIG_VIDEO_COLS == 80)
+ color_fbuf_offset =
+ color_fbuf_offset_640_80;
+ break;
+ }
+ break;
+ }
+
+ if (!scr_def [i].depth){
+ x_margin = y_margin = 0;
+ prom_printf ("console: unknown video resolution %dx%d,"
+ " depth %d\n",
+ con_width, con_height, con_depth);
+ prom_halt ();
+ }
+
+ /* P3: I fear this strips 15inch 1024/768 PC-like
+ * monitors out. */
+ if ((linebytes*8) / con_depth != con_width) {
+ prom_printf("console: unusual video, linebytes=%d, "
+ "width=%d, height=%d depth=%d\n",
+ linebytes, con_width, con_height,
+ con_depth);
+ prom_halt ();
+ }
+}
+
+__initfunc(static int sparc_console_probe(void))
+{
+ int propl, con_node, default_node = 0, i;
+ char prop[16];
+ struct linux_sbus_device *sbdp, *sbdprom;
+ struct linux_sbus *sbus;
+ int creator = 0, cg14 = 0;
+ char prom_name[40];
+ int type, card_found = 0;
+ unsigned long con_base;
+ u32 tmp;
+ u32 prom_console_node = 0;
+
+ for (i = 0; i < FRAME_BUFFERS; i++)
+ fbinfo [i].type.fb_type = FBTYPE_NOTYPE;
+ sbdprom = 0;
switch(prom_vers) {
case PROM_V0:
/* V0 proms are at sun4c only. Can skip many checks. */
@@ -1290,206 +1035,203 @@ sparc_console_probe(void)
prom_halt();
}
for_each_sbusdev(sbdp, SBus_chain) {
- con_node = sbdp->prom_node;
-
/* If no "address" than it is not the PROM console. */
if(sbdp->num_vaddrs) {
- if(!strncmp(sbdp->prom_name, "cgsix", 5)) {
- con_type = FBTYPE_SUNFAST_COLOR;
- fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
- fbiospace = sbdp->reg_addrs[0].which_io;
- break;
- } else if(!strncmp(sbdp->prom_name, "cgthree", 7)) {
- con_type = FBTYPE_SUN3COLOR;
- fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
- fbiospace = sbdp->reg_addrs[0].which_io;
- break;
- } else if (!strncmp(sbdp->prom_name, "bwtwo", 5)) {
- con_type = FBTYPE_SUN2BW;
- fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
- fbiospace = sbdp->reg_addrs[0].which_io;
+ if(known_card(sbdp->prom_name, v0_known_cards)) {
+ sbdprom = sbdp;
+ strncpy(prom_name, sbdp->prom_name, sizeof (prom_name));
break;
}
}
}
- if(con_type == FBTYPE_NOTYPE) return -1;
- con_fb_base = (unsigned char *) sbdp->sbus_vaddrs[0];
- strncpy(con_name, sbdp->prom_name, sizeof (con_name));
+ if(!sbdprom) return -1;
+ for_each_sbusdev(sbdp, SBus_chain) {
+ con_node = sbdp->prom_node;
+
+ if(!strncmp(sbdp->prom_name, "cgsix", 5) ||
+ !strncmp(sbdp->prom_name, "cgthree+", 8)) {
+ type = FBTYPE_SUNFAST_COLOR;
+ } else if(!strncmp(sbdp->prom_name, "cgthree", 7) ||
+ !strncmp(sbdp->prom_name, "cgRDI", 5)) {
+ type = FBTYPE_SUN3COLOR;
+ } else if (!strncmp(sbdp->prom_name, "bwtwo", 5)) {
+ type = FBTYPE_SUN2BW;
+ } else
+ continue;
+ sparc_framebuffer_setup (sbdprom == sbdp, con_node, type, sbdp,
+ (uint)sbdp->reg_addrs [0].phys_addr, sbdp->sbus_vaddrs[0], 0,
+ sbdp->my_bus->prom_node);
+ /* XXX HACK */
+ if (sbdprom == sbdp && !strncmp(sbdp->prom_name, "cgRDI", 5))
+ break;
+ }
break;
case PROM_V2:
case PROM_V3:
case PROM_P1275:
- for_each_sbusdev(sbdp, SBus_chain) {
- prom_printf ("Trying: %s\n", sbdp->prom_name);
- if (known_card (sbdp->prom_name))
+ if (console_fb_path) {
+ char *q, c;
+
+ for (q = console_fb_path; *q && *q != ' '; q++);
+ c = *q;
+ *q = 0;
+ default_node = prom_pathtoinode(console_fb_path);
+ if (default_node) {
+ prom_printf ("Using %s for console\n", console_fb_path);
+ prom_console_node = prom_inst2pkg(prom_stdout);
+ if (prom_console_node == default_node)
+ prom_console_node = 0;
+ }
+ }
+ if (!default_node)
+ default_node = prom_inst2pkg(prom_stdout);
+ propl = prom_getproperty(default_node, "device_type",
+ prop, sizeof (prop));
+ if (propl < 0) {
+ prom_printf ("output-device doesn't have device_type property\n");
+ prom_halt ();
+ } else if (propl != sizeof("display") || strncmp("display", prop, sizeof("display"))) {
+ prop [propl] = 0;
+ prom_printf ("console_probe: output-device is %s"
+ " (not \"display\")\n", prop);
+ prom_halt ();
+ }
+ for_all_sbusdev(sbdp, sbus) {
+ if ((sbdp->prom_node == default_node)
+ && known_card (sbdp->prom_name, known_cards)) {
+ sbdprom = sbdp;
break;
+ }
}
- if (!sbdp){
- if (!(cg14 = cg14_present ())){
- prom_printf ("Could not find a known video card on this machine\n");
- prom_halt ();
- }
+ if (sbdprom)
+ card_found = 1;
+ if (!card_found)
+ card_found = cg14 = cg14_present ();
+ if (!card_found){
+ prom_printf ("Searching for a creator\n");
+ card_found = creator = creator_present ();
}
- if (!cg14){
- prom_apply_sbus_ranges (&sbdp->reg_addrs [0], sbdp->num_registers);
- fbbase = (long) sbdp->reg_addrs [0].phys_addr;
- fbiospace = sbdp->reg_addrs[0].which_io;
- con_node = (*romvec->pv_v2devops.v2_inst2pkg)
- (*romvec->pv_v2bootargs.fd_stdout);
- /*
- * Determine the type of hardware accelerator.
- */
- propl = prom_getproperty(con_node, "emulation", con_name, sizeof (con_name));
- if (propl < 0 || propl >= sizeof (con_name)) {
+ if (!card_found){
+ prom_printf ("Could not find a known video card on this machine\n");
+ prom_halt ();
+ }
+
+ for_all_sbusdev(sbdp, sbus) {
+ if (!known_card (sbdp->prom_name, known_cards))
+ continue;
+ con_node = sbdp->prom_node;
+ prom_apply_sbus_ranges (sbdp->my_bus, &sbdp->reg_addrs [0],
+ sbdp->num_registers, sbdp);
+
+ propl = prom_getproperty(con_node, "address", (char *) &tmp, 4);
+ con_base = tmp;
+ if (propl != 4) con_base = 0;
+ propl = prom_getproperty(con_node, "emulation", prom_name, sizeof (prom_name));
+ if (propl < 0 || propl >= sizeof (prom_name)) {
/* Early cg3s had no "emulation". */
- propl = prom_getproperty(con_node, "name", con_name, sizeof (con_name));
+ propl = prom_getproperty(con_node, "name", prom_name, sizeof (prom_name));
if (propl < 0) {
prom_printf("console: no device name!!\n");
return -1;
}
}
- if(!strncmp(con_name, "cgsix", sizeof (con_name))) {
- con_type = FBTYPE_SUNFAST_COLOR;
- } else if(!strncmp(con_name, "cgthree", sizeof (con_name))) {
- con_type = FBTYPE_SUN3COLOR;
- } else if(!strncmp(con_name, "cgfourteen", sizeof (con_name))) {
- con_type = FBTYPE_MDICOLOR;
- } else if(!strncmp(con_name, "bwtwo", sizeof (con_name))) {
- con_type = FBTYPE_SUN2BW;
- } else if(!strncmp(con_name,"SUNW,tcx", sizeof (con_name))){
- con_type = FBTYPE_SUN3COLOR;
+ prom_name [sizeof (prom_name) - 1] = 0;
+ if(!strcmp(prom_name, "cgsix") ||
+ !strcmp(prom_name, "cgthree+")) {
+ type = FBTYPE_SUNFAST_COLOR;
+ } else if(!strcmp(prom_name, "cgthree") ||
+ !strcmp(prom_name, "cgRDI")) {
+ type = FBTYPE_SUN3COLOR;
+ } else if(!strcmp(prom_name, "cgfourteen")) {
+ type = FBTYPE_MDICOLOR;
+ } else if(!strcmp(prom_name, "SUNW,leo")) {
+ type = FBTYPE_SUNLEO;
+ } else if(!strcmp(prom_name, "bwtwo")) {
+ type = FBTYPE_SUN2BW;
+ } else if(!strcmp(prom_name,"SUNW,tcx")){
+ sparc_framebuffer_setup (sbdprom == sbdp, con_node, FBTYPE_TCXCOLOR, sbdp,
+ (uint)sbdp->reg_addrs [10].phys_addr, con_base,
+ prom_console_node == con_node, sbdp->my_bus->prom_node);
+ continue;
} else {
- prom_printf("console: \"%s\" is unsupported\n", con_name);
- return -1;
- }
- propl = prom_getproperty(con_node, "address", (char *) &con_fb_base, 4);
- if (propl != 4) {
- con_fb_base = 0;
+ prom_printf("console: \"%s\" is unsupported\n", prom_name);
+ continue;
}
- } else {
- int bases [2];
-
- con_node = cg14;
- prom_printf ("Found a cg14\n");
- propl = prom_getproperty (cg14, "address",
- (char *) &bases[0], 8);
- prom_printf ("Size=%d, %x\n", propl, bases [1]);
- con_fb_base = (unsigned char *) bases [1];
- con_type = FBTYPE_MDICOLOR;
+ sparc_framebuffer_setup (sbdprom == sbdp, con_node, type, sbdp,
+ (uint)sbdp->reg_addrs [0].phys_addr, con_base,
+ prom_console_node == con_node, sbdp->my_bus->prom_node);
+ /* XXX HACK */
+ if (sbdprom == sbdp && !strncmp(sbdp->prom_name, "cgRDI", 5))
+ break;
+ }
+ if (cg14) {
+ sparc_framebuffer_setup (!sbdprom, cg14, FBTYPE_MDICOLOR,
+ 0, 0, 0, prom_console_node == cg14,
+ prom_searchsiblings (prom_getchild (prom_root_node), "obio"));
+ }
+ if (creator){
+ sparc_framebuffer_setup (!sbdprom, creator, FBTYPE_CREATOR,
+ 0, 0, 0, prom_console_node == creator,
+ prom_getchild (prom_root_node));
}
break;
default:
return -1;
- };
-
- /* Get the device geometry */
- con_linebytes = prom_getintdefault(con_node, "linebytes", 1152);
- con_width = prom_getintdefault(con_node, "width", 1152);
- con_height = prom_getintdefault(con_node, "height", 900);
-
- /* Currently we just support 1-bit and 8-bit depth displays */
- if (con_type == FBTYPE_SUN2BW) {
- con_depth = 1;
- } else {
- con_depth = 8;
- }
- for (i = 0; scr_def [i].depth; i++){
- if (scr_def [i].resx != con_width || scr_def [i].resy != con_height)
- continue;
- if (scr_def [i].depth != con_depth)
- continue;
- x_margin = scr_def [i].x_margin;
- y_margin = scr_def [i].y_margin;
- chars_per_line = (con_width * con_depth) / 8;
- skip_bytes = chars_per_line * y_margin;
- ints_per_line = chars_per_line / 4;
- bytes_per_row = CHAR_HEIGHT * chars_per_line;
- break;
}
- if (!scr_def [i].depth){
- x_margin = y_margin = 0;
- prom_printf ("PenguinCon: unknown video resolution %dx%d may be slow\n", con_width, con_height);
+
+ if (fbinfo [0].type.fb_type == FBTYPE_NOTYPE) {
+ prom_printf ("Couldn't setup your primary frame buffer.\n");
prom_halt ();
}
- /* P3: I fear this strips 15inch 1024/768 PC-like monitors out. */
- if ((con_linebytes*8) / con_depth != con_width) {
- prom_printf("console: UNUSUAL VIDEO, linebytes=%d, width=%d, depth=%d\n",
- con_linebytes, con_width, con_depth);
- return -1;
- }
-
- /* Negate the font table on 1 bit depth cards so we have white on black */
- if (con_depth == 1)
- for(i=0; i<(16 * 256); i++)
- vga_font[i] = ~vga_font[i];
-
- /* Fill in common fb information */
- fbinfo [0].type.fb_type = con_type;
- fbinfo [0].type.fb_height = con_height;
- fbinfo [0].type.fb_width = con_width;
- fbinfo [0].type.fb_depth = con_depth;
- fbinfo [0].type.fb_size = PAGE_ALIGN((con_linebytes) * (con_height));
- fbinfo [0].space = fbiospace;
- fbinfo [0].blanked = 0;
-
- /* Should be filled in for supported video cards */
- fbinfo [0].mmap = 0;
- fbinfo [0].loadcmap = 0;
- fbinfo [0].ioctl = 0;
- fbinfo [0].blank = 0;
- fbinfo [0].unblank = 0;
-
- if (fbbase == 0xb001b001){
- printk ("Mail miguel@nuclecu.unam.mx video_card=%d (%s)\n", con_type, con_name);
- }
- /* Per card setup */
- switch (con_type){
- case FBTYPE_SUN3COLOR:
- cg3_setup (0, fbbase, fbiospace);
- break;
- case FBTYPE_SUNFAST_COLOR:
- cg6_setup (0, fbbase, fbiospace);
- break;
- case FBTYPE_SUN2BW:
- bwtwo_setup (0, fbbase, fbiospace);
- break;
- case FBTYPE_MDICOLOR:
- cg14_setup (0, fbbase, fbiospace);
- break;
- default:
- break;
- }
+ if (fbinfo [0].blitc)
+ do_accel = 1;
+
+ con_fb_base = (unsigned char *)fbinfo[0].base;
if (!con_fb_base){
prom_printf ("PROM does not have an 'address' property for this\n"
"frame buffer and the Linux drivers do not know how\n"
"to map the video of this device\n");
prom_halt ();
}
- fbinfo [0].base = (long) con_fb_base;
-
- /* Register the frame buffer device */
- if (register_chrdev (GRAPHDEV_MAJOR, "graphics", &graphdev_fops)){
- printk ("Could not register graphics device\n");
- return -EIO;
- }
- return 0; /* success */
+ return fb_init ();
}
/* video init code, called from within the SBUS bus scanner at
* boot time.
*/
-void
-sun_console_init(void)
+__initfunc(unsigned long sun_console_init(unsigned long memory_start))
{
+ int i, j;
if(serial_console)
- return;
+ return memory_start;
+ fbinfo = (fbinfo_t *)memory_start;
+ memset (fbinfo, 0, FRAME_BUFFERS * sizeof (fbinfo_t));
if(sparc_console_probe()) {
prom_printf("Could not probe console, bailing out...\n");
prom_halt();
}
+
sun_clear_screen();
+ for (i = FRAME_BUFFERS; i > 1; i--)
+ if (fbinfo[i - 1].type.fb_type != FBTYPE_NOTYPE) break;
+ fbinfos = i;
+ memory_start = memory_start + i * sizeof (fbinfo_t);
+ for (j = 0; j < i; j++)
+ if (fbinfo[j].postsetup)
+ memory_start = (*fbinfo[j].postsetup)(fbinfo+j, memory_start);
+ for (j = 1; j < i; j++)
+ if (fbinfo[j].type.fb_type != FBTYPE_NOTYPE) {
+ sun_clear_fb(j);
+ set_other_palette(j);
+ }
+#if defined(CONFIG_PROC_FS) && ( defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) )
+ for (j = 0; j < i; j++)
+ if (fbinfo[j].type.fb_type != FBTYPE_NOTYPE)
+ proc_openprom_regdev (&fbinfo[j].proc_entry);
+#endif
+ return memory_start;
}
/*
@@ -1501,7 +1243,7 @@ sun_console_init(void)
* Called from scr_writew() when the destination is
* the "shadow" screen
*/
-static unsigned int
+static uint
fontmask_bits[16] = {
0x00000000,
0x000000ff,
@@ -1522,53 +1264,231 @@ fontmask_bits[16] = {
};
int
-sun_blitc(unsigned int charattr, unsigned long addr)
+sun_blitc(uint charattr, unsigned long addr)
{
+ unsigned int fgmask, bgmask;
+ unsigned char attrib;
int j, idx;
unsigned char *font_row;
-#ifndef DEBUGGING_X
- if (graphics_on)
+ if (do_accel) {
+ (*fbinfo[0].blitc)(charattr,
+ x_margin + (((addr - video_mem_base) % video_size_row)<<2),
+ y_margin + CHAR_HEIGHT * ((addr - video_mem_base) / video_size_row));
return 0;
-#endif
+ }
+
+ /* Invalidate the cursor position if necessary. */
idx = (addr - video_mem_base) >> 1;
- /* Invalidate the cursor position if necessary. */
- if(idx == cursor_pos)
- cursor_pos = -1;
- font_row = &vga_font[(charattr & 0xff) << 4];
+ attrib = CHARATTR_TO_SUNCOLOR(charattr);
+ font_row = &vga_font[(j = (charattr & 0xff)) << 4];
switch (con_depth){
case 1: {
register unsigned char *dst;
+ unsigned long flags;
dst = (unsigned char *)(((unsigned long)con_fb_base) + FBUF_OFFSET(idx));
- for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
- *dst = *font_row;
+
+ __save_and_cli(flags);
+ if ((!(charattr & 0xf000)) ^ (idx == cursor_pos)) {
+ for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
+ *dst = ~(*font_row);
+ } else {
+ for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
+ *dst = *font_row;
+ }
+ __restore_flags(flags);
break;
}
case 8: {
- register unsigned long *dst;
- unsigned long fgmask, bgmask, data, rowbits, attrib;
+#ifdef ASM_BLITC
+ const int cpl = chars_per_line;
+ /* The register assignment is important here, do not modify without touching the assembly code as well */
+ register unsigned int x1 __asm__("g4"), x2 __asm__("g5"), x3 __asm__("g2"), x4 __asm__("g3"), flags __asm__("g7");
+ register unsigned int *dst __asm__("g1");
+#else
const int ipl = ints_per_line;
+ unsigned int data2, data3, data4;
+ unsigned int data, rowbits;
+ register unsigned int *dst;
+ unsigned long flags;
+#endif
+ const uint *fontm_bits = fontmask_bits;
- dst = (unsigned long *)(((unsigned long)con_fb_base) + COLOR_FBUF_OFFSET(idx));
- attrib = (charattr >> 8) & 0x0ff;
- fgmask = attrib & 0x0f;
- bgmask = (attrib >> 4) & 0x0f;
- fgmask = fgmask << 8 | fgmask;
- fgmask |= fgmask << 16;
- bgmask = bgmask << 8 | bgmask;
- bgmask |= bgmask << 16;
-
- for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst += ipl) {
- rowbits = *font_row;
- data = fontmask_bits[(rowbits>>4)&0xf];
- data = (data & fgmask) | (~data & bgmask);
- *dst = data;
- data = fontmask_bits[rowbits&0xf];
- data = (data & fgmask) | (~data & bgmask);
- *(dst+1) = data;
+ dst = (unsigned int *)(((unsigned long)con_fb_base) + COLOR_FBUF_OFFSET(idx));
+ if (j == ' ') /* space is quite common, so we optimize a bit */ {
+#ifdef ASM_BLITC
+#define BLITC_SPACE \
+ "\n\t std %%g4, [%%g1]" \
+ "\n\t std %%g4, [%%g1 + %0]" \
+ "\n\t add %%g1, %1, %%g1"
+#define BLITC_SPC \
+ "\n\t std %0, [%1]" \
+ "\n\t std %0, [%1 + %2]"
+
+ x1 = attrib >> 4;
+ x1 |= x1 << 8;
+ x1 |= x1 << 16;
+ x3 = cpl << 1;
+
+ __asm__ __volatile__ (
+ "\n\t mov %2, %3"
+ BLITC_SPACE
+ BLITC_SPACE
+ BLITC_SPACE
+ BLITC_SPACE
+ BLITC_SPACE
+ BLITC_SPACE
+ BLITC_SPACE
+ : : "r" (cpl), "r" (x3), "r" (x1), "r" (x2));
+ __save_and_cli (flags);
+ if (idx != cursor_pos)
+ __asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (dst), "r" (cpl));
+ else
+ __asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (under_cursor), "i" (8));
+ __restore_flags (flags);
+#else
+ bgmask = attrib >> 4;
+ bgmask |= bgmask << 8;
+ bgmask |= bgmask << 16;
+
+ for(j = 0; j < CHAR_HEIGHT - 2; j++, font_row++, dst += ipl) {
+ *dst = bgmask;
+ *(dst+1) = bgmask;
+ }
+ /* Prevent cursor spots left on the screen */
+ __save_and_cli(flags);
+ if (idx != cursor_pos) {
+ *dst = bgmask;
+ *(dst+1) = bgmask;
+ dst += ipl;
+ *dst = bgmask;
+ *(dst+1) = bgmask;
+ } else {
+ under_cursor [0] = bgmask;
+ under_cursor [1] = bgmask;
+ under_cursor [2] = bgmask;
+ under_cursor [3] = bgmask;
+ }
+ __restore_flags(flags);
+#endif
+ } else /* non-space */ {
+ fgmask = attrib & 0x0f;
+ bgmask = attrib >> 4;
+ fgmask |= fgmask << 8;
+ fgmask |= fgmask << 16;
+ bgmask |= bgmask << 8;
+ bgmask |= bgmask << 16;
+
+#ifdef ASM_BLITC
+#define BLITC_INIT \
+ "\n\t ld [%0], %%g2"
+#define BLITC_BODY(ST1,SC1,ST2,SC2) \
+ "\n\t " #ST1 " %%g2, " #SC1 ", %%g7" \
+ "\n\t " #ST2 " %%g2, " #SC2 ", %7" \
+ "\n\t and %%g7, 0x3c, %%g7" \
+ "\n\t and %7, 0x3c, %7" \
+ "\n\t ld [%1 + %%g7], %6" \
+ "\n\t and %6, %2, %%g7" \
+ "\n\t andn %3, %6, %6" \
+ "\n\t or %%g7, %6, %6" \
+ "\n\t ld [%1 + %7], %7" \
+ "\n\t and %7, %2, %%g7" \
+ "\n\t andn %3, %7, %7" \
+ "\n\t or %%g7, %7, %7"
+#define BLITC_BODYEND \
+ "\n\t sll %3, 2, %%g7" \
+ "\n\t srl %3, 2, %3" \
+ "\n\t and %%g7, 0x3c, %%g7" \
+ "\n\t and %3, 0x3c, %3" \
+ "\n\t ld [%0 + %%g7], %4" \
+ "\n\t and %4, %1, %%g7" \
+ "\n\t andn %2, %4, %4" \
+ "\n\t or %%g7, %4, %4" \
+ "\n\t ld [%0 + %3], %3" \
+ "\n\t and %3, %1, %%g7" \
+ "\n\t andn %2, %3, %3" \
+ "\n\t or %%g7, %3, %3"
+#define BLITC_STOREIT \
+ "\n\t std %6, [%5]" \
+ "\n\t add %5, %4, %5" \
+ "\n\t"
+#define BLITC_STORE \
+ "\n\t std %%g4, [%0]" \
+ "\n\t std %%g2, [%0 + %1]"
+
+ for (j = 0; j < 3; j++, font_row+=4) {
+ __asm__ __volatile__ (BLITC_INIT
+ BLITC_BODY(srl, 26, srl, 22)
+ BLITC_STOREIT
+ BLITC_BODY(srl, 18, srl, 14)
+ BLITC_STOREIT
+ BLITC_BODY(srl, 10, srl, 6)
+ BLITC_STOREIT
+ BLITC_BODY(srl, 2, sll, 2)
+ BLITC_STOREIT
+ : : "r" (font_row), "r" (fontm_bits), "r" (fgmask), "r" (bgmask), "r" (cpl), "r" (dst),
+ "r" (x1), "r" (x2));
+ }
+ __asm__ __volatile__ (BLITC_INIT
+ BLITC_BODY(srl, 26, srl, 22)
+ BLITC_STOREIT
+ BLITC_BODY(srl, 18, srl, 14)
+ BLITC_STOREIT
+ /* Now prepare date for the 15th line, but don't put it anywhere yet (leave it in g4,g5) */
+ BLITC_BODY(srl, 10, srl, 6)
+ : : "r" (font_row), "r" (fontm_bits), "r" (fgmask), "r" (bgmask), "r" (cpl), "r" (dst),
+ "r" (x1), "r" (x2));
+ /* Prepare the data the bottom line (and put it into g2,g3) */
+ __asm__ __volatile__ (BLITC_BODYEND : : "r" (fontm_bits), "r" (fgmask), "r" (bgmask),
+ "r" (x3), "r" (x4));
+ __save_and_cli(flags);
+ if (idx != cursor_pos)
+ __asm__ __volatile__ (BLITC_STORE : : "r" (dst), "r" (cpl));
+ else
+ __asm__ __volatile__ (BLITC_STORE : : "r" (under_cursor), "i" (8));
+ __restore_flags (flags);
+#else
+ for(j = 0; j < CHAR_HEIGHT - 2; j++, font_row++, dst += ipl) {
+ rowbits = *font_row;
+ data = fontm_bits[(rowbits>>4)&0xf];
+ data = (data & fgmask) | (~data & bgmask);
+ *dst = data;
+ data = fontm_bits[rowbits&0xf];
+ data = (data & fgmask) | (~data & bgmask);
+ *(dst+1) = data;
+ }
+ rowbits = *font_row;
+ data = fontm_bits[(rowbits>>4)&0xf];
+ data = (data & fgmask) | (~data & bgmask);
+ data2 = fontm_bits[rowbits&0xf];
+ data2 = (data2 & fgmask) | (~data2 & bgmask);
+ rowbits = font_row[1];
+ data3 = fontm_bits[(rowbits>>4)&0xf];
+ data3 = (data3 & fgmask) | (~data3 & bgmask);
+ data4 = fontm_bits[rowbits&0xf];
+ data4 = (data4 & fgmask) | (~data4 & bgmask);
+
+ /* Prevent cursor spots left on the screen */
+ __save_and_cli(flags);
+
+ if (idx != cursor_pos) {
+ *dst = data;
+ *(dst+1) = data2;
+ dst += ipl;
+ *dst = data3;
+ *(dst+1) = data4;
+ } else {
+ under_cursor [0] = data;
+ under_cursor [1] = data2;
+ under_cursor [2] = data3;
+ under_cursor [3] = data4;
+ }
+
+ __restore_flags(flags);
+#endif
}
break;
} /* case */
@@ -1576,347 +1496,234 @@ sun_blitc(unsigned int charattr, unsigned long addr)
return (0);
}
-unsigned char vga_font[cmapsz] = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd,
-0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
-0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe,
-0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
-0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
-0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e,
-0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
-0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
-0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8,
-0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e,
-0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
-0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
-0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6,
-0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
-0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
-0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
-0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c,
-0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c,
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18,
-0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
-0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
-0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
-0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
-0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
-0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
-0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
-0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
-0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
-0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c,
-0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
-0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
-0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
-0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
-0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
-0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
-0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c,
-0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
-0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
-0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18,
-0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
-0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
-0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
-0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60,
-0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
-0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60,
-0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06,
-0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60,
-0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb,
-0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
-0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
-0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
-0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
-0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
-0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6,
-0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
-0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
-0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe,
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06,
-0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe,
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66,
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
-0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
-0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b,
-0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c,
-0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
-0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
-0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
-0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
-0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
-0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66,
-0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18,
-0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc,
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
-0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
-0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06,
-0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
-0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
-0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
-0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
-0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
-0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
-0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
-0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
-0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
-0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
-0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
-0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8,
-0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66,
-0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
-0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60,
-0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
-0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
-0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
-0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
-0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
-0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
+void memsetw(void * s, unsigned short c, unsigned int count)
+{
+ unsigned short * addr = (unsigned short *) s;
+
+ count /= 2;
+ if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
+ while (count) {
+ count--;
+ *addr++ = c;
+ }
+ return;
+ }
+ if ((unsigned long) addr + count > video_mem_term ||
+ (unsigned long) addr < video_mem_base) {
+ if ((unsigned long) addr + count <= video_mem_term ||
+ (unsigned long) addr > video_mem_base) {
+ while (count) {
+ count--;
+ *addr++ = c;
+ }
+ return;
+ } else {
+ while (count) {
+ count--;
+ scr_writew(c, addr++);
+ }
+ }
+#define GX_SETW (*fbinfo[0].setw)(x_margin + ((xoff - (addr - last)) << 3), y_margin + CHAR_HEIGHT * yoff, c, addr - last);
+ } else if (do_accel) {
+ int yoff = (addr - (unsigned short *)video_mem_base) / video_num_columns;
+ int xoff = (addr - (unsigned short *)video_mem_base) % video_num_columns;
+ unsigned short * last = addr;
+
+ while (count) {
+ count--;
+ if (*addr != c) {
+ if (xoff == video_num_columns) {
+ if (last != addr)
+ GX_SETW
+ xoff = 0;
+ yoff++;
+ last = addr;
+ }
+ *addr++ = c;
+ xoff++;
+ } else {
+ if (last != addr)
+ GX_SETW
+ if (xoff == video_num_columns) {
+ xoff = 0;
+ yoff++;
+ }
+ addr++;
+ xoff++;
+ last = addr;
+ }
+ }
+ if (last != addr)
+ GX_SETW
+ } else {
+ while (count) {
+ count--;
+ if (*addr != c) {
+ sun_blitc(c, (unsigned long)addr);
+ *addr++ = c;
+ } else
+ addr++;
+ }
+ }
+}
+
+void memcpyw(unsigned short *to, unsigned short *from, unsigned int count)
+{
+ if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
+ memcpy(to, from, count);
+ return;
+ }
+ if ((unsigned long) to + count > video_mem_term ||
+ (unsigned long) to < video_mem_base) {
+ if ((unsigned long) to + count <= video_mem_term ||
+ (unsigned long) to > video_mem_base)
+ memcpy(to, from, count);
+ else {
+ count /= 2;
+ while (count) {
+ count--;
+ scr_writew(scr_readw(from++), to++);
+ }
+ }
+#define GX_CPYW (*fbinfo[0].cpyw)(x_margin + ((xoff - (to - last)) << 3), y_margin + CHAR_HEIGHT * yoff, last, to - last);
+ } else if (do_accel) {
+ int yoff = (to - (unsigned short *)video_mem_base) / video_num_columns;
+ int xoff = (to - (unsigned short *)video_mem_base) % video_num_columns;
+ unsigned short * last = to;
+
+ count /= 2;
+ while (count) {
+ count--;
+ if (*to != *from) {
+ if (xoff == video_num_columns) {
+ if (last != to)
+ GX_CPYW
+ xoff = 0;
+ yoff++;
+ last = to;
+ } else if (last != to && (*last & 0xff00) != (*from & 0xff00)) {
+ GX_CPYW
+ last = to;
+ }
+ *to++ = *from++;
+ xoff++;
+ } else {
+ if (last != to)
+ GX_CPYW
+ if (xoff == video_num_columns) {
+ xoff = 0;
+ yoff++;
+ }
+ to++;
+ xoff++;
+ last = to;
+ from++;
+ }
+ }
+ if (last != to)
+ GX_CPYW
+ } else {
+ count /= 2;
+ while (count) {
+ count--;
+ if (*to != *from) {
+ sun_blitc(*from, (unsigned long)to);
+ *to++ = *from++;
+ } else {
+ from++;
+ to++;
+ }
+ }
+ }
+}
+
+#undef pos
+int
+sun_hw_scursor (struct fbcursor *cursor, fbinfo_t *fb)
+{
+ int op = cursor->set;
+ int i, bytes = 0;
+
+ if (op & FB_CUR_SETSHAPE){
+ if ((uint) cursor->size.fbx > fb->cursor.hwsize.fbx)
+ return -EINVAL;
+ if ((uint) cursor->size.fby > fb->cursor.hwsize.fby)
+ return -EINVAL;
+ bytes = (cursor->size.fby * 32)/8;
+ i = verify_area (VERIFY_READ, cursor->image, bytes);
+ if (i) return i;
+ i = verify_area (VERIFY_READ, cursor->mask, bytes);
+ if (i) return i;
+ }
+ if (op & FB_CUR_SETCMAP){
+ if (cursor->cmap.index && cursor->cmap.count != 2)
+ return -EINVAL;
+ i = verify_area (VERIFY_READ, cursor->cmap.red, 2);
+ if (i) return i;
+ i = verify_area (VERIFY_READ, cursor->cmap.green, 2);
+ if (i) return i;
+ i = verify_area (VERIFY_READ, cursor->cmap.blue, 2);
+ if (i) return i;
+ }
+ if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
+ if (op & FB_CUR_SETCUR)
+ fb->cursor.enable = cursor->enable;
+ if (op & FB_CUR_SETPOS)
+ fb->cursor.cpos = cursor->pos;
+ if (op & FB_CUR_SETHOT)
+ fb->cursor.chot = cursor->hot;
+ (*fb->setcursor) (fb);
+ }
+ if (op & FB_CUR_SETCMAP)
+ (*fb->setcursormap) (fb, cursor->cmap.red, cursor->cmap.green, cursor->cmap.blue);
+ if (op & FB_CUR_SETSHAPE){
+ uint u;
+
+ fb->cursor.size = cursor->size;
+ memset ((void *)&fb->cursor.bits, 0, sizeof (fb->cursor.bits));
+ memcpy (fb->cursor.bits [0], cursor->mask, bytes);
+ memcpy (fb->cursor.bits [1], cursor->image, bytes);
+ u = ~0;
+ if (cursor->size.fbx < fb->cursor.hwsize.fbx)
+ u = ~(u >> cursor->size.fbx);
+ for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
+ fb->cursor.bits [0][i] &= u;
+ fb->cursor.bits [1][i] &= fb->cursor.bits [0][i];
+ }
+ (*fb->setcurshape) (fb);
+ }
+ return 0;
+}
+
+static unsigned char hw_cursor_cmap[2] = { 0, 0xff };
+
+void
+sun_hw_hide_cursor (void)
+{
+ fbinfo[0].cursor.enable = 0;
+ (*fbinfo[0].setcursor)(&fbinfo[0]);
+ sun_hw_cursor_shown = 0;
+}
+
+void
+sun_hw_set_cursor (int xoff, int yoff)
+{
+ if (!sun_hw_cursor_shown) {
+ fbinfo[0].cursor.size.fbx = CHAR_WIDTH;
+ fbinfo[0].cursor.size.fby = CHAR_HEIGHT;
+ fbinfo[0].cursor.chot.fbx = 0;
+ fbinfo[0].cursor.chot.fby = 0;
+ fbinfo[0].cursor.enable = 1;
+ memset (fbinfo[0].cursor.bits, 0, sizeof (fbinfo[0].cursor.bits));
+ fbinfo[0].cursor.bits[0][CHAR_HEIGHT - 2] = 0xff000000;
+ fbinfo[0].cursor.bits[1][CHAR_HEIGHT - 2] = 0xff000000;
+ fbinfo[0].cursor.bits[0][CHAR_HEIGHT - 1] = 0xff000000;
+ fbinfo[0].cursor.bits[1][CHAR_HEIGHT - 1] = 0xff000000;
+ (*fbinfo[0].setcursormap) (&fbinfo[0], hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap);
+ (*fbinfo[0].setcurshape) (&fbinfo[0]);
+ sun_hw_cursor_shown = 1;
+ }
+ fbinfo[0].cursor.cpos.fbx = xoff;
+ fbinfo[0].cursor.cpos.fby = yoff;
+ (*fbinfo[0].setcursor)(&fbinfo[0]);
+}
diff --git a/drivers/sbus/char/suncons_font.h b/drivers/sbus/char/suncons_font.h
new file mode 100644
index 000000000..87a07b10d
--- /dev/null
+++ b/drivers/sbus/char/suncons_font.h
@@ -0,0 +1,258 @@
+unsigned char vga_font[cmapsz] = {
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x6c,0xfe,0xfe,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x18,0x3c,0x3c,0xe7,0xe7,0xe7,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x7e,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0xff,0xff,0xff,0xff,
+/* */ 0x00,0x00,0x1e,0x0e,0x1a,0x32,0x78,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3c,0x66,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3f,0x33,0x3f,0x30,0x30,0x30,0x30,0x70,0xf0,0xe0,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7f,0x63,0x7f,0x63,0x63,0x63,0x63,0x67,0xe7,0xe6,0xc0,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x18,0x18,0xdb,0x3c,0xe7,0x3c,0xdb,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfe,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x02,0x06,0x0e,0x1e,0x3e,0xfe,0x3e,0x1e,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7f,0xdb,0xdb,0xdb,0x7b,0x1b,0x1b,0x1b,0x1b,0x1b,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x7c,0xc6,0x60,0x38,0x6c,0xc6,0xc6,0x6c,0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0xfe,0xfe,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x7e,0x3c,0x18,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x18,0x0c,0xfe,0x0c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xfe,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0xc0,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7c,0x7c,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0xfe,0xfe,0x7c,0x7c,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*!*/ 0x00,0x00,0x18,0x3c,0x3c,0x3c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/*"*/ 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*#*/ 0x00,0x00,0x00,0x6c,0x6c,0xfe,0x6c,0x6c,0x6c,0xfe,0x6c,0x6c,0x00,0x00,0x00,0x00,
+/*$*/ 0x18,0x18,0x7c,0xc6,0xc2,0xc0,0x7c,0x06,0x06,0x86,0xc6,0x7c,0x18,0x18,0x00,0x00,
+/*%*/ 0x00,0x00,0x00,0x00,0xc2,0xc6,0x0c,0x18,0x30,0x60,0xc6,0x86,0x00,0x00,0x00,0x00,
+/*&*/ 0x00,0x00,0x38,0x6c,0x6c,0x38,0x76,0xdc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*'*/ 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*(*/ 0x00,0x00,0x0c,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0c,0x00,0x00,0x00,0x00,
+/*)*/ 0x00,0x00,0x30,0x18,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x18,0x30,0x00,0x00,0x00,0x00,
+/***/ 0x00,0x00,0x00,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
+/*+*/ 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/*,*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
+/*-*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*.*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x02,0x06,0x0c,0x18,0x30,0x60,0xc0,0x80,0x00,0x00,0x00,0x00,
+/*0*/ 0x00,0x00,0x7c,0xc6,0xc6,0xce,0xde,0xf6,0xe6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*1*/ 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x00,0x00,0x00,0x00,
+/*2*/ 0x00,0x00,0x7c,0xc6,0x06,0x0c,0x18,0x30,0x60,0xc0,0xc6,0xfe,0x00,0x00,0x00,0x00,
+/*3*/ 0x00,0x00,0x7c,0xc6,0x06,0x06,0x3c,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*4*/ 0x00,0x00,0x0c,0x1c,0x3c,0x6c,0xcc,0xfe,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,
+/*5*/ 0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xfc,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*6*/ 0x00,0x00,0x38,0x60,0xc0,0xc0,0xfc,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*7*/ 0x00,0x00,0xfe,0xc6,0x06,0x06,0x0c,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
+/*8*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7c,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*9*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7e,0x06,0x06,0x06,0x0c,0x78,0x00,0x00,0x00,0x00,
+/*:*/ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/*;*/ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
+/*<*/ 0x00,0x00,0x00,0x06,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,
+/*=*/ 0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*>*/ 0x00,0x00,0x00,0x60,0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
+/*?*/ 0x00,0x00,0x7c,0xc6,0xc6,0x0c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/*@*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xde,0xde,0xde,0xdc,0xc0,0x7c,0x00,0x00,0x00,0x00,
+/*A*/ 0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/*B*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x66,0x66,0x66,0x66,0xfc,0x00,0x00,0x00,0x00,
+/*C*/ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,0xc0,0xc2,0x66,0x3c,0x00,0x00,0x00,0x00,
+/*D*/ 0x00,0x00,0xf8,0x6c,0x66,0x66,0x66,0x66,0x66,0x66,0x6c,0xf8,0x00,0x00,0x00,0x00,
+/*E*/ 0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
+/*F*/ 0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*G*/ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xde,0xc6,0xc6,0x66,0x3a,0x00,0x00,0x00,0x00,
+/*H*/ 0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/*I*/ 0x00,0x00,0x3c,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*J*/ 0x00,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00,
+/*K*/ 0x00,0x00,0xe6,0x66,0x66,0x6c,0x78,0x78,0x6c,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*L*/ 0x00,0x00,0xf0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
+/*M*/ 0x00,0x00,0xc3,0xe7,0xff,0xff,0xdb,0xc3,0xc3,0xc3,0xc3,0xc3,0x00,0x00,0x00,0x00,
+/*N*/ 0x00,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/*O*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*P*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*Q*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xd6,0xde,0x7c,0x0c,0x0e,0x00,0x00,
+/*R*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x6c,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*S*/ 0x00,0x00,0x7c,0xc6,0xc6,0x60,0x38,0x0c,0x06,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*T*/ 0x00,0x00,0xff,0xdb,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*U*/ 0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*V*/ 0x00,0x00,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x00,0x00,0x00,0x00,
+/*W*/ 0x00,0x00,0xc3,0xc3,0xc3,0xc3,0xc3,0xdb,0xdb,0xff,0x66,0x66,0x00,0x00,0x00,0x00,
+/*X*/ 0x00,0x00,0xc3,0xc3,0x66,0x3c,0x18,0x18,0x3c,0x66,0xc3,0xc3,0x00,0x00,0x00,0x00,
+/*Y*/ 0x00,0x00,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*Z*/ 0x00,0x00,0xff,0xc3,0x86,0x0c,0x18,0x30,0x60,0xc1,0xc3,0xff,0x00,0x00,0x00,0x00,
+/*[*/ 0x00,0x00,0x3c,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3c,0x00,0x00,0x00,0x00,
+/*\*/ 0x00,0x00,0x00,0x80,0xc0,0xe0,0x70,0x38,0x1c,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,
+/*]*/ 0x00,0x00,0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00,0x00,0x00,0x00,
+/*^*/ 0x10,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*_*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,
+/*`*/ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*a*/ 0x00,0x00,0x00,0x00,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*b*/ 0x00,0x00,0xe0,0x60,0x60,0x78,0x6c,0x66,0x66,0x66,0x66,0x7c,0x00,0x00,0x00,0x00,
+/*c*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc0,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*d*/ 0x00,0x00,0x1c,0x0c,0x0c,0x3c,0x6c,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*e*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*f*/ 0x00,0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*g*/ 0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0xcc,0x78,0x00,
+/*h*/ 0x00,0x00,0xe0,0x60,0x60,0x6c,0x76,0x66,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*i*/ 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*j*/ 0x00,0x00,0x06,0x06,0x00,0x0e,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3c,0x00,
+/*k*/ 0x00,0x00,0xe0,0x60,0x60,0x66,0x6c,0x78,0x78,0x6c,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*l*/ 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*m*/ 0x00,0x00,0x00,0x00,0x00,0xe6,0xff,0xdb,0xdb,0xdb,0xdb,0xdb,0x00,0x00,0x00,0x00,
+/*n*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/*o*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*p*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0xf0,0x00,
+/*q*/ 0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x1e,0x00,
+/*r*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x76,0x66,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*s*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0x60,0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*t*/ 0x00,0x00,0x10,0x30,0x30,0xfc,0x30,0x30,0x30,0x30,0x36,0x1c,0x00,0x00,0x00,0x00,
+/*u*/ 0x00,0x00,0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*v*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x00,0x00,0x00,0x00,
+/*w*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xdb,0xdb,0xff,0x66,0x00,0x00,0x00,0x00,
+/*x*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0x66,0x3c,0x18,0x3c,0x66,0xc3,0x00,0x00,0x00,0x00,
+/*y*/ 0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00,
+/*z*/ 0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
+/*{*/ 0x00,0x00,0x0e,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0e,0x00,0x00,0x00,0x00,
+/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/*}*/ 0x00,0x00,0x70,0x18,0x18,0x18,0x0e,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
+/*~*/ 0x00,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xfe,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,0xc2,0x66,0x3c,0x0c,0x06,0x7c,0x00,0x00,
+/* */ 0x00,0x00,0xcc,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0c,0x18,0x30,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x10,0x38,0x6c,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xcc,0x00,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x38,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x3c,0x66,0x60,0x60,0x66,0x3c,0x0c,0x06,0x3c,0x00,0x00,0x00,
+/* */ 0x00,0x10,0x38,0x6c,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc6,0x00,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x3c,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xc6,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x38,0x6c,0x38,0x00,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x30,0x60,0x00,0xfe,0x66,0x60,0x7c,0x60,0x60,0x66,0xfe,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x6e,0x3b,0x1b,0x7e,0xd8,0xdc,0x77,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3e,0x6c,0xcc,0xcc,0xfe,0xcc,0xcc,0xcc,0xcc,0xce,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x10,0x38,0x6c,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc6,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x30,0x78,0xcc,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc6,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0x78,0x00,
+/* */ 0x00,0xc6,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xc6,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x18,0x7e,0xc3,0xc0,0xc0,0xc0,0xc3,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,0x60,0x60,0x60,0xe6,0xfc,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc3,0x66,0x3c,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xfc,0x66,0x66,0x7c,0x62,0x66,0x6f,0x66,0x66,0x66,0xf3,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0e,0x1b,0x18,0x18,0x18,0x7e,0x18,0x18,0x18,0x18,0x18,0xd8,0x70,0x00,0x00,
+/* */ 0x00,0x18,0x30,0x60,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0c,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x30,0x60,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x30,0x60,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x76,0xdc,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/* */ 0x76,0xdc,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x3c,0x6c,0x6c,0x3e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x6c,0x38,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xc0,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xc0,0xc0,0xc2,0xc6,0xcc,0x18,0x30,0x60,0xce,0x9b,0x06,0x0c,0x1f,0x00,0x00,
+/* */ 0x00,0xc0,0xc0,0xc2,0xc6,0xcc,0x18,0x30,0x66,0xce,0x96,0x3e,0x06,0x06,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3c,0x3c,0x3c,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x36,0x6c,0xd8,0x6c,0x36,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xd8,0x6c,0x36,0x6c,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
+/* */ 0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
+/* */ 0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf6,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xfe,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf6,0x06,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x3f,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf7,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xf7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf7,0x00,0xf7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xff,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+/* */ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
+/* */ 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x76,0xdc,0xd8,0xd8,0xd8,0xdc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x78,0xcc,0xcc,0xcc,0xd8,0xcc,0xc6,0xc6,0xc6,0xcc,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xfe,0xc6,0xc6,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0xfe,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0xfe,0xc6,0x60,0x30,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x7e,0xd8,0xd8,0xd8,0xd8,0xd8,0x70,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0xc0,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x76,0xdc,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x7e,0x18,0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0x6c,0x38,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x38,0x6c,0xc6,0xc6,0xc6,0x6c,0x6c,0x6c,0x6c,0xee,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x1e,0x30,0x18,0x0c,0x3e,0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x7e,0xdb,0xdb,0xdb,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x03,0x06,0x7e,0xdb,0xdb,0xf3,0x7e,0x60,0xc0,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x1c,0x30,0x60,0x60,0x7c,0x60,0x60,0x60,0x30,0x1c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00,0xff,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x00,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x00,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x0e,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xd8,0xd8,0xd8,0x70,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7e,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x76,0xdc,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0f,0x0c,0x0c,0x0c,0x0c,0x0c,0xec,0x6c,0x6c,0x3c,0x1c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xd8,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x70,0xd8,0x30,0x60,0xc8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
diff --git a/drivers/sbus/char/sunfb.c b/drivers/sbus/char/sunfb.c
new file mode 100644
index 000000000..e803344bd
--- /dev/null
+++ b/drivers/sbus/char/sunfb.c
@@ -0,0 +1,315 @@
+/* $Id: sunfb.c,v 1.22 1997/04/03 08:47:56 davem Exp $
+ * sunfb.c: Sun generic frame buffer support.
+ *
+ * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Added getcmap ioctl, may, 96
+ * Support for multiple fbs, sep, 96
+ */
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/oplib.h>
+#include <asm/sbus.h>
+#include <asm/fbio.h>
+#include <asm/io.h>
+
+#include "../../char/kbd_kern.h"
+#include "../../char/vt_kern.h"
+#include "../../char/consolemap.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+
+#include "fb.h"
+
+extern void set_other_palette (int);
+extern void sun_clear_fb(int);
+extern void set_cursor (int);
+
+#define FB_SETUP(err) \
+ int minor = FB_DEV (inode->i_rdev); \
+\
+ if (minor >= fbinfos || \
+ fbinfo [minor].type.fb_type == FBTYPE_NOTYPE) \
+ return -(err);
+
+static int
+fb_open (struct inode * inode, struct file * file)
+{
+ FB_SETUP(EBADF)
+ if (fbinfo [minor].open)
+ return -EBUSY;
+ fbinfo [minor].mmaped = 0;
+ fbinfo [minor].open = 1;
+ return 0;
+}
+
+static int
+fb_ioctl (struct inode *inode, struct file *file, uint cmd, unsigned long arg)
+{
+ fbinfo_t *fb;
+ struct fbcmap *cmap;
+ int i;
+ FB_SETUP(EBADF)
+
+ fb = &fbinfo [minor];
+
+ switch (cmd){
+ case FBIOGTYPE: /* return frame buffer type */
+ copy_to_user_ret((struct fbtype *)arg, &fb->type, sizeof(struct fbtype), -EFAULT);
+ break;
+ case FBIOGATTR:{
+ struct fbgattr *fba = (struct fbgattr *) arg;
+
+ i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
+ if (i) return i;
+ __put_user_ret(fb->real_type, &fba->real_type, -EFAULT);
+ __put_user_ret(0, &fba->owner, -EFAULT);
+ __copy_to_user_ret(&fba->fbtype, &fb->type,
+ sizeof(struct fbtype), -EFAULT);
+ __put_user_ret(0, &fba->sattr.flags, -EFAULT);
+ __put_user_ret(fb->type.fb_type, &fba->sattr.emu_type, -EFAULT);
+ __put_user_ret(-1, &fba->sattr.dev_specific[0], -EFAULT);
+ __put_user_ret(fb->type.fb_type, &fba->emu_types[0], -EFAULT);
+ for (i = 1; i < 4; i++)
+ put_user_ret(fb->emulations[i], &fba->emu_types[i], -EFAULT);
+ break;
+ }
+ case FBIOSATTR:
+ i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbsattr));
+ if (i) return i;
+ return -EINVAL;
+ case FBIOSVIDEO:
+ if (fb == fbinfo && vt_cons[fg_console]->vc_mode == KD_TEXT)
+ break;
+ get_user_ret(i, (int *)arg, -EFAULT);
+ if (i){
+ if (!fb->blanked || !fb->unblank)
+ break;
+ if (!minor || (fb->open && fb->mmaped))
+ (*fb->unblank)(fb);
+ fb->blanked = 0;
+ } else {
+ if (fb->blanked || !fb->blank)
+ break;
+ (*fb->blank)(fb);
+ fb->blanked = 1;
+ }
+ break;
+ case FBIOGVIDEO:
+ put_user_ret(fb->blanked, (int *) arg, -EFAULT);
+ break;
+ case FBIOGETCMAP: {
+ char *rp, *gp, *bp;
+ int end, count, index;
+
+ if (!fb->loadcmap)
+ return -EINVAL;
+ i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
+ if (i) return i;
+ cmap = (struct fbcmap *) arg;
+ __get_user_ret(count, &cmap->count, -EFAULT);
+ __get_user_ret(index, &cmap->index, -EFAULT);
+ if ((index < 0) || (index > 255))
+ return -EINVAL;
+ if (index + count > 256)
+ count = 256 - cmap->index;
+ __get_user_ret(rp, &cmap->red, -EFAULT);
+ __get_user_ret(gp, &cmap->green, -EFAULT);
+ __get_user_ret(bp, &cmap->blue, -EFAULT);
+ if(verify_area (VERIFY_WRITE, rp, count)) return -EFAULT;
+ if(verify_area (VERIFY_WRITE, gp, count)) return -EFAULT;
+ if(verify_area (VERIFY_WRITE, bp, count)) return -EFAULT;
+ end = index + count;
+ for (i = index; i < end; i++){
+ __put_user_ret(fb->color_map CM(i,0), rp, -EFAULT);
+ __put_user_ret(fb->color_map CM(i,1), gp, -EFAULT);
+ __put_user_ret(fb->color_map CM(i,2), bp, -EFAULT);
+ rp++; gp++; bp++;
+ }
+ (*fb->loadcmap)(fb, cmap->index, count);
+ break;
+
+ }
+ case FBIOPUTCMAP: { /* load color map entries */
+ char *rp, *gp, *bp;
+ int end, count, index;
+
+ if (!fb->loadcmap)
+ return -EINVAL;
+ i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
+ if (i) return i;
+ cmap = (struct fbcmap *) arg;
+ __get_user_ret(count, &cmap->count, -EFAULT);
+ __get_user_ret(index, &cmap->index, -EFAULT);
+ if ((index < 0) || (index > 255))
+ return -EINVAL;
+ if (index + count > 256)
+ count = 256 - cmap->index;
+ __get_user_ret(rp, &cmap->red, -EFAULT);
+ __get_user_ret(gp, &cmap->green, -EFAULT);
+ __get_user_ret(bp, &cmap->blue, -EFAULT);
+ if(verify_area (VERIFY_READ, rp, cmap->count)) return -EFAULT;
+ if(verify_area (VERIFY_READ, gp, cmap->count)) return -EFAULT;
+ if(verify_area (VERIFY_READ, bp, cmap->count)) return -EFAULT;
+
+ end = index + count;
+ for (i = index; i < end; i++){
+ __get_user_ret(fb->color_map CM(i,0), rp, -EFAULT);
+ __get_user_ret(fb->color_map CM(i,1), gp, -EFAULT);
+ __get_user_ret(fb->color_map CM(i,2), bp, -EFAULT);
+ rp++; gp++; bp++;
+ }
+ (*fb->loadcmap)(fb, cmap->index, count);
+ break;
+ }
+
+ case FBIOGCURMAX: {
+ struct fbcurpos *p = (struct fbcurpos *) arg;
+ if (!fb->setcursor) return -EINVAL;
+ if(verify_area (VERIFY_WRITE, p, sizeof (struct fbcurpos)))
+ return -EFAULT;
+ __put_user_ret(fb->cursor.hwsize.fbx, &p->fbx, -EFAULT);
+ __put_user_ret(fb->cursor.hwsize.fby, &p->fby, -EFAULT);
+ break;
+ }
+ case FBIOSCURSOR:
+ if (!fb->setcursor) return -EINVAL;
+ if (fb == fbinfo) {
+ if (vt_cons[fg_console]->vc_mode == KD_TEXT)
+ return -EINVAL; /* Don't let graphics programs hide our nice text cursor */
+ sun_hw_cursor_shown = 0; /* Forget state of our text cursor */
+ }
+ return sun_hw_scursor ((struct fbcursor *) arg, fb);
+
+ case FBIOSCURPOS:
+ if (!fb->setcursor) return -EINVAL;
+ /* Don't let graphics programs move our nice text cursor */
+ if (fb == fbinfo) {
+ if (vt_cons[fg_console]->vc_mode == KD_TEXT)
+ return -EINVAL; /* Don't let graphics programs move our nice text cursor */
+ }
+ i= verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcurpos));
+ if (i) return i;
+ fb->cursor.cpos = *(struct fbcurpos *)arg;
+ (*fb->setcursor) (fb);
+ break;
+
+ default:
+ if (fb->ioctl){
+ i = fb->ioctl (inode, file, cmd, arg, fb);
+ if (i == -ENOSYS) {
+ printk ("[[FBIO: %8.8x]]\n", cmd);
+ return -EINVAL;
+ }
+ return i;
+ }
+ printk ("[[FBIO: %8.8x]]\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+fb_close (struct inode * inode, struct file *filp)
+{
+ fbinfo_t *fb;
+ struct fbcursor cursor;
+ FB_SETUP(EBADF)
+
+ fb = &fbinfo[minor];
+
+ if (!minor)
+ vt_cons [fb->vtconsole]->vc_mode = KD_TEXT;
+
+ /* Leaving graphics mode, turn off the cursor */
+ if (fb->mmaped)
+ sun_clear_fb (minor);
+ cursor.set = FB_CUR_SETCUR;
+ cursor.enable = 0;
+
+ /* Reset the driver */
+ if (fb->reset)
+ fb->reset(fb);
+
+ if (fb->open)
+ fb->open = 0;
+ fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor);
+ set_other_palette (minor);
+ if (!minor) {
+ render_screen ();
+ set_cursor (fg_console);
+ } else if (fb->blank)
+ (*fb->blank)(fb);
+ return 0;
+}
+
+static int
+fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+{
+ fbinfo_t *fb;
+ FB_SETUP(ENXIO)
+
+ fb = &fbinfo [minor];
+
+ if (fb->mmap){
+ int v;
+
+ v = (*fb->mmap)(inode, file, vma, fb->base, fb);
+ if (v) return v;
+ if (!fb->mmaped) {
+ fb->mmaped = 1;
+ if (!minor) {
+ fb->vtconsole = fg_console;
+ vt_cons [fg_console]->vc_mode = KD_GRAPHICS;
+ } else {
+ if (fb->unblank && !fb->blanked)
+ (*fb->unblank)(fb);
+ }
+ }
+ return 0;
+ } else
+ return -ENXIO;
+}
+
+static struct file_operations graphdev_fops =
+{
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ fb_ioctl,
+ fb_mmap,
+ fb_open, /* open */
+ fb_close, /* close */
+};
+
+__initfunc(int fb_init (void))
+{
+ /* Register the frame buffer device */
+ if (register_chrdev (GRAPHDEV_MAJOR, "graphics", &graphdev_fops)){
+ printk ("Could not register graphics device\n");
+ return -EIO;
+ }
+ return 0; /* success */
+}
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index b5d3c42ea..87fb0fea4 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -14,11 +14,16 @@
#include <linux/signal.h>
#include <linux/string.h>
#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/random.h>
+#include <linux/init.h>
+
#include <asm/kbio.h>
#include <asm/vuid_event.h>
#include <asm/delay.h>
#include <asm/bitops.h>
#include <asm/oplib.h>
+#include <asm/uaccess.h>
#include "../../char/kbd_kern.h"
#include "../../char/diacr.h"
@@ -58,7 +63,15 @@ extern void reset_vc(unsigned int new_console);
extern void scrollback(int);
extern void scrollfront(int);
-unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
+unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
+unsigned char aux_device_present = 0x00; /* To make kernel/ksyms.c happy */
+
+struct wait_queue * keypress_wait = NULL;
+
+void keyboard_wait_for_keypress(void)
+{
+ sleep_on(&keypress_wait);
+}
/*
* global state includes the following, and various static variables
@@ -89,6 +102,9 @@ struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct tty_struct **ttytab;
static struct kbd_struct * kbd = kbd_table;
static struct tty_struct * tty = NULL;
+static int compose_led_on = 0;
+static int kbd_delay_ticks = HZ / 5;
+static int kbd_rate_ticks = HZ / 20;
extern void compute_shiftstate(void);
@@ -141,8 +157,8 @@ volatile unsigned char sunkbd_type;
#define SUNKBD_TYPE3 0x03
#define SUNKBD_TYPE4 0x04
-#define SUNKBD_LOUT_TYP4 0x00
-#define SUNKBD_LOUT_TYP5 0x22
+#define SUNKBD_LOUT_TYP4 0x00
+#define SUNKBD_LOUT_TYP5_MASK 0x20
volatile int kbd_reset_pending;
volatile int kbd_layout_pending;
@@ -213,6 +229,8 @@ static inline unsigned char vcleds_to_sunkbd(unsigned char vcleds)
retval |= LED_NLOCK;
if(vcleds & (1<<VC_CAPSLOCK))
retval |= LED_CLOCK;
+ if(compose_led_on)
+ retval |= LED_CMPOSE;
return retval;
}
@@ -331,6 +349,21 @@ static unsigned char e0_keys[128] = {
0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
};
+/* we use this map to determine if a particular key should not be
+ autorepeated. We don't autorepeat CONTROL, LSHIFT, CAPS,
+ ALT, LMETA, RSHIFT, RMETA, ALTG and COMPOSE */
+static unsigned char norepeat_keys[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 0x00-0x0f */
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x2f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30-0x3f */
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, /* 0x40-0x4f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50-0x5f */
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 0x60-0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, /* 0x70-0x7f */
+};
+
+
int setkeycode(unsigned int scancode, unsigned int keycode)
{
if (scancode < SC_LIM || scancode > 255 || keycode > 127)
@@ -350,7 +383,7 @@ int getkeycode(unsigned int scancode)
e0_keys[scancode - 128];
}
-void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs);
+void sunkbd_inchar(unsigned char ch, struct pt_regs *regs);
static void keyboard_timer (unsigned long ignored);
static struct timer_list
@@ -367,16 +400,18 @@ keyboard_timer (unsigned long ignored)
save_flags(flags); cli();
/* Auto repeat: send regs = 0 to indicate autorepeat */
- sunkbd_inchar (last_keycode, 0, 0);
+ sunkbd_inchar (last_keycode, 0);
del_timer (&auto_repeat_timer);
- auto_repeat_timer.expires = jiffies + HZ/20;
- add_timer (&auto_repeat_timer);
+ if (kbd_rate_ticks) {
+ auto_repeat_timer.expires = jiffies + kbd_rate_ticks;
+ add_timer (&auto_repeat_timer);
+ }
restore_flags(flags);
}
/* #define SKBD_DEBUG */
/* This is our keyboard 'interrupt' routine. */
-void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs)
+void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
{
unsigned char keycode;
char up_flag; /* 0 or SUNKBD_UBIT */
@@ -401,7 +436,9 @@ void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs)
kbd_layout_pending = 0;
return;
} else if(ch == SKBD_ALLUP) {
- /* eat it */
+ del_timer (&auto_repeat_timer);
+ memset(key_down, 0, sizeof(key_down));
+ compute_shiftstate();
return;
}
#ifdef SKBD_DEBUG
@@ -413,11 +450,13 @@ void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs)
#endif
/* Whee, a real character. */
- if (regs){
+ if(regs) {
pt_regs = regs;
last_keycode = keycode = ch;
- } else
+ } else {
keycode = ch;
+ }
+ add_keyboard_randomness(keycode);
mark_bh(KEYBOARD_BH);
do_poke_blanked_console = 1;
@@ -441,8 +480,13 @@ void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs)
rep = 0;
clear_bit(keycode, key_down);
} else {
- auto_repeat_timer.expires = jiffies+HZ/5;
- add_timer (&auto_repeat_timer);
+ if (!norepeat_keys[keycode]) {
+ if (kbd_rate_ticks) {
+ auto_repeat_timer.expires =
+ jiffies + kbd_delay_ticks;
+ add_timer (&auto_repeat_timer);
+ }
+ }
rep = set_bit(keycode, key_down);
}
@@ -661,6 +705,8 @@ static void boot_it(void)
static void compose(void)
{
dead_key_next = 1;
+ compose_led_on = 1;
+ set_leds();
}
int spawnpid, spawnsig;
@@ -718,8 +764,11 @@ static void do_self(unsigned char value, char up_flag)
if (up_flag)
return; /* no action, if this is a key release */
- if (diacr)
+ if (diacr) {
value = handle_diacr(value);
+ compose_led_on = 0;
+ set_leds();
+ }
if (dead_key_next) {
dead_key_next = 0;
@@ -782,7 +831,7 @@ static void do_cons(unsigned char value, char up_flag)
{
if (up_flag)
return;
- want_console = value;
+ set_console(value);
}
static void do_fn(unsigned char value, char up_flag)
@@ -971,6 +1020,7 @@ static void do_lock(unsigned char value, char up_flag)
*/
static unsigned char ledstate = 0xff; /* undefined */
+static unsigned char sunkbd_ledstate = 0xff; /* undefined */
static unsigned char ledioctl;
unsigned char getledstate(void) {
@@ -1050,15 +1100,56 @@ static inline unsigned char getleds(void){
static void kbd_bh(void)
{
unsigned char leds = getleds();
+ unsigned char kbd_leds = vcleds_to_sunkbd(leds);
- if (leds != ledstate) {
+ if (kbd_leds != sunkbd_ledstate) {
ledstate = leds;
+ sunkbd_ledstate = kbd_leds;
send_cmd(SKBDCMD_SETLED);
- send_cmd(vcleds_to_sunkbd(leds));
+ send_cmd(kbd_leds);
}
}
-int kbd_init(void)
+/* Support for keyboard "beeps". */
+
+/* Timer routine to turn off the beep after the interval expires. */
+static void sunkbd_kd_nosound(unsigned long __unused)
+{
+ send_cmd(SKBDCMD_BELLOFF);
+}
+
+/*
+ * Initiate a keyboard beep. If the frequency is zero, then we stop
+ * the beep. Any other frequency will start a monotone beep. The beep
+ * will be stopped by a timer after "ticks" jiffies. If ticks is 0,
+ * then we do not start a timer.
+ */
+static void sunkbd_kd_mksound(unsigned int hz, unsigned int ticks)
+{
+ unsigned long flags;
+ static struct timer_list sound_timer = { NULL, NULL, 0, 0,
+ sunkbd_kd_nosound };
+
+ save_flags(flags);
+ cli();
+
+ del_timer(&sound_timer);
+
+ if (hz) {
+ send_cmd(SKBDCMD_BELLON);
+ if (ticks) {
+ sound_timer.expires = jiffies + ticks;
+ add_timer(&sound_timer);
+ }
+ } else
+ send_cmd(SKBDCMD_BELLOFF);
+
+ restore_flags(flags);
+}
+
+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+
+__initfunc(int kbd_init(void))
{
int i, opt_node;
struct kbd_struct kbd0;
@@ -1075,6 +1166,8 @@ int kbd_init(void)
ttytab = console_driver.table;
+ kd_mksound = sunkbd_kd_mksound;
+
/* XXX Check keyboard-click? property in 'options' PROM node XXX */
if(sparc_cpu_model != sun4) {
opt_node = prom_getchild(prom_root_node);
@@ -1098,6 +1191,7 @@ int kbd_init(void)
static Firm_event kbd_queue [KBD_QSIZE];
static int kbd_head, kbd_tail;
char kbd_opened;
+static int kbd_active = 0;
static struct wait_queue *kbd_wait;
static struct fasync_struct *kb_fasync;
@@ -1119,8 +1213,8 @@ push_kbd (int scan)
wake_up_interruptible (&kbd_wait);
}
-static int
-kbd_read (struct inode *inode, struct file *f, char *buffer, int count)
+static long
+kbd_read (struct inode *inode, struct file *f, char *buffer, unsigned long count)
{
struct wait_queue wait = { current, NULL };
char *end, *p;
@@ -1141,7 +1235,7 @@ kbd_read (struct inode *inode, struct file *f, char *buffer, int count)
end = buffer+count;
p = buffer;
for (; p < end && kbd_head != kbd_tail; p += sizeof (Firm_event)){
- *(Firm_event *)p = kbd_queue [kbd_tail];
+ copy_to_user_ret((Firm_event *)p, &kbd_queue [kbd_tail], sizeof(Firm_event), -EFAULT);
#ifdef KBD_DEBUG
printk ("[%s]", kbd_queue [kbd_tail].value == VKEY_UP ? "UP" : "DOWN");
#endif
@@ -1163,47 +1257,40 @@ kbd_fasync (struct inode *inode, struct file *filp, int on)
return 0;
}
-static int
-kbd_select (struct inode *i, struct file *f, int sel_type, select_table *wait)
+static unsigned int kbd_poll (struct file *f, poll_table *wait)
{
- if (sel_type != SEL_IN)
- return 0;
+ poll_wait(&kbd_wait, wait);
if (kbd_head != kbd_tail)
- return 1;
- select_wait (&kbd_wait, wait);
+ return POLLIN | POLLRDNORM;
return 0;
}
static int
kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
{
+ unsigned char c;
+ unsigned char leds = 0;
+ int value;
+
switch (cmd){
- case KIOCTYPE: /* return keyboard type */
- if (verify_area (VERIFY_WRITE, (void *)arg, sizeof (int)))
- return -EFAULT;
- *(int *) arg = sunkbd_type;
+ case KIOCTYPE: /* return keyboard type */
+ put_user_ret(sunkbd_type, (int *) arg, -EFAULT);
break;
case KIOCGTRANS:
- if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
- return -EFAULT;
- *(int *) arg = TR_UNTRANS_EVENT;
+ put_user_ret(TR_UNTRANS_EVENT, (int *) arg, -EFAULT);
break;
case KIOCTRANS:
- if (verify_area (VERIFY_READ, (void *) arg, sizeof (int)))
- return -EFAULT;
- if (*(int *) arg != TR_UNTRANS_EVENT)
+ get_user_ret(value, (int *) arg, -EFAULT);
+ if (value != TR_UNTRANS_EVENT)
return -EINVAL;
break;
case KIOCLAYOUT:
- if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
- return -EFAULT;
- *(int *) arg = sunkbd_layout;
+ put_user_ret(sunkbd_layout, (int *) arg, -EFAULT);
break;
case KIOCSDIRECT:
- if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
- return -EFAULT;
#ifndef CODING_NEW_DRIVER
- if (*(int *) arg)
+ get_user_ret(value, (int *) arg, -EFAULT);
+ if(value)
kbd_redirected = fg_console + 1;
else
kbd_redirected = 0;
@@ -1211,16 +1298,75 @@ kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
#endif
break;
case KIOCCMD:
- /* Need to support beep on/off, keyclick on/off */
+ get_user_ret(value, (int *) arg, -EFAULT);
+ c = (unsigned char) value;
+ switch (c) {
+ case SKBDCMD_CLICK:
+ case SKBDCMD_NOCLICK:
+ send_cmd(c);
+ return 0;
+ case SKBDCMD_BELLON:
+ kd_mksound(1,0);
+ return 0;
+ case SKBDCMD_BELLOFF:
+ kd_mksound(0,0);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ case KIOCSLED:
+ get_user_ret(c, (unsigned char *) arg, -EFAULT);
+
+ if (c & LED_SCRLCK) leds |= (1 << VC_SCROLLOCK);
+ if (c & LED_NLOCK) leds |= (1 << VC_NUMLOCK);
+ if (c & LED_CLOCK) leds |= (1 << VC_CAPSLOCK);
+ compose_led_on = !!(c & LED_CMPOSE);
+ setledstate(kbd_table + fg_console, leds);
+ break;
+ case KIOCGLED:
+ put_user_ret(vcleds_to_sunkbd(getleds()), (unsigned char *) arg, -EFAULT);
+ break;
+ case KIOCGRATE:
+ {
+ struct kbd_rate rate;
+
+ rate.delay = kbd_delay_ticks;
+ if (kbd_rate_ticks)
+ rate.rate = HZ / kbd_rate_ticks;
+ else
+ rate.rate = 0;
+
+ copy_to_user_ret((struct kbd_rate *)arg, &rate,
+ sizeof(struct kbd_rate), -EFAULT);
+
+ return 0;
+ }
+ case KIOCSRATE:
+ {
+ struct kbd_rate rate;
+
+ if (verify_area(VERIFY_READ, (void *)arg,
+ sizeof(struct kbd_rate)))
+ return -EFAULT;
+ copy_from_user(&rate, (struct kbd_rate *)arg,
+ sizeof(struct kbd_rate));
+
+ if (rate.rate > 50)
+ return -EINVAL;
+ if (rate.rate == 0)
+ kbd_rate_ticks = 0;
+ else
+ kbd_rate_ticks = HZ / rate.rate;
+ kbd_delay_ticks = rate.delay;
+
return 0;
+ }
case FIONREAD: /* return number of bytes in kbd queue */
{
int count;
- if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
- return -EFAULT;
count = kbd_head - kbd_tail;
- * (int *)arg = (count < 0) ? KBD_QSIZE - count : count;
+ put_user_ret((count < 0) ? KBD_QSIZE - count : count, (int *) arg, -EFAULT);
return 0;
}
default:
@@ -1233,22 +1379,30 @@ kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
static int
kbd_open (struct inode *i, struct file *f)
{
+ kbd_active++;
+
if (kbd_opened)
return 0;
+
kbd_opened = fg_console + 1;
kbd_head = kbd_tail = 0;
return 0;
}
-static void
+static int
kbd_close (struct inode *i, struct file *f)
{
+ if (--kbd_active)
+ return 0;
+
if (kbd_redirected)
kbd_table [kbd_opened-1].kbdmode = VC_XLATE;
+
kbd_redirected = 0;
kbd_opened = 0;
kbd_fasync (i, f, 0);
+ return 0;
}
static struct
@@ -1258,7 +1412,7 @@ file_operations kbd_fops =
kbd_read, /* read */
NULL, /* write */
NULL, /* readdir */
- kbd_select, /* select */
+ kbd_poll, /* poll */
kbd_ioctl, /* ioctl */
NULL, /* mmap */
kbd_open, /* open */
@@ -1269,8 +1423,7 @@ file_operations kbd_fops =
NULL, /* revalidate */
};
-void
-keyboard_zsinit(void)
+__initfunc(void keyboard_zsinit(void))
{
int timeout = 0;
@@ -1295,15 +1448,18 @@ keyboard_zsinit(void)
while(timeout++ < 500000)
barrier();
printk("Sun TYPE %d keyboard detected ",
- ((sunkbd_layout==SUNKBD_LOUT_TYP5) ? 5 : 4));
+ ((sunkbd_layout & SUNKBD_LOUT_TYP5_MASK) ? 5 : 4));
}
if(sunkbd_type == SUNKBD_TYPE2)
sunkbd_clickp = 0;
- if(sunkbd_clickp)
+ if(sunkbd_clickp) {
+ send_cmd(SKBDCMD_CLICK);
printk("with keyclick\n");
- else
+ } else {
+ send_cmd(SKBDCMD_NOCLICK);
printk("without keyclick\n");
+ }
/* Dork with led lights, then turn them all off */
send_cmd(SKBDCMD_SETLED); send_cmd(0xf); /* All on */
diff --git a/drivers/sbus/char/sunkeymap.c b/drivers/sbus/char/sunkeymap.c
index 17b2f5789..076367f59 100644
--- a/drivers/sbus/char/sunkeymap.c
+++ b/drivers/sbus/char/sunkeymap.c
@@ -26,8 +26,8 @@ u_short plain_map[NR_KEYS] = {
u_short shift_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf10a, 0xf10b, 0xf113,
- 0xf10c, 0xf10a, 0xf10d, 0xf10b, 0xf10e, 0xf701, 0xf105, 0xf200,
- 0xf110, 0xf107, 0xf112, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf203,
+ 0xf10c, 0xf10a, 0xf10d, 0xf10b, 0xf10e, 0xf701, 0xf10f, 0xf200,
+ 0xf110, 0xf111, 0xf112, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf203,
0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf01b, 0xf021, 0xf040,
0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, 0xf02a, 0xf028, 0xf029,
0xf05f, 0xf02b, 0xf07e, 0xf07f, 0xf115, 0xf200, 0xf30d, 0xf30c,
@@ -45,7 +45,7 @@ u_short shift_map[NR_KEYS] = {
u_short altgr_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf50c, 0xf50d, 0xf515,
- 0xf50e, 0xf516, 0xf50f, 0xf517, 0xf510, 0xf701, 0xf200, 0xf200,
+ 0xf50e, 0xf516, 0xf50f, 0xf517, 0xf510, 0xf701, 0xf511, 0xf200,
0xf512, 0xf513, 0xf514, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf202,
0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf040,
0xf200, 0xf024, 0xf200, 0xf200, 0xf07b, 0xf05b, 0xf05d, 0xf07d,
@@ -64,8 +64,8 @@ u_short altgr_map[NR_KEYS] = {
u_short ctrl_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf100, 0xf101, 0xf109,
- 0xf102, 0xf10a, 0xf103, 0xf10b, 0xf104, 0xf701, 0xf200, 0xf200,
- 0xf107, 0xf200, 0xf108, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf204,
+ 0xf102, 0xf10a, 0xf103, 0xf10b, 0xf104, 0xf701, 0xf105, 0xf200,
+ 0xf106, 0xf107, 0xf108, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf204,
0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf000,
0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 0xf07f, 0xf200, 0xf200,
0xf01f, 0xf200, 0xf000, 0xf008, 0xf115, 0xf200, 0xf30d, 0xf30c,
@@ -103,7 +103,7 @@ u_short shift_ctrl_map[NR_KEYS] = {
u_short alt_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf500, 0xf501, 0xf509,
0xf502, 0xf50a, 0xf503, 0xf50b, 0xf504, 0xf701, 0xf505, 0xf200,
- 0xf507, 0xf200, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf209,
+ 0xf506, 0xf507, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf209,
0xf210, 0xf200, 0xf200, 0xf600, 0xf211, 0xf81b, 0xf831, 0xf832,
0xf833, 0xf834, 0xf835, 0xf836, 0xf837, 0xf838, 0xf839, 0xf830,
0xf82d, 0xf83d, 0xf860, 0xf87f, 0xf115, 0xf200, 0xf30d, 0xf30c,
@@ -121,14 +121,14 @@ u_short alt_map[NR_KEYS] = {
u_short ctrl_alt_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf500, 0xf501, 0xf509,
- 0xf502, 0xf50a, 0xf503, 0xf50b, 0xf504, 0xf701, 0xf200, 0xf200,
- 0xf507, 0xf200, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf200,
+ 0xf502, 0xf50a, 0xf503, 0xf50b, 0xf504, 0xf701, 0xf505, 0xf200,
+ 0xf506, 0xf507, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf200,
0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c,
0xf200, 0xf200, 0xf20c, 0xf200, 0xf114, 0xf200, 0xf811, 0xf817,
0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, 0xf80f, 0xf810,
- 0xf200, 0xf200, 0xf200, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
+ 0xf200, 0xf200, 0xf20c, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf801, 0xf813, 0xf804,
0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, 0xf200,
0xf200, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
diff --git a/drivers/sbus/char/sunkeymap.map b/drivers/sbus/char/sunkeymap.map
index 734419108..7fa644d1e 100644
--- a/drivers/sbus/char/sunkeymap.map
+++ b/drivers/sbus/char/sunkeymap.map
@@ -44,18 +44,20 @@ keycode 0x0c = F5 F15 Console_17
alt keycode 0x0c = Console_5
control alt keycode 0x0c = Console_5
keycode 0x0d = AltGr
-keycode 0x0e = F6 F6
+keycode 0x0e = F6 F16 Console_18
+ control keycode 0x0e = F6
alt keycode 0x0e = Console_6
+ control alt keycode 0x0e = Console_6
# BLANK KEY on type 5 keyboards
keycode 0x0f =
keycode 0x10 = F7 F17 Console_19
- control Keycode 0x10 = F7
+ control keycode 0x10 = F7
alt keycode 0x10 = Console_7
control alt keycode 0x10 = Console_7
-keycode 0x11 = F8 F8 Console_20
- control keycode 0x10 = F8
- alt keycode 0x10 = Console_8
- control alt keycode 0x10 = Console_8
+keycode 0x11 = F8 F18 Console_20
+ control keycode 0x11 = F8
+ alt keycode 0x11 = Console_8
+ control alt keycode 0x11 = Console_8
keycode 0x12 = F9 F19 Console_21
control keycode 0x12 = F9
alt keycode 0x12 = Console_9
@@ -159,6 +161,7 @@ keycode 0x41 = bracketright braceright asciitilde
keycode 0x42 = Delete Delete
control keycode 0x42 = BackSpace
alt keycode 0x43 = Meta_Delete
+ control alt keycode 0x42 = Boot
keycode 0x43 = Compose
keycode 0x44 = KP_7
alt keycode 0x44 = Ascii_7
diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c
index 9b32cf59a..371fb3004 100644
--- a/drivers/sbus/char/sunmouse.c
+++ b/drivers/sbus/char/sunmouse.c
@@ -9,6 +9,7 @@
* Dec/19/95 Added SunOS mouse ioctls - miguel.
* Jan/5/96 Added VUID support, sigio support - miguel.
* Mar/5/96 Added proper mouse stream support - miguel.
+ * Sep/96 Allow more than one reader -miguel.
*/
/* The mouse is run off of one of the Zilog serial ports. On
@@ -31,7 +32,9 @@
* set when the device is opened and allows the application to see the
* mouse character stream as we get it from the serial (for gpm for
* example). The second method, VUID_FIRM_EVENT will provide cooked
- * events in Firm_event records.
+ * events in Firm_event records as expected by SunOS/Solaris applications.
+ *
+ * FIXME: We need to support more than one mouse.
* */
#include <linux/kernel.h>
@@ -42,7 +45,9 @@
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/vuid_event.h>
#include <linux/random.h>
@@ -129,11 +134,61 @@ push_char (char c)
wake_up_interruptible (&sunmouse.proc_list);
}
+/* Auto baud rate "detection". ;-) */
+static int mouse_bogon_bytes = 0;
+static int mouse_baud_changing = 0; /* For reporting things to the user. */
+static int mouse_baud = 4800; /* Initial rate set by zilog driver. */
+
+/* Change the baud rate after receiving too many "bogon bytes". */
+void sun_mouse_change_baud(void)
+{
+ extern void zs_change_mouse_baud(int newbaud);
+
+ if(mouse_baud == 1200)
+ mouse_baud = 4800;
+ else
+ mouse_baud = 1200;
+
+ zs_change_mouse_baud(mouse_baud);
+ mouse_baud_changing = 1;
+}
+
+void mouse_baud_detection(unsigned char c)
+{
+ static int wait_for_synchron = 1;
+ static int ctr = 0;
+
+ if(wait_for_synchron) {
+ if((c < 0x80) || (c > 0x87))
+ mouse_bogon_bytes++;
+ else {
+ ctr = 0;
+ wait_for_synchron = 0;
+ }
+ } else {
+ ctr++;
+ if(ctr >= 4) {
+ ctr = 0;
+ wait_for_synchron = 1;
+ if(mouse_baud_changing == 1) {
+ printk("sunmouse: Successfully adjusted to %d baud.\n",
+ mouse_baud);
+ mouse_baud_changing = 0;
+ }
+ }
+ }
+ if(mouse_bogon_bytes > 12) {
+ sun_mouse_change_baud();
+ mouse_bogon_bytes = 0;
+ wait_for_synchron = 1;
+ }
+}
+
/* The following is called from the zs driver when bytes are received on
* the Mouse zs8530 channel.
*/
void
-sun_mouse_inbyte(unsigned char byte, unsigned char status)
+sun_mouse_inbyte(unsigned char byte)
{
signed char mvalue;
int d;
@@ -143,12 +198,12 @@ sun_mouse_inbyte(unsigned char byte, unsigned char status)
if(!sunmouse.active)
return;
+ mouse_baud_detection(byte);
+
if (!gen_events){
push_char (byte);
return;
}
- /* Check for framing errors and parity errors */
- /* XXX TODO XXX */
/* If the mouse sends us a byte from 0x80 to 0x87
* we are starting at byte zero in the transaction
@@ -259,11 +314,10 @@ sun_mouse_inbyte(unsigned char byte, unsigned char status)
static int
sun_mouse_open(struct inode * inode, struct file * file)
{
+ if(sunmouse.active++)
+ return 0;
if(!sunmouse.present)
return -EINVAL;
- if(sunmouse.active)
- return -EBUSY;
- sunmouse.active = 1;
sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
sunmouse.button_state = 0x80;
sunmouse.vuid_mode = VUID_NATIVE;
@@ -281,23 +335,26 @@ sun_mouse_fasync (struct inode *inode, struct file *filp, int on)
return 0;
}
-static void
+static int
sun_mouse_close(struct inode *inode, struct file *file)
{
- sunmouse.active = sunmouse.ready = 0;
sun_mouse_fasync (inode, file, 0);
+ if (--sunmouse.active)
+ return 0;
+ sunmouse.ready = 0;
+ return 0;
}
-static int
+static long
sun_mouse_write(struct inode *inode, struct file *file, const char *buffer,
- int count)
+ unsigned long count)
{
return -EINVAL; /* foo on you */
}
-static int
+static long
sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
- int count)
+ unsigned long count)
{
struct wait_queue wait = { current, NULL };
@@ -316,7 +373,8 @@ sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
char *p = buffer, *end = buffer+count;
while (p < end && !queue_empty ()){
- *(Firm_event *)p = *get_from_queue ();
+ copy_to_user_ret((Firm_event *)p, get_from_queue(),
+ sizeof(Firm_event), -EFAULT);
p += sizeof (Firm_event);
}
sunmouse.ready = !queue_empty ();
@@ -325,11 +383,12 @@ sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
} else {
int c;
- for (c = count; !queue_empty () && c; c--){
- *buffer++ = sunmouse.queue.stream [sunmouse.tail];
+ for (c = count; !queue_empty() && c; c--){
+ put_user_ret(sunmouse.queue.stream[sunmouse.tail], buffer, -EFAULT);
+ buffer++;
sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
}
- sunmouse.ready = !queue_empty ();
+ sunmouse.ready = !queue_empty();
inode->i_atime = CURRENT_TIME;
return count-c;
}
@@ -339,15 +398,11 @@ sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
return 0;
}
-static int
-sun_mouse_select(struct inode *inode, struct file *file, int sel_type,
- select_table *wait)
+static unsigned int sun_mouse_poll(struct file *file, poll_table *wait)
{
- if(sel_type != SEL_IN)
- return 0;
+ poll_wait(&sunmouse.proc_list, wait);
if(sunmouse.ready)
- return 1;
- select_wait(&sunmouse.proc_list, wait);
+ return POLLIN | POLLRDNORM;
return 0;
}
int
@@ -358,22 +413,28 @@ sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsig
switch (cmd){
/* VUIDGFORMAT - Get input device byte stream format */
case _IOR('v', 2, int):
- i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (int));
- if (i) return i;
- *(int *)arg = sunmouse.vuid_mode;
+ put_user_ret(sunmouse.vuid_mode, (int *) arg, -EFAULT);
break;
/* VUIDSFORMAT - Set input device byte stream format*/
case _IOW('v', 1, int):
- i = verify_area (VERIFY_READ, (void *)arg, sizeof (int));
- if (i) return i;
- i = *(int *) arg;
+ get_user_ret(i, (int *) arg, -EFAULT);
if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){
- sunmouse.vuid_mode = *(int *)arg;
+ int value;
+
+ get_user_ret(value, (int *)arg, -EFAULT);
+ sunmouse.vuid_mode = value;
sunmouse.head = sunmouse.tail = 0;
} else
return -EINVAL;
break;
+
+ case 0x8024540b:
+ case 0x40245408:
+ /* This is a buggy application doing termios on the mouse driver */
+ /* we ignore it. I keep this check here so that we will notice */
+ /* future mouse vuid ioctls */
+ break;
default:
printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
@@ -387,7 +448,7 @@ struct file_operations sun_mouse_fops = {
sun_mouse_read,
sun_mouse_write,
NULL,
- sun_mouse_select,
+ sun_mouse_poll,
sun_mouse_ioctl,
NULL,
sun_mouse_open,
@@ -400,8 +461,7 @@ static struct miscdevice sun_mouse_mouse = {
SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
};
-int
-sun_mouse_init(void)
+__initfunc(int sun_mouse_init(void))
{
printk("Sun Mouse-Systems mouse driver version 1.00\n");
sunmouse.present = 1;
@@ -410,6 +470,7 @@ sun_mouse_init(void)
sunmouse.delta_x = sunmouse.delta_y = 0;
sunmouse.button_state = 0x80;
sunmouse.proc_list = NULL;
+ sunmouse.byte = 69;
return 0;
}
diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c
index ed1d75073..cd4fe4ee3 100644
--- a/drivers/sbus/char/sunserial.c
+++ b/drivers/sbus/char/sunserial.c
@@ -1,6 +1,9 @@
-/* serial.c: Serial port driver for the Sparc.
+/* $Id: sunserial.c,v 1.38 1997/04/14 17:05:00 jj Exp $
+ * serial.c: Serial port driver for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Fixes by Pete A. Zaitcev <zaitcev@ipmce.su>.
*/
#include <linux/errno.h>
@@ -16,37 +19,41 @@
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/kernel.h>
+#include <linux/init.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/oplib.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <asm/delay.h>
#include <asm/kdebug.h>
#include "sunserial.h"
-#define NUM_SERIAL 2 /* Two chips on board. */
+static int num_serial = 2; /* sun4/sun4c/sun4m - Two chips on board. */
+#define NUM_SERIAL num_serial
#define NUM_CHANNELS (NUM_SERIAL * 2)
#define KEYBOARD_LINE 0x2
#define MOUSE_LINE 0x3
-struct sun_zslayout *zs_chips[NUM_SERIAL] = { 0, 0, };
-struct sun_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, 0, 0, };
+extern struct wait_queue * keypress_wait;
+
+struct sun_zslayout **zs_chips;
+struct sun_zschannel **zs_channels;
struct sun_zschannel *zs_conschan;
struct sun_zschannel *zs_mousechan;
struct sun_zschannel *zs_kbdchan;
struct sun_zschannel *zs_kgdbchan;
-int zs_nodes[NUM_SERIAL] = { 0, 0, };
+int *zs_nodes;
-struct sun_serial zs_soft[NUM_CHANNELS];
+struct sun_serial *zs_soft;
struct sun_serial *zs_chain; /* IRQ servicing chain */
int zilog_irq;
-struct tty_struct zs_ttys[NUM_CHANNELS];
+struct tty_struct *zs_ttys;
/** struct tty_struct *zs_constty; **/
/* Console hooks... */
@@ -61,23 +68,39 @@ struct sun_serial *zs_consinfo = 0;
#define SUNKBD_UP 0x80
#define SUNKBD_A 0x4d
-extern void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs);
-extern void sun_mouse_inbyte(unsigned char byte, unsigned char status);
+extern void sunkbd_inchar(unsigned char ch, struct pt_regs *regs);
+extern void sun_mouse_inbyte(unsigned char byte);
static unsigned char kgdb_regs[16] = {
0, 0, 0, /* write 0, 1, 2 */
- (Rx8 | RxENABLE), /* write 3 */
+ (Rx8 | RxENAB), /* write 3 */
(X16CLK | SB1 | PAR_EVEN), /* write 4 */
- (Tx8 | TxENAB), /* write 5 */
+ (DTR | Tx8 | TxENAB), /* write 5 */
0, 0, 0, /* write 6, 7, 8 */
(NV), /* write 9 */
(NRZ), /* write 10 */
(TCBR | RCBR), /* write 11 */
0, 0, /* BRG time constant, write 12 + 13 */
- (BRSRC | BRENABL), /* write 14 */
+ (BRSRC | BRENAB), /* write 14 */
(DCDIE) /* write 15 */
};
+static unsigned char zscons_regs[16] = {
+ 0, /* write 0 */
+ (EXT_INT_ENAB | INT_ALL_Rx), /* write 1 */
+ 0, /* write 2 */
+ (Rx8 | RxENAB), /* write 3 */
+ (X16CLK), /* write 4 */
+ (DTR | Tx8 | TxENAB), /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ (NV | MIE), /* write 9 */
+ (NRZ), /* write 10 */
+ (TCBR | RCBR), /* write 11 */
+ 0, 0, /* BRG time constant, write 12 + 13 */
+ (BRSRC | BRENAB), /* write 14 */
+ (DCDIE | CTSIE | TxUIE | BRKIE) /* write 15 */
+};
+
#define ZS_CLOCK 4915200 /* Zilog input clock rate */
DECLARE_TASK_QUEUE(tq_serial);
@@ -106,9 +129,9 @@ static int serial_refcount;
static void change_speed(struct sun_serial *info);
-static struct tty_struct *serial_table[NUM_CHANNELS];
-static struct termios *serial_termios[NUM_CHANNELS];
-static struct termios *serial_termios_locked[NUM_CHANNELS];
+static struct tty_struct **serial_table;
+static struct termios **serial_termios;
+static struct termios **serial_termios_locked;
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -152,7 +175,7 @@ static inline int serial_paranoia_check(struct sun_serial *info,
*/
static int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 0 };
+ 9600, 19200, 38400, 76800, 0 };
/*
* Reading and writing Zilog8530 registers. The delays are to make this
@@ -160,7 +183,8 @@ static int baud_table[] = {
* register access, other machines handle this in hardware via auxiliary
* flip-flops which implement the settle time we do in software.
*/
-static inline unsigned char read_zsreg(struct sun_zschannel *channel, unsigned char reg)
+static inline unsigned char read_zsreg(struct sun_zschannel *channel,
+ unsigned char reg)
{
unsigned char retval;
@@ -171,48 +195,87 @@ static inline unsigned char read_zsreg(struct sun_zschannel *channel, unsigned c
return retval;
}
-static inline void write_zsreg(struct sun_zschannel *channel, unsigned char reg, unsigned char value)
+static inline void write_zsreg(struct sun_zschannel *channel,
+ unsigned char reg, unsigned char value)
{
channel->control = reg;
udelay(5);
channel->control = value;
udelay(5);
- return;
}
-static inline void load_zsregs(struct sun_zschannel *channel, unsigned char *regs)
+static inline void load_zsregs(struct sun_serial *info, unsigned char *regs)
{
+ unsigned long flags;
+ struct sun_zschannel *channel = info->zs_channel;
+ unsigned char stat;
+ int i;
+
+ for (i = 0; i < 1000; i++) {
+ stat = read_zsreg(channel, R1);
+ if (stat & ALL_SNT)
+ break;
+ udelay(100);
+ }
+ write_zsreg(channel, R3, 0);
+ ZS_CLEARSTAT(channel);
ZS_CLEARERR(channel);
ZS_CLEARFIFO(channel);
+
/* Load 'em up */
+ save_flags(flags); cli();
+ if (info->channelA)
+ write_zsreg(channel, R9, CHRA);
+ else
+ write_zsreg(channel, R9, CHRB);
+ udelay(20); /* wait for some old sun4's */
write_zsreg(channel, R4, regs[R4]);
- write_zsreg(channel, R10, regs[R10]);
- write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+ write_zsreg(channel, R3, regs[R3] & ~RxENAB);
write_zsreg(channel, R5, regs[R5] & ~TxENAB);
- write_zsreg(channel, R1, regs[R1]);
- write_zsreg(channel, R9, regs[R9]);
+ write_zsreg(channel, R9, regs[R9] & ~MIE);
+ write_zsreg(channel, R10, regs[R10]);
write_zsreg(channel, R11, regs[R11]);
write_zsreg(channel, R12, regs[R12]);
write_zsreg(channel, R13, regs[R13]);
+ write_zsreg(channel, R14, regs[R14] & ~BRENAB);
write_zsreg(channel, R14, regs[R14]);
- write_zsreg(channel, R15, regs[R15]);
+ write_zsreg(channel, R14, (regs[R14] & ~SNRZI) | BRENAB);
write_zsreg(channel, R3, regs[R3]);
write_zsreg(channel, R5, regs[R5]);
- return;
+ write_zsreg(channel, R15, regs[R15]);
+ write_zsreg(channel, R0, RES_EXT_INT);
+ write_zsreg(channel, R0, ERR_RES);
+ write_zsreg(channel, R1, regs[R1]);
+ write_zsreg(channel, R9, regs[R9]);
+ restore_flags(flags);
+}
+
+static inline void zs_put_char(struct sun_zschannel *channel, char ch)
+{
+ int loops = 0;
+
+ while((channel->control & Tx_BUF_EMP) == 0 && loops < 10000) {
+ loops++;
+ udelay(5);
+ }
+ channel->data = ch;
+ udelay(5);
}
/* Sets or clears DTR/RTS on the requested line */
static inline void zs_rtsdtr(struct sun_serial *ss, int set)
{
+ unsigned long flags;
+
+ save_flags(flags); cli();
if(set) {
ss->curregs[5] |= (RTS | DTR);
- ss->pendregs[5] = ss->curregs[5];
write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
} else {
ss->curregs[5] &= ~(RTS | DTR);
- ss->pendregs[5] = ss->curregs[5];
write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
}
+ restore_flags(flags);
return;
}
@@ -230,23 +293,7 @@ static inline void kgdb_chaninit(struct sun_serial *ss, int intson, int bps)
brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
kgdb_regs[R12] = (brg & 255);
kgdb_regs[R13] = ((brg >> 8) & 255);
- load_zsregs(ss->zs_channel, kgdb_regs);
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct sun_serial *ss)
-{
- struct sun_zschannel *channel = ss->zs_channel;
- int brg;
-
- /* The baud rate is split up between two 8-bit registers in
- * what is termed 'BRG time constant' format in my docs for
- * the chip, it is a function of the clk rate the chip is
- * receiving which happens to be constant.
- */
- brg = ((read_zsreg(channel, 13)&0xff) << 8);
- brg |= (read_zsreg(channel, 12)&0xff);
- return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+ load_zsregs(ss, kgdb_regs);
}
/*
@@ -268,7 +315,6 @@ static void rs_stop(struct tty_struct *tty)
save_flags(flags); cli();
if (info->curregs[5] & TxENAB) {
info->curregs[5] &= ~TxENAB;
- info->pendregs[5] &= ~TxENAB;
write_zsreg(info->zs_channel, 5, info->curregs[5]);
}
restore_flags(flags);
@@ -285,7 +331,6 @@ static void rs_start(struct tty_struct *tty)
save_flags(flags); cli();
if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
info->curregs[5] |= TxENAB;
- info->pendregs[5] = info->curregs[5];
write_zsreg(info->zs_channel, 5, info->curregs[5]);
}
restore_flags(flags);
@@ -307,7 +352,7 @@ static void batten_down_hatches(void)
(((unsigned long)linux_dbvec)<=DEBUG_LASTVADDR))
sp_enter_debugger();
else
- prom_halt();
+ prom_cmdline();
/* XXX We want to notify the keyboard driver that all
* XXX keys are in the up state or else weird things
@@ -317,14 +362,6 @@ static void batten_down_hatches(void)
return;
}
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct sun_zschannel *zsc)
-{
- zsc->control = ERR_RES;
- udelay(5);
- zsc->control = RES_H_IUS;
- udelay(5);
-}
/*
* ----------------------------------------------------------------------
@@ -355,7 +392,7 @@ static _INLINE_ void rs_sched_event(struct sun_serial *info,
int event)
{
info->event |= 1 << event;
- queue_task_irq_off(&info->tqueue, &tq_serial);
+ queue_task(&info->tqueue, &tq_serial);
mark_bh(SERIAL_BH);
}
@@ -366,116 +403,108 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs
struct tty_struct *tty = info->tty;
unsigned char ch, stat;
- ch = info->zs_channel->data;
- udelay(5);
- stat = read_zsreg(info->zs_channel, R1);
- udelay(5);
+ do {
+ ch = (info->zs_channel->data) & info->parity_mask;
+ udelay(5);
- /* If this is the console keyboard, we need to handle
- * L1-A's here.
- */
- if(info->cons_keyb) {
- if(ch == SUNKBD_RESET) {
- l1a_state.kbd_id = 1;
- l1a_state.l1_down = 0;
- } else if(l1a_state.kbd_id) {
- l1a_state.kbd_id = 0;
- } else if(ch == SUNKBD_L1) {
- l1a_state.l1_down = 1;
- } else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
- l1a_state.l1_down = 0;
- } else if(ch == SUNKBD_A && l1a_state.l1_down) {
- /* whee... */
- batten_down_hatches();
- /* Clear the line and continue execution... */
- rs_recv_clear(info->zs_channel);
- l1a_state.l1_down = 0;
- l1a_state.kbd_id = 0;
+ /* If this is the console keyboard, we need to handle
+ * L1-A's here.
+ */
+ if(info->cons_keyb) {
+ if(ch == SUNKBD_RESET) {
+ l1a_state.kbd_id = 1;
+ l1a_state.l1_down = 0;
+ } else if(l1a_state.kbd_id) {
+ l1a_state.kbd_id = 0;
+ } else if(ch == SUNKBD_L1) {
+ l1a_state.l1_down = 1;
+ } else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
+ l1a_state.l1_down = 0;
+ } else if(ch == SUNKBD_A && l1a_state.l1_down) {
+ /* whee... */
+ batten_down_hatches();
+ /* Continue execution... */
+ l1a_state.l1_down = 0;
+ l1a_state.kbd_id = 0;
+ return;
+ }
+ sunkbd_inchar(ch, regs);
return;
}
- rs_recv_clear(info->zs_channel);
- sunkbd_inchar(ch, stat, regs);
-
- return;
- }
- if(info->cons_mouse) {
- rs_recv_clear(info->zs_channel);
- sun_mouse_inbyte(ch, stat);
- return;
- }
- if(info->is_cons) {
- if(ch==0) { /* whee, break received */
- batten_down_hatches();
- rs_recv_clear(info->zs_channel);
- return;
- } else if (ch == 1) {
- show_state();
+ if(info->cons_mouse) {
+ sun_mouse_inbyte(ch);
return;
- } else if (ch == 2) {
- show_buffers();
+ }
+ if(info->is_cons) {
+ if(ch==0) {
+ /* whee, break received */
+ batten_down_hatches();
+ /* Continue execution... */
+ return;
+#if 0
+ } else if (ch == 1) {
+ show_state();
+ return;
+ } else if (ch == 2) {
+ show_buffers();
+ return;
+#endif
+ }
+ /* It is a 'keyboard interrupt' ;-) */
+ wake_up(&keypress_wait);
+ }
+ /* Look for kgdb 'stop' character, consult the gdb
+ * documentation for remote target debugging and
+ * arch/sparc/kernel/sparc-stub.c to see how all this works.
+ */
+ if((info->kgdb_channel) && (ch =='\003')) {
+ breakpoint();
return;
}
- /* It is a 'keyboard interrupt' ;-) */
- wake_up(&keypress_wait);
- }
- /* Look for kgdb 'stop' character, consult the gdb documentation
- * for remote target debugging and arch/sparc/kernel/sparc-stub.c
- * to see how all this works.
- */
- if((info->kgdb_channel) && (ch =='\003')) {
- breakpoint();
- goto clear_and_exit;
- }
- if(!tty)
- goto clear_and_exit;
+ if(!tty)
+ return;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
- tty->flip.count++;
- if(stat & PAR_ERR)
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
- else if(stat & Rx_OVR)
- *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
- else if(stat & CRC_ERR)
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
- else
- *tty->flip.flag_buf_ptr++ = 0; /* XXX */
- *tty->flip.char_buf_ptr++ = ch;
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ break;
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = 0;
+ *tty->flip.char_buf_ptr++ = ch;
-clear_and_exit:
- rs_recv_clear(info->zs_channel);
- return;
+ /* Check if we have another character... */
+ stat = info->zs_channel->control;
+ udelay(5);
+ if (!(stat & Rx_CH_AV))
+ break;
+
+ /* ... and see if it is clean. */
+ stat = read_zsreg(info->zs_channel, R1);
+ } while (!(stat & (PAR_ERR | Rx_OVR | CRC_ERR)));
+
+ queue_task(&tty->flip.tqueue, &tq_timer);
}
static _INLINE_ void transmit_chars(struct sun_serial *info)
{
- /* P3: In theory we have to test readiness here because a
- * serial console can clog the chip through rs_put_char().
- * David did not do this. I think he relies on 3-chars FIFO in 8530.
- * Let's watch for lost _output_ characters. XXX
- */
+ struct tty_struct *tty = info->tty;
if (info->x_char) {
/* Send next char */
- info->zs_channel->data = info->x_char;
- udelay(5);
+ zs_put_char(info->zs_channel, info->x_char);
info->x_char = 0;
- goto clear_and_return;
+ return;
}
- if((info->xmit_cnt <= 0) || info->tty->stopped) {
+ if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) {
/* That's peculiar... */
info->zs_channel->control = RES_Tx_P;
udelay(5);
- goto clear_and_return;
+ return;
}
/* Send char */
- info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
- udelay(5);
+ zs_put_char(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt--;
@@ -485,14 +514,7 @@ static _INLINE_ void transmit_chars(struct sun_serial *info)
if(info->xmit_cnt <= 0) {
info->zs_channel->control = RES_Tx_P;
udelay(5);
- goto clear_and_return;
}
-
-clear_and_return:
- /* Clear interrupt */
- info->zs_channel->control = RES_H_IUS;
- udelay(5);
- return;
}
static _INLINE_ void status_handle(struct sun_serial *info)
@@ -505,22 +527,17 @@ static _INLINE_ void status_handle(struct sun_serial *info)
/* Clear status condition... */
info->zs_channel->control = RES_EXT_INT;
udelay(5);
- /* Clear the interrupt */
- info->zs_channel->control = RES_H_IUS;
- udelay(5);
#if 0
if(status & DCD) {
if((info->tty->termios->c_cflag & CRTSCTS) &&
((info->curregs[3] & AUTO_ENAB)==0)) {
info->curregs[3] |= AUTO_ENAB;
- info->pendregs[3] |= AUTO_ENAB;
write_zsreg(info->zs_channel, 3, info->curregs[3]);
}
} else {
if((info->curregs[3] & AUTO_ENAB)) {
info->curregs[3] &= ~AUTO_ENAB;
- info->pendregs[3] &= ~AUTO_ENAB;
write_zsreg(info->zs_channel, 3, info->curregs[3]);
}
}
@@ -538,79 +555,107 @@ static _INLINE_ void status_handle(struct sun_serial *info)
return;
}
-/*
- * This is the serial driver's generic interrupt routine
- */
-void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static _INLINE_ void special_receive(struct sun_serial *info)
{
- struct sun_serial * info;
- unsigned char zs_intreg;
+ struct tty_struct *tty = info->tty;
+ unsigned char ch, stat;
- info = zs_chain;
- if (!info)
- return;
+ stat = read_zsreg(info->zs_channel, R1);
+ if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+ ch = info->zs_channel->data;
+ udelay(5);
+ }
- zs_intreg = read_zsreg(info->zs_channel, 3);
+ if (!tty)
+ goto clear;
- /* NOTE: The read register 3, which holds the irq status,
- * does so for both channels on each chip. Although
- * the status value itself must be read from the A
- * channel and is only valid when read from channel A.
- * Yes... broken hardware...
- */
-#define CHAN_A_IRQMASK (CHARxIP | CHATxIP | CHAEXT)
-#define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto done;
- /* *** Chip 1 *** */
- /* Channel A -- /dev/ttya, could be the console */
- if(zs_intreg & CHAN_A_IRQMASK) {
- if (zs_intreg & CHARxIP)
- receive_chars(info, regs);
- if (zs_intreg & CHATxIP)
- transmit_chars(info);
- if (zs_intreg & CHAEXT)
- status_handle(info);
- }
+ tty->flip.count++;
+ if(stat & PAR_ERR)
+ *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+ else if(stat & Rx_OVR)
+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ else if(stat & CRC_ERR)
+ *tty->flip.flag_buf_ptr++ = TTY_FRAME;
- info=info->zs_next;
+done:
+ queue_task(&tty->flip.tqueue, &tq_timer);
+clear:
+ info->zs_channel->control = ERR_RES;
+ udelay(5);
+}
- /* Channel B -- /dev/ttyb, could be the console */
- if(zs_intreg & CHAN_B_IRQMASK) {
- if (zs_intreg & CHBRxIP)
- receive_chars(info, regs);
- if (zs_intreg & CHBTxIP)
- transmit_chars(info);
- if (zs_intreg & CHBEXT)
- status_handle(info);
- }
- info = info->zs_next;
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct sun_serial *info;
+ unsigned char zs_intreg;
+ int i;
+
+ info = (struct sun_serial *)dev_id;
+ for (i = 0; i < NUM_SERIAL; i++) {
+ zs_intreg = read_zsreg(info->zs_next->zs_channel, 2);
+ zs_intreg &= STATUS_MASK;
+
+ /* NOTE: The read register 2, which holds the irq status,
+ * does so for both channels on each chip. Although
+ * the status value itself must be read from the B
+ * channel and is only valid when read from channel B.
+ * When read from channel A, read register 2 contains
+ * the value written to write register 2.
+ */
- zs_intreg = read_zsreg(info->zs_channel, 3);
- /* *** Chip 2 *** */
- /* Channel A -- /dev/kbd, pass communication to keyboard driver */
- if(zs_intreg & CHAN_A_IRQMASK) {
- if (zs_intreg & CHARxIP)
+ /* Channel A -- /dev/ttya or /dev/kbd, could be the console */
+ if (zs_intreg == CHA_Rx_AVAIL) {
receive_chars(info, regs);
- if (zs_intreg & CHATxIP)
+ return;
+ }
+ if(zs_intreg == CHA_Tx_EMPTY) {
transmit_chars(info);
- if (zs_intreg & CHAEXT)
+ return;
+ }
+ if (zs_intreg == CHA_EXT_STAT) {
status_handle(info);
- }
+ return;
+ }
+ if (zs_intreg == CHA_SPECIAL) {
+ special_receive(info);
+ return;
+ }
+
+ /* Channel B -- /dev/ttyb or /dev/mouse, could be the console */
+ if(zs_intreg == CHB_Rx_AVAIL) {
+ receive_chars(info->zs_next, regs);
+ return;
+ }
+ if(zs_intreg == CHB_Tx_EMPTY) {
+ transmit_chars(info->zs_next);
+ return;
+ }
+ if (zs_intreg == CHB_EXT_STAT) {
+ status_handle(info->zs_next);
+ return;
+ }
- info=info->zs_next;
+ /* NOTE: The default value for the IRQ status in read register
+ * 2 in channel B is CHB_SPECIAL, so we need to look at
+ * read register 3 in channel A to check if this is a
+ * real interrupt, or just the default value.
+ * Yes... broken hardware...
+ */
- /* Channel B -- /dev/mouse, pass communication to mouse driver */
- if(zs_intreg & CHAN_B_IRQMASK) {
- if (zs_intreg & CHBRxIP)
- receive_chars(info, regs);
- if (zs_intreg & CHBTxIP)
- transmit_chars(info);
- if (zs_intreg & CHBEXT)
- status_handle(info);
+ zs_intreg = read_zsreg(info->zs_channel, 3);
+ if (zs_intreg & CHBRxIP) {
+ special_receive(info->zs_next);
+ return;
+ }
+ info = info->zs_next->zs_next;
}
-
- return;
}
/*
@@ -667,6 +712,10 @@ static void do_serial_hangup(void *private_)
tty = info->tty;
if (!tty)
return;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("do_serial_hangup<%p: tty-%d\n",
+ __builtin_return_address(0), info->line);
+#endif
tty_hangup(tty);
}
@@ -701,7 +750,7 @@ static int startup(struct sun_serial * info)
save_flags(flags); cli();
#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttys%d (irq %d)...", info->line, info->irq);
+ printk("Starting up tty-%d (irq %d)...\n", info->line, info->irq);
#endif
/*
@@ -727,15 +776,12 @@ static int startup(struct sun_serial * info)
/*
* Finally, enable sequencing and interrupts
*/
- info->curregs[1] |= (info->curregs[1] & ~0x18) | (EXT_INT_ENAB|INT_ALL_Rx);
- info->pendregs[1] = info->curregs[1];
- info->curregs[3] |= (RxENABLE | Rx8);
- info->pendregs[3] = info->curregs[3];
+ info->curregs[1] |= (info->curregs[1] & ~(RxINT_MASK)) |
+ (EXT_INT_ENAB | INT_ALL_Rx);
+ info->curregs[3] |= (RxENAB | Rx8);
/* We enable Tx interrupts as needed. */
info->curregs[5] |= (TxENAB | Tx8);
- info->pendregs[5] = info->curregs[5];
info->curregs[9] |= (NV | MIE);
- info->pendregs[9] = info->curregs[9];
write_zsreg(info->zs_channel, 3, info->curregs[3]);
write_zsreg(info->zs_channel, 5, info->curregs[5]);
write_zsreg(info->zs_channel, 9, info->curregs[9]);
@@ -808,6 +854,7 @@ static void change_speed(struct sun_serial *info)
{
unsigned short port;
unsigned cflag;
+ int quot = 0;
int i;
int brg;
@@ -817,57 +864,76 @@ static void change_speed(struct sun_serial *info)
if (!(port = info->port))
return;
i = cflag & CBAUD;
- if (i & CBAUDEX) {
- /* XXX CBAUDEX is not obeyed.
- * It is impossible at a 32bits SPARC.
- * But we have to report this to user ... someday.
- */
- i = B9600;
+ if (cflag & CBAUDEX) {
+ i &= ~CBAUDEX;
+ if (i != 1)
+ info->tty->termios->c_cflag &= ~CBAUDEX;
+ else
+ i += 15;
+ }
+ if (i == 15) {
+ if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_HI)
+ i += 1;
+ if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_CUST)
+ quot = info->custom_divisor;
+ }
+ if (quot) {
+ info->zs_baud = info->baud_base / quot;
+ info->clk_divisor = 16;
+
+ info->curregs[4] = X16CLK;
+ info->curregs[11] = TCBR | RCBR;
+ brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+ info->curregs[12] = (brg & 255);
+ info->curregs[13] = ((brg >> 8) & 255);
+ info->curregs[14] = BRSRC | BRENAB;
+ zs_rtsdtr(info, 1);
+ } else if (baud_table[i]) {
+ info->zs_baud = baud_table[i];
+ info->clk_divisor = 16;
+
+ info->curregs[4] = X16CLK;
+ info->curregs[11] = TCBR | RCBR;
+ brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+ info->curregs[12] = (brg & 255);
+ info->curregs[13] = ((brg >> 8) & 255);
+ info->curregs[14] = BRSRC | BRENAB;
+ zs_rtsdtr(info, 1);
+ } else {
+ zs_rtsdtr(info, 0);
+ return;
}
- info->zs_baud = baud_table[i];
- info->clk_divisor = 16;
-
- info->curregs[4] = X16CLK;
- info->curregs[11] = TCBR | RCBR;
- brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
- info->curregs[12] = (brg & 255);
- info->curregs[13] = ((brg >> 8) & 255);
- info->curregs[14] = BRSRC | BRENABL;
/* byte size and parity */
switch (cflag & CSIZE) {
case CS5:
- info->curregs[3] &= ~(0xc0);
+ info->curregs[3] &= ~(RxN_MASK);
info->curregs[3] |= Rx5;
- info->pendregs[3] = info->curregs[3];
- info->curregs[5] &= ~(0xe0);
+ info->curregs[5] &= ~(TxN_MASK);
info->curregs[5] |= Tx5;
- info->pendregs[5] = info->curregs[5];
+ info->parity_mask = 0x1f;
break;
case CS6:
- info->curregs[3] &= ~(0xc0);
+ info->curregs[3] &= ~(RxN_MASK);
info->curregs[3] |= Rx6;
- info->pendregs[3] = info->curregs[3];
- info->curregs[5] &= ~(0xe0);
+ info->curregs[5] &= ~(TxN_MASK);
info->curregs[5] |= Tx6;
- info->pendregs[5] = info->curregs[5];
+ info->parity_mask = 0x3f;
break;
case CS7:
- info->curregs[3] &= ~(0xc0);
+ info->curregs[3] &= ~(RxN_MASK);
info->curregs[3] |= Rx7;
- info->pendregs[3] = info->curregs[3];
- info->curregs[5] &= ~(0xe0);
+ info->curregs[5] &= ~(TxN_MASK);
info->curregs[5] |= Tx7;
- info->pendregs[5] = info->curregs[5];
+ info->parity_mask = 0x7f;
break;
case CS8:
default: /* defaults to 8 bits */
- info->curregs[3] &= ~(0xc0);
+ info->curregs[3] &= ~(RxN_MASK);
info->curregs[3] |= Rx8;
- info->pendregs[3] = info->curregs[3];
- info->curregs[5] &= ~(0xe0);
+ info->curregs[5] &= ~(TxN_MASK);
info->curregs[5] |= Tx8;
- info->pendregs[5] = info->curregs[5];
+ info->parity_mask = 0xff;
break;
}
info->curregs[4] &= ~(0x0c);
@@ -876,24 +942,19 @@ static void change_speed(struct sun_serial *info)
} else {
info->curregs[4] |= SB1;
}
- info->pendregs[4] = info->curregs[4];
if (cflag & PARENB) {
- info->curregs[4] |= PAR_ENA;
- info->pendregs[4] |= PAR_ENA;
+ info->curregs[4] |= PAR_ENAB;
} else {
- info->curregs[4] &= ~PAR_ENA;
- info->pendregs[4] &= ~PAR_ENA;
+ info->curregs[4] &= ~PAR_ENAB;
}
if (!(cflag & PARODD)) {
info->curregs[4] |= PAR_EVEN;
- info->pendregs[4] |= PAR_EVEN;
} else {
info->curregs[4] &= ~PAR_EVEN;
- info->pendregs[4] &= ~PAR_EVEN;
}
/* Load up the new values */
- load_zsregs(info->zs_channel, info->curregs);
+ load_zsregs(info, info->curregs);
return;
}
@@ -904,38 +965,26 @@ static void change_speed(struct sun_serial *info)
void kbd_put_char(unsigned char ch)
{
struct sun_zschannel *chan = zs_kbdchan;
- int flags, loops = 0;
+ unsigned long flags;
if(!chan)
return;
save_flags(flags); cli();
- while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
- loops++;
- udelay(5);
- }
-
- chan->data = ch;
- udelay(5);
+ zs_put_char(chan, ch);
restore_flags(flags);
}
void mouse_put_char(char ch)
{
struct sun_zschannel *chan = zs_mousechan;
- int flags, loops = 0;
+ unsigned long flags;
if(!chan)
return;
save_flags(flags); cli();
- while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
- loops++;
- udelay(5);
- }
-
- chan->data = ch;
- udelay(5);
+ zs_put_char(chan, ch);
restore_flags(flags);
}
@@ -944,19 +993,13 @@ void mouse_put_char(char ch)
static void rs_put_char(char ch)
{
struct sun_zschannel *chan = zs_conschan;
- int flags, loops = 0;
+ unsigned long flags;
if(!chan)
return;
save_flags(flags); cli();
- while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
- loops++;
- udelay(5);
- }
-
- chan->data = ch;
- udelay(5);
+ zs_put_char(chan, ch);
restore_flags(flags);
}
@@ -969,7 +1012,6 @@ void putDebugChar(char kgdb_char)
while((chan->control & Tx_BUF_EMP)==0)
udelay(5);
-
chan->data = kgdb_char;
}
@@ -1005,7 +1047,7 @@ static void rs_fair_output(void)
rs_put_char(c);
- save_flags(flags); cli();
+ cli();
left = MIN(info->xmit_cnt, left-1);
}
@@ -1051,10 +1093,8 @@ static void rs_flush_chars(struct tty_struct *tty)
/* Enable transmitter */
save_flags(flags); cli();
info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
- info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
write_zsreg(info->zs_channel, 1, info->curregs[1]);
info->curregs[5] |= TxENAB;
- info->pendregs[5] |= TxENAB;
write_zsreg(info->zs_channel, 5, info->curregs[5]);
/*
@@ -1064,13 +1104,10 @@ static void rs_flush_chars(struct tty_struct *tty)
* but resets interrupts also what we do not desire here.
* XXX Discuss with David.
*/
- if (info->zs_channel->control & Tx_BUF_EMP) {
- /* Send char */
- info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
- udelay(5);
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- }
+ zs_put_char(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+
restore_flags(flags);
}
@@ -1084,7 +1121,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
if (serial_paranoia_check(info, tty->device, "rs_write"))
return 0;
- if (!tty || !info->xmit_buf)
+ if (!info || !info->xmit_buf)
return 0;
save_flags(flags);
@@ -1097,7 +1134,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
if (from_user) {
down(&tmp_buf_sem);
- memcpy_fromfs(tmp_buf, buf, c);
+ copy_from_user(tmp_buf, buf, c);
c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
@@ -1111,16 +1148,22 @@ static int rs_write(struct tty_struct * tty, int from_user,
count -= c;
total += c;
}
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
- !(info->curregs[5] & TxENAB)) {
+
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
/* Enable transmitter */
info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
- info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
write_zsreg(info->zs_channel, 1, info->curregs[1]);
info->curregs[5] |= TxENAB;
- info->pendregs[5] |= TxENAB;
write_zsreg(info->zs_channel, 5, info->curregs[5]);
}
+#if 1
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+ zs_put_char(info->zs_channel,
+ info->xmit_buf[info->xmit_tail++]);
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+ }
+#endif
restore_flags(flags);
return total;
}
@@ -1189,7 +1232,6 @@ static void rs_throttle(struct tty_struct * tty)
/* Turn off RTS line */
cli();
info->curregs[5] &= ~RTS;
- info->pendregs[5] &= ~RTS;
write_zsreg(info->zs_channel, 5, info->curregs[5]);
sti();
}
@@ -1217,7 +1259,6 @@ static void rs_unthrottle(struct tty_struct * tty)
/* Assert RTS line */
cli();
info->curregs[5] |= RTS;
- info->pendregs[5] |= RTS;
write_zsreg(info->zs_channel, 5, info->curregs[5]);
sti();
}
@@ -1245,7 +1286,7 @@ static int get_serial_info(struct sun_serial * info,
tmp.close_delay = info->close_delay;
tmp.closing_wait = info->closing_wait;
tmp.custom_divisor = info->custom_divisor;
- memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
+ copy_to_user_ret(retinfo,&tmp,sizeof(*retinfo), -EFAULT);
return 0;
}
@@ -1256,9 +1297,8 @@ static int set_serial_info(struct sun_serial * info,
struct sun_serial old_info;
int retval = 0;
- if (!new_info)
+ if (!new_info || copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
- memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
old_info = *info;
if (!suser()) {
@@ -1285,6 +1325,7 @@ static int set_serial_info(struct sun_serial * info,
info->baud_base = new_serial.baud_base;
info->flags = ((info->flags & ~ZILOG_FLAGS) |
(new_serial.flags & ZILOG_FLAGS));
+ info->custom_divisor = new_serial.custom_divisor;
info->type = new_serial.type;
info->close_delay = new_serial.close_delay;
info->closing_wait = new_serial.closing_wait;
@@ -1311,7 +1352,57 @@ static int get_lsr_info(struct sun_serial * info, unsigned int *value)
cli();
status = info->zs_channel->control;
sti();
- put_user(status,value);
+ put_user_ret(status,value, -EFAULT);
+ return 0;
+}
+
+static int get_modem_info(struct sun_serial * info, unsigned int *value)
+{
+ unsigned char status;
+ unsigned int result;
+
+ cli();
+ status = info->zs_channel->control;
+ sti();
+ result = ((info->curregs[5] & RTS) ? TIOCM_RTS : 0)
+ | ((info->curregs[5] & DTR) ? TIOCM_DTR : 0)
+ | ((status & DCD) ? TIOCM_CAR : 0)
+ | ((status & SYNC) ? TIOCM_DSR : 0)
+ | ((status & CTS) ? TIOCM_CTS : 0);
+ put_user_ret(result, value, -EFAULT);
+ return 0;
+}
+
+static int set_modem_info(struct sun_serial * info, unsigned int cmd,
+ unsigned int *value)
+{
+ unsigned int arg;
+
+ get_user_ret(arg, value, -EFAULT);
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS)
+ info->curregs[5] |= RTS;
+ if (arg & TIOCM_DTR)
+ info->curregs[5] |= DTR;
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS)
+ info->curregs[5] &= ~RTS;
+ if (arg & TIOCM_DTR)
+ info->curregs[5] &= ~DTR;
+ break;
+ case TIOCMSET:
+ info->curregs[5] = ((info->curregs[5] & ~(RTS | DTR))
+ | ((arg & TIOCM_RTS) ? RTS : 0)
+ | ((arg & TIOCM_DTR) ? DTR : 0));
+ break;
+ default:
+ return -EINVAL;
+ }
+ cli();
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ sti();
return 0;
}
@@ -1334,7 +1425,6 @@ static void send_break( struct sun_serial * info, int duration)
static int rs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int error;
struct sun_serial * info = (struct sun_serial *)tty->driver_data;
int retval;
@@ -1365,44 +1455,33 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
send_break(info, arg ? arg*(HZ/10) : HZ/4);
return 0;
case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned int *) arg);
+ put_user_ret(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long *) arg, -EFAULT);
+ return 0;
case TIOCSSOFTCAR:
- {
- unsigned int value;
- retval = get_user(value, (unsigned int *) arg);
- if (retval)
- return retval;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (value ? CLOCAL : 0));
- }
+ get_user_ret(arg, (unsigned long *) arg, -EFAULT);
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
return 0;
+ case TIOCMGET:
+ return get_modem_info(info, (unsigned int *) arg);
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return set_modem_info(info, cmd, (unsigned int *) arg);
case TIOCGSERIAL:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct serial_struct));
- if (error)
- return error;
return get_serial_info(info,
(struct serial_struct *) arg);
case TIOCSSERIAL:
return set_serial_info(info,
(struct serial_struct *) arg);
case TIOCSERGETLSR: /* Get line status register */
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
- if (error)
- return error;
- else
- return get_lsr_info(info, (unsigned int *) arg);
+ return get_lsr_info(info, (unsigned int *) arg);
case TIOCSERGSTRUCT:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct sun_serial));
- if (error)
- return error;
- memcpy_tofs((struct sun_serial *) arg,
- info, sizeof(struct sun_serial));
+ copy_to_user_ret((struct sun_serial *) arg,
+ info, sizeof(struct sun_serial), -EFAULT);
return 0;
default:
@@ -1453,7 +1532,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
}
#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+ printk("rs_close tty-%d, count = %d\n", info->line, info->count);
#endif
if ((tty->count == 1) && (info->count != 1)) {
/*
@@ -1499,11 +1578,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
* line status register.
*/
/** if (!info->iscons) ... **/
- info->curregs[3] &= ~RxENABLE;
- info->pendregs[3] = info->curregs[3];
+ info->curregs[3] &= ~RxENAB;
write_zsreg(info->zs_channel, 3, info->curregs[3]);
- info->curregs[1] &= ~(0x18);
- info->pendregs[1] = info->curregs[1];
+ info->curregs[1] &= ~(RxINT_MASK);
write_zsreg(info->zs_channel, 1, info->curregs[1]);
ZS_CLEARFIFO(info->zs_channel);
@@ -1534,6 +1611,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
ZILOG_CLOSING);
wake_up_interruptible(&info->close_wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_close tty-%d exiting, count = %d\n", info->line, info->count);
+#endif
restore_flags(flags);
}
@@ -1547,6 +1627,11 @@ void rs_hangup(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_hangup"))
return;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_hangup<%p: tty-%d, count = %d bye\n",
+ __builtin_return_address(0), info->line, info->count);
+#endif
+
rs_flush_buffer(tty);
shutdown(info);
info->event = 0;
@@ -1567,6 +1652,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
struct wait_queue wait = { current, NULL };
int retval;
int do_clocal = 0;
+ unsigned char r0;
/*
* If the device is in the middle of being closed, then block
@@ -1636,7 +1722,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready before block: ttys%d, count = %d\n",
info->line, info->count);
#endif
- info->count--;
+ cli();
+ if(!tty_hung_up_p(filp))
+ info->count--;
+ sti();
info->blocked_open++;
while (1) {
cli();
@@ -1646,6 +1735,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) ||
!(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready hup-ed: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
#ifdef SERIAL_DO_RESTART
if (info->flags & ZILOG_HUP_NOTIFY)
retval = -EAGAIN;
@@ -1656,8 +1749,13 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
#endif
break;
}
+
+ cli();
+ r0 = read_zsreg(info->zs_channel, R0);
+ sti();
if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
- !(info->flags & ZILOG_CLOSING) && do_clocal)
+ !(info->flags & ZILOG_CLOSING) &&
+ (do_clocal || (DCD & r0)))
break;
if (current->signal & ~current->blocked) {
retval = -ERESTARTSYS;
@@ -1713,6 +1811,11 @@ int rs_open(struct tty_struct *tty, struct file * filp)
printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
info->count);
#endif
+ if (info->tty != 0 && info->tty != tty) {
+ /* Never happen? */
+ printk("rs_open %s%d, tty overwrite.\n", tty->driver.name, info->line);
+ return -EBUSY;
+ }
info->count++;
tty->driver_data = info;
info->tty = tty;
@@ -1754,16 +1857,28 @@ int rs_open(struct tty_struct *tty, struct file * filp)
static void show_serial_version(void)
{
- printk("Sparc Zilog8530 serial driver version 1.00\n");
+ char *revision = "$Revision: 1.38 $";
+ char *version, *p;
+
+ version = strchr(revision, ' ');
+ p = strchr(++version, ' ');
+ *p = '\0';
+ printk("Sparc Zilog8530 serial driver version %s\n", version);
+ *p = ' ';
}
-/* Probe the PROM for the request zs chip number. */
-static inline struct sun_zslayout *get_zs(int chip)
+/* Probe the PROM for the request zs chip number.
+ *
+ * Note: The Sun Voyager shows two addresses and two intr for it's
+ * Zilogs, what the second does, I don't know. It does work
+ * with using only the first number of each property.
+ */
+static struct sun_zslayout *get_zs(int chip)
{
- struct linux_prom_irqs tmp_irq;
- unsigned long paddr = 0;
- unsigned long vaddr = 0;
- int zsnode, tmpnode, iospace, slave;
+ struct linux_prom_irqs tmp_irq[2];
+ unsigned int paddr = 0;
+ unsigned int vaddr[2] = { 0, 0 };
+ int zsnode, tmpnode, iospace, slave, len, seen, sun4u_irq;
static int irq = 0;
#if CONFIG_AP1000
@@ -1789,54 +1904,265 @@ static inline struct sun_zslayout *get_zs(int chip)
zs_nodes[chip] = 0;
if(!irq)
zilog_irq = irq = 12;
- vaddr = (unsigned long)
- sparc_alloc_io((char *) paddr, 0, 8,
- "Zilog Serial", iospace, 0);
+ vaddr[0] = (unsigned long)
+ sparc_alloc_io(paddr, 0, 8,
+ "Zilog Serial", iospace, 0);
} else {
/* Can use the prom for other machine types */
zsnode = prom_getchild(prom_root_node);
- tmpnode = prom_searchsiblings(zsnode, "obio");
- if(tmpnode)
- zsnode = prom_getchild(tmpnode);
+ if (sparc_cpu_model == sun4d) {
+ int board, node;
+
+ tmpnode = zsnode;
+ while (tmpnode && (tmpnode = prom_searchsiblings(tmpnode, "cpu-unit"))) {
+ board = prom_getintdefault (tmpnode, "board#", -1);
+ if (board == (chip >> 1)) {
+ node = prom_getchild(tmpnode);
+ if (node && (node = prom_searchsiblings(node, "bootbus"))) {
+ zsnode = node;
+ break;
+ }
+ }
+ tmpnode = prom_getsibling(tmpnode);
+ }
+ if (!tmpnode)
+ panic ("get_zs: couldn't find board%d's bootbus\n", chip >> 1);
+ } else if (sparc_cpu_model == sun4u) {
+ tmpnode = prom_searchsiblings(zsnode, "sbus");
+ if(tmpnode)
+ zsnode = prom_getchild(tmpnode);
+ } else {
+ tmpnode = prom_searchsiblings(zsnode, "obio");
+ if(tmpnode)
+ zsnode = prom_getchild(tmpnode);
+ }
if(!zsnode)
panic("get_zs no zs serial prom node");
+ seen = 0;
while(zsnode) {
zsnode = prom_searchsiblings(zsnode, "zs");
slave = prom_getintdefault(zsnode, "slave", -1);
- if(slave==chip) {
+ if((slave == chip) ||
+ (sparc_cpu_model == sun4u && seen == chip)) {
/* The one we want */
- vaddr = (unsigned long)
- prom_getintdefault(zsnode, "address",
- 0xdeadbeef);
- if(vaddr == 0xdeadbeef)
- prom_halt();
+ len = prom_getproperty(zsnode, "address",
+ (void *) vaddr,
+ sizeof(vaddr));
+ if (len % sizeof(unsigned int)) {
+ prom_printf("WHOOPS: proplen for %s "
+ "was %d, need multiple of "
+ "%d\n", "address", len,
+ sizeof(unsigned int));
+ panic("zilog: address property");
+ }
zs_nodes[chip] = zsnode;
- prom_getproperty(zsnode, "intr",
- (char *) &tmp_irq,
- sizeof(tmp_irq));
-#ifdef OLD_STYLE_IRQ
- tmp_irq.pri &= 0xf;
-#endif
+ if(sparc_cpu_model == sun4u) {
+ len = prom_getproperty(zsnode, "interrupts",
+ (char *) &sun4u_irq,
+ sizeof(tmp_irq));
+ tmp_irq[0].pri = sun4u_irq;
+ } else {
+ len = prom_getproperty(zsnode, "intr",
+ (char *) tmp_irq,
+ sizeof(tmp_irq));
+ if (len % sizeof(struct linux_prom_irqs)) {
+ prom_printf(
+ "WHOOPS: proplen for %s "
+ "was %d, need multiple of "
+ "%d\n", "address", len,
+ sizeof(struct linux_prom_irqs));
+ panic("zilog: address property");
+ }
+ }
if(!irq) {
- irq = zilog_irq = tmp_irq.pri;
+ irq = zilog_irq = tmp_irq[0].pri;
} else {
- if(tmp_irq.pri != irq)
+ if(tmp_irq[0].pri != irq)
panic("zilog: bogon irqs");
}
break;
}
zsnode = prom_getsibling(zsnode);
+ seen++;
}
if(!zsnode)
panic("get_zs whee chip not found");
}
- if(!vaddr)
+ if(!vaddr[0])
panic("get_zs whee no serial chip mappable");
- return (struct sun_zslayout *) vaddr;
-
+ return (struct sun_zslayout *)(unsigned long) vaddr[0];
}
+static inline void
+init_zscons_termios(struct termios *termios)
+{
+ char mode[16], buf[16];
+ char *mode_prop = "ttyX-mode";
+ char *cd_prop = "ttyX-ignore-cd";
+ char *dtr_prop = "ttyX-rts-dtr-off";
+ char *s;
+ int baud, bits, cflag;
+ char parity;
+ int topnd, nd;
+ int channel, stop;
+ int carrier = 0;
+ int rtsdtr = 1;
+ extern int serial_console;
+
+ if (!serial_console)
+ return;
+
+ if (serial_console == 1) {
+ mode_prop[3] = 'a';
+ cd_prop[3] = 'a';
+ dtr_prop[3] = 'a';
+ } else {
+ mode_prop[3] = 'b';
+ cd_prop[3] = 'b';
+ dtr_prop[3] = 'b';
+ }
+
+ topnd = prom_getchild(prom_root_node);
+ nd = prom_searchsiblings(topnd, "options");
+ if (!nd) {
+ strcpy(mode, "9600,8,n,1,-");
+ goto no_options;
+ }
+
+ if (!prom_node_has_property(nd, mode_prop)) {
+ strcpy(mode, "9600,8,n,1,-");
+ goto no_options;
+ }
+
+ memset(mode, 0, sizeof(mode));
+ prom_getstring(nd, mode_prop, mode, sizeof(mode));
+
+ if (prom_node_has_property(nd, cd_prop)) {
+ memset(buf, 0, sizeof(buf));
+ prom_getstring(nd, cd_prop, buf, sizeof(buf));
+ if (!strcmp(buf, "false"))
+ carrier = 1;
+
+ /* XXX this is unused below. */
+ }
+
+ if (prom_node_has_property(nd, cd_prop)) {
+ memset(buf, 0, sizeof(buf));
+ prom_getstring(nd, cd_prop, buf, sizeof(buf));
+ if (!strcmp(buf, "false"))
+ rtsdtr = 0;
+
+ /* XXX this is unused below. */
+ }
+
+no_options:
+ cflag = CREAD | HUPCL | CLOCAL;
+
+ s = mode;
+ baud = simple_strtoul(s, 0, 0);
+ s = strchr(s, ',');
+ bits = simple_strtoul(++s, 0, 0);
+ s = strchr(s, ',');
+ parity = *(++s);
+ s = strchr(s, ',');
+ stop = simple_strtoul(++s, 0, 0);
+ s = strchr(s, ',');
+ /* XXX handshake is not handled here. */
+
+ for (channel = 0; channel < NUM_CHANNELS; channel++)
+ if (zs_soft[channel].is_cons)
+ break;
+
+ switch (baud) {
+ case 150:
+ cflag |= B150;
+ break;
+ case 300:
+ cflag |= B300;
+ break;
+ case 600:
+ cflag |= B600;
+ break;
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 2400:
+ cflag |= B2400;
+ break;
+ case 4800:
+ cflag |= B4800;
+ break;
+ default:
+ baud = 9600;
+ case 9600:
+ cflag |= B9600;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ }
+ zs_soft[channel].zs_baud = baud;
+
+ switch (bits) {
+ case 5:
+ zscons_regs[3] = Rx5 | RxENAB;
+ zscons_regs[5] = Tx5 | TxENAB;
+ zs_soft[channel].parity_mask = 0x1f;
+ cflag |= CS5;
+ break;
+ case 6:
+ zscons_regs[3] = Rx6 | RxENAB;
+ zscons_regs[5] = Tx6 | TxENAB;
+ zs_soft[channel].parity_mask = 0x3f;
+ cflag |= CS6;
+ break;
+ case 7:
+ zscons_regs[3] = Rx7 | RxENAB;
+ zscons_regs[5] = Tx7 | TxENAB;
+ zs_soft[channel].parity_mask = 0x7f;
+ cflag |= CS7;
+ break;
+ default:
+ case 8:
+ zscons_regs[3] = Rx8 | RxENAB;
+ zscons_regs[5] = Tx8 | TxENAB;
+ zs_soft[channel].parity_mask = 0xff;
+ cflag |= CS8;
+ break;
+ }
+ zscons_regs[5] |= DTR;
+
+ switch (parity) {
+ case 'o':
+ zscons_regs[4] |= PAR_ENAB;
+ cflag |= (PARENB | PARODD);
+ break;
+ case 'e':
+ zscons_regs[4] |= (PAR_ENAB | PAR_EVEN);
+ cflag |= PARENB;
+ break;
+ default:
+ case 'n':
+ break;
+ }
+
+ switch (stop) {
+ default:
+ case 1:
+ zscons_regs[4] |= SB1;
+ break;
+ case 2:
+ cflag |= CSTOPB;
+ zscons_regs[4] |= SB2;
+ break;
+ }
+
+ termios->c_cflag = cflag;
+}
extern void register_console(void (*proc)(const char *));
@@ -1844,8 +2170,8 @@ static inline void
rs_cons_check(struct sun_serial *ss, int channel)
{
int i, o, io;
- static consout_registered = 0;
- static msg_printed = 0;
+ static int consout_registered = 0;
+ static int msg_printed = 0;
i = o = io = 0;
@@ -1861,6 +2187,9 @@ rs_cons_check(struct sun_serial *ss, int channel)
o = 1;
/* double whee.. */
if(!consout_registered) {
+ extern void serial_finish_init (void (*)(const char *));
+
+ serial_finish_init (zs_console_print);
register_console(zs_console_print);
consout_registered = 1;
}
@@ -1875,8 +2204,6 @@ rs_cons_check(struct sun_serial *ss, int channel)
}
if(o && i)
io = 1;
- if(ss->zs_baud != 9600)
- panic("Console baud rate weirdness");
/* Set flag variable for this port so that it cannot be
* opened for other uses by accident.
@@ -1894,15 +2221,66 @@ rs_cons_check(struct sun_serial *ss, int channel)
}
}
-volatile int test_done;
extern void keyboard_zsinit(void);
extern void sun_mouse_zsinit(void);
-/* rs_init inits the driver */
-int rs_init(void)
+/* This is for the auto baud rate detection in the mouse driver. */
+void zs_change_mouse_baud(int newbaud)
{
- int chip, channel, i, flags;
+ int channel = MOUSE_LINE;
+ int brg;
+
+ zs_soft[channel].zs_baud = newbaud;
+ brg = BPS_TO_BRG(zs_soft[channel].zs_baud,
+ (ZS_CLOCK / zs_soft[channel].clk_divisor));
+ write_zsreg(zs_soft[channel].zs_channel, R12, (brg & 0xff));
+ write_zsreg(zs_soft[channel].zs_channel, R13, ((brg >> 8) & 0xff));
+}
+
+__initfunc(unsigned long sun_serial_setup (unsigned long memory_start))
+{
+ char *p;
+ int i;
+
+ if (sparc_cpu_model == sun4d) {
+ int node = prom_searchsiblings(prom_getchild(prom_root_node), "boards");
+ NUM_SERIAL = 0;
+ if (!node)
+ panic ("Cannot find out count of boards");
+ else
+ node = prom_getchild(node);
+ while (node && (node = prom_searchsiblings(node, "bif"))) {
+ NUM_SERIAL += 2;
+ node = prom_getsibling(node);
+ }
+ }
+ p = (char *)((memory_start + 7) & ~7);
+ zs_chips = (struct sun_zslayout **)(p);
+ i = NUM_SERIAL * sizeof (struct sun_zslayout *);
+ zs_channels = (struct sun_zschannel **)(p + i);
+ i += NUM_CHANNELS * sizeof (struct sun_zschannel *);
+ zs_nodes = (int *)(p + i);
+ i += NUM_SERIAL * sizeof (int);
+ zs_soft = (struct sun_serial *)(p + i);
+ i += NUM_CHANNELS * sizeof (struct sun_serial);
+ zs_ttys = (struct tty_struct *)(p + i);
+ i += NUM_CHANNELS * sizeof (struct tty_struct);
+ serial_table = (struct tty_struct **)(p + i);
+ i += NUM_CHANNELS * sizeof (struct tty_struct *);
+ serial_termios = (struct termios **)(p + i);
+ i += NUM_CHANNELS * sizeof (struct termios *);
+ serial_termios_locked = (struct termios **)(p + i);
+ i += NUM_CHANNELS * sizeof (struct termios *);
+ memset (p, 0, i);
+ return (((unsigned long)p) + i + 7) & ~7;
+}
+
+__initfunc(int rs_init(void))
+{
+ int chip, channel, brg, i;
+ unsigned long flags;
struct sun_serial *info;
+ char dummy;
#if CONFIG_AP1000
printk("not doing rs_init()\n");
@@ -1921,6 +2299,7 @@ int rs_init(void)
memset(&serial_driver, 0, sizeof(struct tty_driver));
serial_driver.magic = TTY_DRIVER_MAGIC;
+ serial_driver.driver_name = "serial";
serial_driver.name = "ttyS";
serial_driver.major = TTY_MAJOR;
serial_driver.minor_start = 64;
@@ -1952,6 +2331,12 @@ int rs_init(void)
serial_driver.start = rs_start;
serial_driver.hangup = rs_hangup;
+ /* I'm too lazy, someone write versions of this for us. -DaveM */
+ serial_driver.read_proc = 0;
+ serial_driver.proc_entry = 0;
+
+ init_zscons_termios(&serial_driver.init_termios);
+
/*
* The callout device is just like normal device except for
* major number and the subtype code.
@@ -1970,11 +2355,11 @@ int rs_init(void)
/* Set up our interrupt linked list */
zs_chain = &zs_soft[0];
- zs_soft[0].zs_next = &zs_soft[1];
- zs_soft[1].zs_next = &zs_soft[2];
- zs_soft[2].zs_next = &zs_soft[3];
- zs_soft[3].zs_next = 0;
+ for(channel = 0; channel < NUM_CHANNELS - 1; channel++)
+ zs_soft[channel].zs_next = &zs_soft[channel + 1];
+ zs_soft[channel + 1].zs_next = 0;
+ /* Initialize Softinfo */
for(chip = 0; chip < NUM_SERIAL; chip++) {
/* If we are doing kgdb over one of the channels on
* chip zero, kgdb_channel will be set to 1 by the
@@ -1988,105 +2373,175 @@ int rs_init(void)
zs_soft[(chip*2)].kgdb_channel = 0;
zs_soft[(chip*2)+1].kgdb_channel = 0;
}
+
/* First, set up channel A on this chip. */
channel = chip * 2;
zs_soft[channel].zs_channel = zs_channels[channel];
zs_soft[channel].change_needed = 0;
zs_soft[channel].clk_divisor = 16;
- zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+ zs_soft[channel].cons_keyb = 0;
zs_soft[channel].cons_mouse = 0;
- /* If not keyboard/mouse and is console serial
- * line, then enable receiver interrupts.
- */
- if((channel<KEYBOARD_LINE) && (zs_soft[channel].is_cons)) {
- write_zsreg(zs_soft[channel].zs_channel, R1,
- (EXT_INT_ENAB | INT_ALL_Rx));
- write_zsreg(zs_soft[channel].zs_channel, R9, (NV | MIE));
- write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
- write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
- write_zsreg(zs_soft[channel].zs_channel, R5, (Tx8 | TxENAB));
+ zs_soft[channel].channelA = 1;
+
+ /* Now, channel B */
+ channel++;
+ zs_soft[channel].zs_channel = zs_channels[channel];
+ zs_soft[channel].change_needed = 0;
+ zs_soft[channel].clk_divisor = 16;
+ zs_soft[channel].cons_keyb = 0;
+ zs_soft[channel].cons_mouse = 0;
+ zs_soft[channel].channelA = 0;
+ }
+
+ /* Initialize Hardware */
+ for(channel = 0; channel < NUM_CHANNELS; channel++) {
+
+ /* Hardware reset each chip */
+ if (!(channel & 1)) {
+ write_zsreg(zs_soft[channel].zs_channel, R9, FHWRES);
+ udelay(20); /* wait for some old sun4's */
+ dummy = read_zsreg(zs_soft[channel].zs_channel, R0);
}
- /* If this is the kgdb line, enable interrupts because we
- * now want to receive the 'control-c' character from the
- * client attached to us asynchronously.
- */
- if(zs_soft[channel].kgdb_channel)
- kgdb_chaninit(&zs_soft[channel], 1, zs_soft[channel].zs_baud);
if(channel == KEYBOARD_LINE) {
- /* Tell keyboard driver about our presence. */
- if(zs_soft[channel].zs_baud != 1200)
- panic("Weird keyboard serial baud rate");
zs_soft[channel].cons_keyb = 1;
+ zs_soft[channel].parity_mask = 0xff;
zs_kbdchan = zs_soft[channel].zs_channel;
- /* Enable Rx/Tx, IRQs, and inform kbd driver */
- write_zsreg(zs_soft[channel].zs_channel, R1,
- (EXT_INT_ENAB | INT_ALL_Rx));
+
write_zsreg(zs_soft[channel].zs_channel, R4,
(PAR_EVEN | X16CLK | SB1));
- write_zsreg(zs_soft[channel].zs_channel, R9, (NV|MIE));
- write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
+ write_zsreg(zs_soft[channel].zs_channel, R3, Rx8);
+ write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+ write_zsreg(zs_soft[channel].zs_channel, R9, NV);
+ write_zsreg(zs_soft[channel].zs_channel, R10, NRZ);
write_zsreg(zs_soft[channel].zs_channel, R11,
(TCBR | RCBR));
+ zs_soft[channel].zs_baud = 1200;
+ brg = BPS_TO_BRG(zs_soft[channel].zs_baud,
+ ZS_CLOCK/zs_soft[channel].clk_divisor);
+ write_zsreg(zs_soft[channel].zs_channel, R12,
+ (brg & 0xff));
+ write_zsreg(zs_soft[channel].zs_channel, R13,
+ ((brg >> 8) & 0xff));
+ write_zsreg(zs_soft[channel].zs_channel, R14, BRSRC);
+
+ /* Enable Rx/Tx, IRQs, and inform kbd driver */
write_zsreg(zs_soft[channel].zs_channel, R14,
- (BRSRC | BRENABL));
- write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+ (BRSRC | BRENAB));
+ write_zsreg(zs_soft[channel].zs_channel, R3,
+ (Rx8 | RxENAB));
write_zsreg(zs_soft[channel].zs_channel, R5,
(Tx8 | TxENAB | DTR | RTS));
-#if 0
+
write_zsreg(zs_soft[channel].zs_channel, R15,
(DCDIE | CTSIE | TxUIE | BRKIE));
-#endif
- ZS_CLEARERR(zs_soft[channel].zs_channel);
- ZS_CLEARFIFO(zs_soft[channel].zs_channel);
- }
+ write_zsreg(zs_soft[channel].zs_channel, R0,
+ RES_EXT_INT);
+ write_zsreg(zs_soft[channel].zs_channel, R0,
+ RES_EXT_INT);
- /* Now, channel B */
- channel++;
- zs_soft[channel].zs_channel = zs_channels[channel];
- zs_soft[channel].change_needed = 0;
- zs_soft[channel].clk_divisor = 16;
- zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
- zs_soft[channel].cons_keyb = 0;
- /* If not keyboard/mouse and is console serial
- * line, then enable receiver interrupts.
- */
- if(channel<KEYBOARD_LINE && zs_soft[channel].is_cons) {
write_zsreg(zs_soft[channel].zs_channel, R1,
(EXT_INT_ENAB | INT_ALL_Rx));
write_zsreg(zs_soft[channel].zs_channel, R9,
(NV | MIE));
- write_zsreg(zs_soft[channel].zs_channel, R10,
- (NRZ));
- write_zsreg(zs_soft[channel].zs_channel, R3,
- (Rx8|RxENABLE));
- write_zsreg(zs_soft[channel].zs_channel, R5,
- (Tx8 | TxENAB | RTS | DTR));
- }
- if(channel == MOUSE_LINE) {
- /* Tell mouse driver about our presence. */
- if(zs_soft[channel].zs_baud != 1200)
- panic("Weird mouse serial baud rate");
+ ZS_CLEARERR(zs_soft[channel].zs_channel);
+ ZS_CLEARFIFO(zs_soft[channel].zs_channel);
+ } else if(channel == MOUSE_LINE) {
zs_soft[channel].cons_mouse = 1;
+ zs_soft[channel].parity_mask = 0xff;
zs_mousechan = zs_soft[channel].zs_channel;
+
+ write_zsreg(zs_soft[channel].zs_channel, R4,
+ (PAR_EVEN | X16CLK | SB1));
+ write_zsreg(zs_soft[channel].zs_channel, R3, Rx8);
+ write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+ write_zsreg(zs_soft[channel].zs_channel, R9, NV);
+ write_zsreg(zs_soft[channel].zs_channel, R10, NRZ);
+ write_zsreg(zs_soft[channel].zs_channel, R11,
+ (TCBR | RCBR));
+
+ zs_soft[channel].zs_baud = 4800;
+ brg = BPS_TO_BRG(zs_soft[channel].zs_baud,
+ ZS_CLOCK/zs_soft[channel].clk_divisor);
+ write_zsreg(zs_soft[channel].zs_channel, R12,
+ (brg & 0xff));
+ write_zsreg(zs_soft[channel].zs_channel, R13,
+ ((brg >> 8) & 0xff));
+ write_zsreg(zs_soft[channel].zs_channel, R14, BRSRC);
+
/* Enable Rx, IRQs, and inform mouse driver */
- write_zsreg(zs_soft[channel].zs_channel, R1, (INT_ALL_Rx));
- write_zsreg(zs_soft[channel].zs_channel, R9, (NV|MIE));
- write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
-#if 0 /* XXX hangs sun4c's sometimes */
+ write_zsreg(zs_soft[channel].zs_channel, R14,
+ (BRSRC | BRENAB));
+ write_zsreg(zs_soft[channel].zs_channel, R3,
+ (Rx8 | RxENAB));
+ write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+
write_zsreg(zs_soft[channel].zs_channel, R15,
(DCDIE | CTSIE | TxUIE | BRKIE));
-#endif
+ write_zsreg(zs_soft[channel].zs_channel, R0,
+ RES_EXT_INT);
+ write_zsreg(zs_soft[channel].zs_channel, R0,
+ RES_EXT_INT);
+
+ write_zsreg(zs_soft[channel].zs_channel, R1,
+ (EXT_INT_ENAB | INT_ALL_Rx));
+ write_zsreg(zs_soft[channel].zs_channel, R9,
+ (NV | MIE));
+
sun_mouse_zsinit();
+ } else if (zs_soft[channel].is_cons) {
+ brg = BPS_TO_BRG(zs_soft[channel].zs_baud,
+ ZS_CLOCK/zs_soft[channel].clk_divisor);
+ zscons_regs[12] = brg & 0xff;
+ zscons_regs[13] = (brg >> 8) & 0xff;
+
+ memcpy(zs_soft[channel].curregs, zscons_regs, sizeof(zscons_regs));
+ load_zsregs(&zs_soft[channel], zscons_regs);
+
+ ZS_CLEARERR(zs_soft[channel].zs_channel);
+ ZS_CLEARFIFO(zs_soft[channel].zs_channel);
+ } else if (zs_soft[channel].kgdb_channel) {
+ /* If this is the kgdb line, enable interrupts because
+ * we now want to receive the 'control-c' character
+ * from the client attached to us asynchronously.
+ */
+ zs_soft[channel].parity_mask = 0xff;
+ kgdb_chaninit(&zs_soft[channel], 1,
+ zs_soft[channel].zs_baud);
} else {
- zs_soft[channel].cons_mouse = 0;
+ zs_soft[channel].parity_mask = 0xff;
+ write_zsreg(zs_soft[channel].zs_channel, R4,
+ (PAR_EVEN | X16CLK | SB1));
+ write_zsreg(zs_soft[channel].zs_channel, R3, Rx8);
+ write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+ write_zsreg(zs_soft[channel].zs_channel, R9, NV);
+ write_zsreg(zs_soft[channel].zs_channel, R10, NRZ);
+ write_zsreg(zs_soft[channel].zs_channel, R11,
+ (RCBR | TCBR));
+ zs_soft[channel].zs_baud = 9600;
+ brg = BPS_TO_BRG(zs_soft[channel].zs_baud,
+ ZS_CLOCK/zs_soft[channel].clk_divisor);
+ write_zsreg(zs_soft[channel].zs_channel, R12,
+ (brg & 0xff));
+ write_zsreg(zs_soft[channel].zs_channel, R13,
+ ((brg >> 8) & 0xff));
+ write_zsreg(zs_soft[channel].zs_channel, R14, BRSRC);
+ write_zsreg(zs_soft[channel].zs_channel, R14,
+ (BRSRC | BRENAB));
+ write_zsreg(zs_soft[channel].zs_channel, R3, Rx8);
+ write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+ write_zsreg(zs_soft[channel].zs_channel, R15, DCDIE);
+ write_zsreg(zs_soft[channel].zs_channel, R9, NV | MIE);
+ write_zsreg(zs_soft[channel].zs_channel, R0,
+ RES_EXT_INT);
+ write_zsreg(zs_soft[channel].zs_channel, R0,
+ RES_EXT_INT);
}
}
- for(info=zs_chain, i=0; info; info = info->zs_next, i++)
- {
+ for (info = zs_chain, i=0; info; info = info->zs_next, i++) {
info->magic = SERIAL_MAGIC;
- info->port = (int) info->zs_channel;
+ info->port = (long) info->zs_channel;
info->line = i;
info->tty = 0;
info->irq = zilog_irq;
@@ -2101,7 +2556,7 @@ int rs_init(void)
info->tqueue.data = info;
info->tqueue_hangup.routine = do_serial_hangup;
info->tqueue_hangup.data = info;
- info->callout_termios =callout_driver.init_termios;
+ info->callout_termios = callout_driver.init_termios;
info->normal_termios = serial_driver.init_termios;
info->open_wait = 0;
info->close_wait = 0;
@@ -2110,15 +2565,13 @@ int rs_init(void)
printk(" is a Zilog8530\n");
}
- if (request_irq(zilog_irq,
- rs_interrupt,
+ if (request_irq(zilog_irq, rs_interrupt,
(SA_INTERRUPT | SA_STATIC_ALLOC),
- "Zilog8530", NULL))
+ "Zilog8530", zs_chain))
panic("Unable to attach zs intr\n");
restore_flags(flags);
keyboard_zsinit();
-
return 0;
}
@@ -2144,10 +2597,15 @@ void unregister_serial(int line)
* are addressed backwards, channel B is first, then channel A.
*/
void
-rs_cons_hook(int chip, int out, int channel)
+rs_cons_hook(int chip, int out, int line)
{
+ int channel;
+
if(chip)
panic("rs_cons_hook called with chip not zero");
+ if(line != 1 && line != 2)
+ panic("rs_cons_hook called with line not ttya or ttyb");
+ channel = line - 1;
if(!zs_chips[chip]) {
zs_chips[chip] = get_zs(chip);
/* Two channels per chip */
@@ -2157,13 +2615,11 @@ rs_cons_hook(int chip, int out, int channel)
zs_soft[channel].zs_channel = zs_channels[channel];
zs_soft[channel].change_needed = 0;
zs_soft[channel].clk_divisor = 16;
- zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
- rs_cons_check(&zs_soft[channel], channel);
if(out)
zs_cons_chanout = ((chip * 2) + channel);
else
zs_cons_chanin = ((chip * 2) + channel);
-
+ rs_cons_check(&zs_soft[channel], channel);
}
/* This is called at boot time to prime the kgdb serial debugging
@@ -2186,12 +2642,11 @@ rs_kgdb_hook(int tty_num)
zs_kgdbchan = zs_soft[tty_num].zs_channel;
zs_soft[tty_num].change_needed = 0;
zs_soft[tty_num].clk_divisor = 16;
- zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+ zs_soft[tty_num].zs_baud = 9600;
zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */
zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
/* Turn on transmitter/receiver at 8-bits/char */
- kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
- ZS_CLEARERR(zs_kgdbchan);
- udelay(5);
- ZS_CLEARFIFO(zs_kgdbchan);
+ kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+ ZS_CLEARERR(zs_kgdbchan);
+ ZS_CLEARFIFO(zs_kgdbchan);
}
diff --git a/drivers/sbus/char/sunserial.h b/drivers/sbus/char/sunserial.h
index 8fb029669..b8ae23305 100644
--- a/drivers/sbus/char/sunserial.h
+++ b/drivers/sbus/char/sunserial.h
@@ -1,6 +1,8 @@
-/* serial.h: Definitions for the Sparc Zilog serial driver.
+/* $Id: sunserial.h,v 1.9 1997/04/12 23:33:12 ecd Exp $
+ * serial.h: Definitions for the Sparc Zilog serial driver.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*/
#ifndef _SPARC_SERIAL_H
#define _SPARC_SERIAL_H
@@ -66,9 +68,7 @@ struct serial_struct {
#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
#define ZILOG_SPD_MASK 0x0030
-#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_HI 0x0010 /* Use 76800 instead of 38400 bps */
#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
@@ -114,6 +114,9 @@ struct sun_serial {
char kgdb_channel; /* Kgdb is running on this channel */
char is_cons; /* Is this our console. */
+ char channelA; /* This is channel A. */
+ char parity_mask; /* Mask out parity bits in data register. */
+
/* We need to know the current clock divisor
* to read the bps rate the chip has currently
* loaded.
@@ -124,9 +127,6 @@ struct sun_serial {
/* Current write register values */
unsigned char curregs[NUM_ZSREGS];
- /* Values we need to set next opportunity */
- unsigned char pendregs[NUM_ZSREGS];
-
char change_needed;
int magic;
@@ -231,6 +231,7 @@ struct sun_serial {
#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
#define INT_ERR_Rx 0x18 /* Int on error only */
+#define RxINT_MASK 0x18
#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
@@ -240,7 +241,7 @@ struct sun_serial {
/* Write Register 3 */
-#define RxENABLE 0x1 /* Rx Enable */
+#define RxENAB 0x1 /* Rx Enable */
#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
@@ -250,10 +251,11 @@ struct sun_serial {
#define Rx7 0x40 /* Rx 7 Bits/Character */
#define Rx6 0x80 /* Rx 6 Bits/Character */
#define Rx8 0xc0 /* Rx 8 Bits/Character */
+#define RxN_MASK 0xc0
/* Write Register 4 */
-#define PAR_ENA 0x1 /* Parity Enable */
+#define PAR_ENAB 0x1 /* Parity Enable */
#define PAR_EVEN 0x2 /* Parity Even/Odd* */
#define SYNC_ENAB 0 /* Sync Modes Enable */
@@ -282,6 +284,7 @@ struct sun_serial {
#define Tx7 0x20 /* Tx 7 bits/character */
#define Tx6 0x40 /* Tx 6 bits/character */
#define Tx8 0x60 /* Tx 8 bits/character */
+#define TxN_MASK 0x60
#define DTR 0x80 /* DTR */
/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
@@ -334,7 +337,7 @@ struct sun_serial {
/* Write Register 13 (upper byte of baud rate generator time constant) */
/* Write Register 14 (Misc control bits) */
-#define BRENABL 1 /* Baud rate generator enable */
+#define BRENAB 1 /* Baud rate generator enable */
#define BRSRC 2 /* Baud rate generator source */
#define DTRREQ 4 /* DTR/Request function */
#define AUTOECHO 8 /* Auto Echo */
@@ -361,7 +364,7 @@ struct sun_serial {
#define ZCOUNT 0x2 /* Zero count */
#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
#define DCD 0x8 /* DCD */
-#define SYNC_HUNT 0x10 /* Sync/hunt */
+#define SYNC 0x10 /* Sync/hunt */
#define CTS 0x20 /* CTS */
#define TxEOM 0x40 /* Tx underrun */
#define BRK_ABRT 0x80 /* Break/Abort */
@@ -384,6 +387,15 @@ struct sun_serial {
#define END_FR 0x80 /* End of Frame (SDLC) */
/* Read Register 2 (channel b only) - Interrupt vector */
+#define CHB_Tx_EMPTY 0x00
+#define CHB_EXT_STAT 0x02
+#define CHB_Rx_AVAIL 0x04
+#define CHB_SPECIAL 0x06
+#define CHA_Tx_EMPTY 0x08
+#define CHA_EXT_STAT 0x0a
+#define CHA_Rx_AVAIL 0x0c
+#define CHA_SPECIAL 0x0e
+#define STATUS_MASK 0x0e
/* Read Register 3 (interrupt pending register) ch a only */
#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
@@ -408,7 +420,12 @@ struct sun_serial {
/* Read Register 15 (value of WR 15) */
/* Misc macros */
-#define ZS_CLEARERR(channel) (channel->control = ERR_RES)
+#define ZS_CLEARERR(channel) do { channel->control = ERR_RES; \
+ udelay(5); } while(0)
+
+#define ZS_CLEARSTAT(channel) do { channel->control = RES_EXT_INT; \
+ udelay(5); } while(0)
+
#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
garbage = channel->data; \
udelay(2); \
diff --git a/drivers/sbus/char/tcx.c b/drivers/sbus/char/tcx.c
new file mode 100644
index 000000000..2ecabda62
--- /dev/null
+++ b/drivers/sbus/char/tcx.c
@@ -0,0 +1,369 @@
+/* $Id: tcx.c,v 1.12 1997/04/14 17:04:51 jj Exp $
+ * tcx.c: SUNW,tcx 24/8bit frame buffer driver
+ *
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/* Offset of interesting structures in the tcx registers */
+#define TCX_RAM8BIT_OFFSET 0
+#define TCX_CONTROLPLANE_OFFSET 4
+#define TCX_BROOKTREE_OFFSET 8
+#define TCX_THC_OFFSET 9
+#define TCX_TEC_OFFSET 7
+
+/* THC definitions */
+#define TCX_THC_MISC_REV_SHIFT 16
+#define TCX_THC_MISC_REV_MASK 15
+#define TCX_THC_MISC_RESET (1 << 12)
+#define TCX_THC_MISC_VIDEO (1 << 10)
+#define TCX_THC_MISC_SYNC (1 << 9)
+#define TCX_THC_MISC_VSYNC (1 << 8)
+#define TCX_THC_MISC_SYNC_ENAB (1 << 7)
+#define TCX_THC_MISC_CURS_RES (1 << 6)
+#define TCX_THC_MISC_INT_ENAB (1 << 5)
+#define TCX_THC_MISC_INT (1 << 4)
+#define TCX_THC_MISC_INIT 0x9f
+#define TCX_THC_REV_REV_SHIFT 20
+#define TCX_THC_REV_REV_MASK 15
+#define TCX_THC_REV_MINREV_SHIFT 28
+#define TCX_THC_REV_MINREV_MASK 15
+
+/* The contents are unknown */
+struct tcx_tec {
+ volatile int tec_matrix;
+ volatile int tec_clip;
+ volatile int tec_vdc;
+};
+
+struct tcx_thc {
+ volatile uint thc_rev;
+ uint thc_pad0[511];
+ volatile uint thc_hs; /* hsync timing */
+ volatile uint thc_hsdvs;
+ volatile uint thc_hd;
+ volatile uint thc_vs; /* vsync timing */
+ volatile uint thc_vd;
+ volatile uint thc_refresh;
+ volatile uint thc_misc;
+ uint thc_pad1[56];
+ volatile uint thc_cursxy; /* cursor x,y position (16 bits each) */
+ volatile uint thc_cursmask[32]; /* cursor mask bits */
+ volatile uint thc_cursbits[32]; /* what to show where mask enabled */
+};
+
+static void
+tcx_restore_palette (fbinfo_t *fbinfo)
+{
+ volatile struct bt_regs *bt;
+
+ bt = fbinfo->info.tcx.bt;
+ bt->addr = 0;
+ bt->color_map = 0xffffffff;
+ bt->color_map = 0xffffffff;
+ bt->color_map = 0xffffffff;
+}
+
+static void
+tcx_set_control_plane (fbinfo_t *fb)
+{
+ register uint *p, *pend;
+
+ p = fb->info.tcx.tcx_cplane;
+ if (!p) return;
+ for (pend = p + (fb->info.tcx.tcx_sizes [TCX_CONTROLPLANE_OFFSET] >> 2); p < pend; p++)
+ *p &= 0xffffff;
+}
+
+static void
+tcx_switch_from_graph (void)
+{
+ fbinfo_t *fb = &(fbinfo [0]);
+
+ /* Reset control plane to 8bit mode if necessary */
+ if (fb->open && fb->mmaped)
+ tcx_set_control_plane (fb);
+}
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+tcx_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+ long base, fbinfo_t *fb)
+{
+ uint size, page, r, map_size;
+ uint map_offset = 0, i;
+ long offsets[13] = { -1, TCX_RAM24BIT, TCX_UNK3, TCX_UNK4,
+ -1, TCX_UNK6, TCX_UNK7,
+ -1, -1, -1, TCX_UNK2, TCX_DHC, TCX_ALT };
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages */
+ vma->vm_flags |= FB_MMAP_VM_FLAGS;
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ){
+ switch (vma->vm_offset+page){
+ case TCX_RAM8BIT:
+ map_size = fb->type.fb_size;
+ map_offset = get_phys ((unsigned long) fb->base);
+ break;
+ case TCX_TEC:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.tcx.tec);
+ break;
+ case TCX_BTREGS:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.tcx.bt);
+ break;
+ case TCX_THC:
+ map_size = PAGE_SIZE;
+ map_offset = get_phys ((unsigned long)fb->info.tcx.thc);
+ break;
+ case TCX_CONTROLPLANE:
+ if (fb->info.tcx.tcx_cplane) {
+ map_size = fb->info.tcx.tcx_sizes [TCX_CONTROLPLANE_OFFSET];
+ map_offset = get_phys ((unsigned long)fb->info.tcx.tcx_cplane);
+ } else
+ map_size = 0;
+ break;
+ default:
+ map_size = 0;
+ for (i = 0; i < 13; i++)
+ if (offsets [i] == vma->vm_offset+page) {
+ if ((map_size = fb->info.tcx.tcx_sizes [i]))
+ map_offset = fb->info.tcx.tcx_offsets [i];
+ break;
+ }
+ break;
+ }
+ if (!map_size){
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+ r = io_remap_page_range (vma->vm_start+page,
+ map_offset,
+ map_size, vma->vm_page_prot,
+ fb->space);
+ if (r) return -EAGAIN;
+ page += map_size;
+ }
+ vma->vm_inode = inode;
+ inode->i_count++;
+ return 0;
+}
+
+static void
+tcx_loadcmap (fbinfo_t *fb, int index, int count)
+{
+ struct bt_regs *bt = fb->info.tcx.bt;
+ int i;
+
+ bt->addr = index << 24;
+ for (i = index; count--; i++){
+ bt->color_map = fb->color_map CM(i,0) << 24;
+ bt->color_map = fb->color_map CM(i,1) << 24;
+ bt->color_map = fb->color_map CM(i,2) << 24;
+ }
+ bt->addr = 0;
+}
+
+static void
+tcx_setcursormap (fbinfo_t *fb, unsigned char *red,
+ unsigned char *green,
+ unsigned char *blue)
+{
+ struct bt_regs *bt = fb->info.tcx.bt;
+
+ /* Note the 2 << 24 is different from cg6's 1 << 24 */
+ bt->addr = 2 << 24;
+ bt->cursor = red[0] << 24;
+ bt->cursor = green[0] << 24;
+ bt->cursor = blue[0] << 24;
+ bt->addr = 3 << 24;
+ bt->cursor = red[1] << 24;
+ bt->cursor = green[1] << 24;
+ bt->cursor = blue[1] << 24;
+ bt->addr = 0;
+}
+
+/* Load cursor information */
+static void
+tcx_setcursor (fbinfo_t *fb)
+{
+ uint v;
+ struct cg_cursor *c = &fb->cursor;
+
+ if (c->enable){
+ v = ((c->cpos.fbx - c->chot.fbx) << 16)
+ |((c->cpos.fby - c->chot.fby) & 0xffff);
+ } else {
+ /* Magic constant to turn off the cursor */
+ v = ((65536-32) << 16) | (65536-32);
+ }
+ fb->info.tcx.thc->thc_cursxy = v;
+}
+
+/* Set cursor shape */
+static void
+tcx_setcurshape (fbinfo_t *fb)
+{
+ struct tcx_thc *thc = fb->info.tcx.thc;
+ int i;
+
+ for (i = 0; i < 32; i++){
+ thc->thc_cursmask [i] = fb->cursor.bits[0][i];
+ thc->thc_cursbits [i] = fb->cursor.bits[1][i];
+ }
+}
+
+static void
+tcx_blank (fbinfo_t *fb)
+{
+ fb->info.tcx.thc->thc_misc &= ~TCX_THC_MISC_VIDEO;
+}
+
+static void
+tcx_unblank (fbinfo_t *fb)
+{
+ fb->info.tcx.thc->thc_misc |= TCX_THC_MISC_VIDEO;
+}
+
+void
+tcx_reset (fbinfo_t *fb)
+{
+ struct tcx_info *tcx = &(fb->info.tcx);
+
+ if (fb->setcursor)
+ sun_hw_hide_cursor ();
+ /* Reset control plane to 8bit mode if necessary */
+ if (fb->open && fb->mmaped)
+ tcx_set_control_plane (fb);
+
+ /* Turn off stuff in the Transform Engine. */
+ tcx->tec->tec_matrix = 0;
+ tcx->tec->tec_clip = 0;
+ tcx->tec->tec_vdc = 0;
+
+ /* Enable cursor in Brooktree DAC. */
+ tcx->bt->addr = 0x06 << 24;
+ tcx->bt->control |= 0x03 << 24;
+}
+
+__initfunc(void tcx_setup (fbinfo_t *fb, int slot, int node, u32 tcx, struct linux_sbus_device *sbdp))
+{
+ struct tcx_info *tcxinfo;
+ int i;
+
+ printk ("tcx%d at 0x%8.8x ", slot, tcx);
+
+ /* Fill in parameters we left out */
+ fb->type.fb_cmsize = 256;
+ fb->mmap = tcx_mmap;
+ fb->loadcmap = tcx_loadcmap;
+ fb->reset = tcx_reset;
+ fb->blank = tcx_blank;
+ fb->unblank = tcx_unblank;
+ fb->emulations [1] = FBTYPE_SUN3COLOR;
+ fb->emulations [2] = FBTYPE_MEMCOLOR;
+ fb->switch_from_graph = tcx_switch_from_graph;
+ fb->postsetup = sun_cg_postsetup;
+
+ tcxinfo = (struct tcx_info *) &fb->info.tcx;
+
+ memset (tcxinfo, 0, sizeof(struct tcx_info));
+
+ for (i = 0; i < 13; i++)
+ tcxinfo->tcx_offsets [i] = (long)(sbdp->reg_addrs [i].phys_addr);
+
+ /* Map the hardware registers */
+ tcxinfo->bt = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_BROOKTREE_OFFSET], 0,
+ sizeof (struct bt_regs),"tcx_dac", fb->space, 0);
+ tcxinfo->thc = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_THC_OFFSET], 0,
+ sizeof (struct tcx_thc), "tcx_thc", fb->space, 0);
+ tcxinfo->tec = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0,
+ sizeof (struct tcx_tec), "tcx_tec", fb->space, 0);
+ if (!fb->base){
+ fb->base = (uint)
+ sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0,
+ fb->type.fb_size, "tcx_ram", fb->space, 0);
+ }
+
+ if (prom_getbool (node, "hw-cursor")) {
+ fb->setcursor = tcx_setcursor;
+ fb->setcursormap = tcx_setcursormap;
+ fb->setcurshape = tcx_setcurshape;
+ }
+
+ if (!slot) {
+ fb_restore_palette = tcx_restore_palette;
+ }
+
+ i = fb->type.fb_size;
+ tcxinfo->tcx_sizes[2] = i << 3;
+ tcxinfo->tcx_sizes[3] = i << 3;
+ tcxinfo->tcx_sizes[10] = 0x20000;
+ tcxinfo->tcx_sizes[11] = PAGE_SIZE;
+ tcxinfo->tcx_sizes[12] = PAGE_SIZE;
+
+ if (prom_getbool (node, "tcx-8-bit"))
+ tcxinfo->lowdepth = 1;
+
+ if (!tcxinfo->lowdepth) {
+ tcxinfo->tcx_sizes[1] = i << 2;
+ tcxinfo->tcx_sizes[4] = i << 2;
+ tcxinfo->tcx_sizes[5] = i << 3;
+ tcxinfo->tcx_sizes[6] = i << 3;
+ fb->type.fb_depth = 24;
+ tcxinfo->tcx_cplane =
+ sparc_alloc_io((u32)tcxinfo->tcx_offsets[TCX_CONTROLPLANE_OFFSET], 0,
+ tcxinfo->tcx_sizes [TCX_CONTROLPLANE_OFFSET],
+ "tcx_cplane", fb->space, 0);
+ }
+
+ /* Initialize Brooktree DAC */
+ tcxinfo->bt->addr = 0x04 << 24; /* color planes */
+ tcxinfo->bt->control = 0xff << 24;
+ tcxinfo->bt->addr = 0x05 << 24;
+ tcxinfo->bt->control = 0x00 << 24;
+ tcxinfo->bt->addr = 0x06 << 24; /* overlay plane */
+ tcxinfo->bt->control = 0x73 << 24;
+ tcxinfo->bt->addr = 0x07 << 24;
+ tcxinfo->bt->control = 0x00 << 24;
+
+ printk("Rev %d.%d %s\n",
+ (tcxinfo->thc->thc_rev >> TCX_THC_REV_REV_SHIFT) & TCX_THC_REV_REV_MASK,
+ (tcxinfo->thc->thc_rev >> TCX_THC_REV_MINREV_SHIFT) & TCX_THC_REV_MINREV_MASK,
+ tcxinfo->lowdepth ? "8-bit only" : "24-bit depth");
+
+ /* Reset the tcx */
+ tcx_reset(fb);
+
+ if (!slot)
+ /* Enable Video */
+ tcx_unblank (fb);
+ else
+ tcx_blank (fb);
+}
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
new file mode 100644
index 000000000..752bf748c
--- /dev/null
+++ b/drivers/sbus/char/vfc.h
@@ -0,0 +1,171 @@
+#ifndef _LINUX_VFC_H_
+#define _LINUX_VFC_H_
+
+/*
+ * The control register for the vfc is at offset 0x4000
+ * The first field ram bank is located at offset 0x5000
+ * The second field ram bank is at offset 0x7000
+ * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c)
+ * data and transmit register.
+ * i2c_s1 controls register s1 of the PCF8584
+ * i2c_write seems to be similar to i2c_write but I am not
+ * quite sure why sun uses it
+ *
+ * I am also not sure whether or not you can read the fram bank as a
+ * whole or whether you must read each word individually from offset
+ * 0x5000 as soon as I figure it out I will update this file */
+
+struct vfc_regs {
+ char pad1[0x4000];
+ unsigned int control; /* Offset 0x4000 */
+ char pad2[0xffb]; /* from offset 0x4004 to 0x5000 */
+ unsigned int fram_bank1; /* Offset 0x5000 */
+ char pad3[0xffb]; /* from offset 0x5004 to 0x6000 */
+ unsigned int i2c_reg; /* Offset 0x6000 */
+ unsigned int i2c_magic2; /* Offset 0x6004 */
+ unsigned int i2c_s1; /* Offset 0x6008 */
+ unsigned int i2c_write; /* Offset 0x600c */
+ char pad4[0xff0]; /* from offset 0x6010 to 0x7000 */
+ unsigned int fram_bank2; /* Offset 0x7000 */
+ char pad5[0x1000];
+};
+
+#define VFC_SAA9051_NR (13)
+#define VFC_SAA9051_ADDR (0x8a)
+ /* The saa9051 returns the following for its status
+ * bit 0 - 0
+ * bit 1 - SECAM color detected (1=found,0=not found)
+ * bit 2 - COLOR detected (1=found,0=not found)
+ * bit 3 - 0
+ * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL))
+ * bit 5 - 1
+ * bit 6 - horizontal frequency lock (1=transmitter found,
+ * 0=no transmitter)
+ * bit 7 - Power on reset bit (1=reset,0=at least one successful
+ * read of the status byte)
+ */
+
+#define VFC_SAA9051_PONRES (0x80)
+#define VFC_SAA9051_HLOCK (0x40)
+#define VFC_SAA9051_FD (0x10)
+#define VFC_SAA9051_CD (0x04)
+#define VFC_SAA9051_CS (0x02)
+
+
+/* The various saa9051 sub addresses */
+
+#define VFC_SAA9051_IDEL (0)
+#define VFC_SAA9051_HSY_START (1)
+#define VFC_SAA9051_HSY_STOP (2)
+#define VFC_SAA9051_HC_START (3)
+#define VFC_SAA9051_HC_STOP (4)
+#define VFC_SAA9051_HS_START (5)
+#define VFC_SAA9051_HORIZ_PEAK (6)
+#define VFC_SAA9051_HUE (7)
+#define VFC_SAA9051_C1 (8)
+#define VFC_SAA9051_C2 (9)
+#define VFC_SAA9051_C3 (0xa)
+#define VFC_SAA9051_SECAM_DELAY (0xb)
+
+
+/* Bit settings for saa9051 sub address 0x06 */
+
+#define VFC_SAA9051_AP1 (0x01)
+#define VFC_SAA9051_AP2 (0x02)
+#define VFC_SAA9051_COR1 (0x04)
+#define VFC_SAA9051_COR2 (0x08)
+#define VFC_SAA9051_BP1 (0x10)
+#define VFC_SAA9051_BP2 (0x20)
+#define VFC_SAA9051_PF (0x40)
+#define VFC_SAA9051_BY (0x80)
+
+
+/* Bit settings for saa9051 sub address 0x08 */
+
+#define VFC_SAA9051_CCFR0 (0x01)
+#define VFC_SAA9051_CCFR1 (0x02)
+#define VFC_SAA9051_YPN (0x04)
+#define VFC_SAA9051_ALT (0x08)
+#define VFC_SAA9051_CO (0x10)
+#define VFC_SAA9051_VTR (0x20)
+#define VFC_SAA9051_FS (0x40)
+#define VFC_SAA9051_HPLL (0x80)
+
+
+/* Bit settings for saa9051 sub address 9 */
+
+#define VFC_SAA9051_SS0 (0x01)
+#define VFC_SAA9051_SS1 (0x02)
+#define VFC_SAA9051_AFCC (0x04)
+#define VFC_SAA9051_CI (0x08)
+#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */
+#define VFC_SAA9051_OEC (0x20)
+#define VFC_SAA9051_OEY (0x40)
+#define VFC_SAA9051_VNL (0x80)
+
+
+/* Bit settings for saa9051 sub address 0x0A */
+
+#define VFC_SAA9051_YDL0 (0x01)
+#define VFC_SAA9051_YDL1 (0x02)
+#define VFC_SAA9051_YDL2 (0x04)
+#define VFC_SAA9051_SS2 (0x08)
+#define VFC_SAA9051_SS3 (0x10)
+#define VFC_SAA9051_YC (0x20)
+#define VFC_SAA9051_CT (0x40)
+#define VFC_SAA9051_SYC (0x80)
+
+
+#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1])
+#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\
+ (a)->saa9051_state_array,\
+ VFC_SAA9051_NR))
+
+
+struct vfc_dev {
+ volatile struct vfc_regs *regs;
+ struct vfc_regs *phys_regs;
+ unsigned int control_reg;
+ struct semaphore device_lock_sem;
+ struct timer_list poll_timer;
+ struct wait_queue *poll_wait;
+ int instance;
+ int busy;
+ unsigned long which_io;
+ unsigned char saa9051_state_array[VFC_SAA9051_NR];
+};
+
+extern struct vfc_dev **vfc_dev_lst;
+
+void captstat_reset(struct vfc_dev *);
+void memptr_reset(struct vfc_dev *);
+
+int vfc_pcf8584_init(struct vfc_dev *);
+void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long);
+void vfc_i2c_delay(struct vfc_dev *);
+int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ;
+int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ;
+int vfc_i2c_reset_bus(struct vfc_dev *);
+int vfc_init_i2c_bus(struct vfc_dev *);
+void vfc_lock_device(struct vfc_dev *);
+void vfc_unlock_device(struct vfc_dev *);
+
+#define VFC_CONTROL_DIAGMODE 0x10000000
+#define VFC_CONTROL_MEMPTR 0x20000000
+#define VFC_CONTROL_CAPTURE 0x02000000
+#define VFC_CONTROL_CAPTRESET 0x04000000
+
+#define VFC_STATUS_CAPTURE 0x08000000
+
+#ifdef VFC_DEBUG
+#define VFC_DEBUG_PRINTK(a) printk a
+#else
+#define VFC_DEBUG_PRINTK(a)
+#endif
+
+#endif /* _LINUX_VFC_H_ */
+
+
+
+
+
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
new file mode 100644
index 000000000..556d06e9f
--- /dev/null
+++ b/drivers/sbus/char/vfc_dev.c
@@ -0,0 +1,693 @@
+/*
+ * drivers/sbus/char/vfc_dev.c
+ *
+ * Driver for the Videopix Frame Grabber.
+ *
+ * In order to use the VFC you need to progeam the video controller
+ * chip. This chip is the Phillips SAA9051. You need to call their
+ * documentation ordering line to get the docs.
+ *
+ * Their is very little documentation on the VFC itself. There is
+ * some useful info that can be found in the manuals that come with
+ * the card. I will hopefully write some better docs at a later date.
+ *
+ * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
+ * */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sbus.h>
+#include <asm/delay.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+#define VFC_MAJOR (60)
+
+#if 0
+#define VFC_DEBUG
+#endif
+
+#include "vfc.h"
+#include <asm/vfc_ioctls.h>
+
+struct vfc_dev **vfc_dev_lst;
+static char vfcstr[]="vfc";
+static unsigned char saa9051_init_array[VFC_SAA9051_NR]=
+{ 0x00, 0x64, 0x72, 0x52,
+ 0x36, 0x18, 0xff, 0x20,
+ 0xfc, 0x77, 0xe3, 0x50,
+ 0x3e};
+
+void vfc_lock_device(struct vfc_dev *dev) {
+ down(&dev->device_lock_sem);
+}
+
+void vfc_unlock_device(struct vfc_dev *dev) {
+ up(&dev->device_lock_sem);
+}
+
+
+void vfc_captstat_reset(struct vfc_dev *dev)
+{
+ dev->control_reg |= VFC_CONTROL_CAPTRESET;
+ dev->regs->control=dev->control_reg;
+ dev->control_reg &= ~VFC_CONTROL_CAPTRESET;
+ dev->regs->control=dev->control_reg;
+ dev->control_reg |= VFC_CONTROL_CAPTRESET;
+ dev->regs->control=dev->control_reg;
+ return;
+}
+
+void vfc_memptr_reset(struct vfc_dev *dev)
+{
+ dev->control_reg |= VFC_CONTROL_MEMPTR;
+ dev->regs->control = dev->control_reg;
+ dev->control_reg &= ~VFC_CONTROL_MEMPTR;
+ dev->regs->control = dev->control_reg;
+ dev->control_reg |= VFC_CONTROL_MEMPTR;
+ dev->regs->control = dev->control_reg;
+ return;
+}
+
+int vfc_csr_init(struct vfc_dev *dev)
+{
+ dev->control_reg = 0x80000000;
+ dev->regs->control = dev->control_reg;
+ udelay(200);
+ dev->control_reg &= ~0x80000000;
+ dev->regs->control = dev->control_reg;
+ udelay(100);
+ dev->regs->i2c_magic2 = 0x0f000000;
+
+ vfc_memptr_reset(dev);
+
+ dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
+ dev->control_reg &= ~VFC_CONTROL_CAPTURE;
+ dev->control_reg |= 0x40000000;
+ dev->regs->control=dev->control_reg;
+
+ vfc_captstat_reset(dev);
+
+ return 0;
+}
+
+int vfc_saa9051_init(struct vfc_dev *dev)
+{
+ int i;
+ for(i=0;i<VFC_SAA9051_NR;i++) {
+ dev->saa9051_state_array[i]=saa9051_init_array[i];
+ }
+ vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR,
+ dev->saa9051_state_array, VFC_SAA9051_NR);
+ return 0;
+}
+
+int init_vfc_hw(struct vfc_dev *dev)
+{
+ vfc_lock_device(dev);
+ vfc_csr_init(dev);
+
+ vfc_pcf8584_init(dev);
+ vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic
+ sun code above*/
+ vfc_saa9051_init(dev);
+ vfc_unlock_device(dev);
+ return 0;
+}
+
+int init_vfc_devstruct(struct vfc_dev *dev, int instance)
+{
+ dev->instance=instance;
+ dev->device_lock_sem=MUTEX;
+ dev->control_reg=0;
+ dev->poll_wait=NULL;
+ dev->busy=0;
+ /* initialize the timer struct */
+ return 0;
+}
+
+int init_vfc_device(struct linux_sbus_device *sdev,struct vfc_dev *dev,
+ int instance) {
+ struct linux_prom_registers reg;
+ if(!dev) {
+ printk(KERN_ERR "VFC: Bogus pointer passed\n");
+ return -ENOMEM;
+ }
+ printk("Initializing vfc%d\n",instance);
+ dev->regs=NULL;
+ memcpy(&reg,&sdev->reg_addrs[0],sizeof(struct linux_prom_registers));
+ prom_apply_sbus_ranges(sdev->my_bus, &reg, sdev->num_registers, sdev);
+ dev->regs=sparc_alloc_io(reg.phys_addr, 0,
+ sizeof(struct vfc_regs), vfcstr,
+ reg.which_io, 0x0);
+ dev->which_io=reg.which_io;
+ dev->phys_regs=(struct vfc_regs *)reg.phys_addr;
+ if(!dev->regs) return -EIO;
+
+ printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n",
+ instance,(unsigned long)reg.phys_addr,(unsigned long)dev->regs);
+
+ if(init_vfc_devstruct(dev,instance)) return -EINVAL;
+ if(init_vfc_hw(dev)) return -EIO;
+
+ return 0;
+}
+
+
+struct vfc_dev *vfc_get_dev_ptr(int instance)
+{
+ return vfc_dev_lst[instance];
+}
+
+static int vfc_open(struct inode *inode, struct file *file)
+{
+ struct vfc_dev *dev;
+ dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
+ if(!dev) return -ENODEV;
+ if(dev->busy) return -EBUSY;
+ dev->busy=1;
+ MOD_INC_USE_COUNT;
+ vfc_lock_device(dev);
+
+ vfc_csr_init(dev);
+ vfc_pcf8584_init(dev);
+ vfc_init_i2c_bus(dev);
+ vfc_saa9051_init(dev);
+ vfc_memptr_reset(dev);
+ vfc_captstat_reset(dev);
+
+ vfc_unlock_device(dev);
+ return 0;
+}
+
+static int vfc_release(struct inode *inode,struct file *file)
+{
+ struct vfc_dev *dev;
+ dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
+ if(!dev) return -EINVAL;
+ if(!dev->busy) return 0;
+ dev->busy=0;
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg)
+{
+ struct vfc_debug_inout inout;
+ unsigned char *buffer;
+
+ switch(cmd) {
+ case VFC_I2C_SEND:
+ if(copy_from_user(&inout, (void *)arg, sizeof(inout)))
+ return -EFAULT;
+
+ buffer = kmalloc(inout.len*sizeof(char), GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ if(copy_from_user(buffer, inout.buffer, inout.len*sizeof(char))) {
+ kfree_s(buffer,inout.len);
+ return -EFAULT;
+ }
+
+ vfc_lock_device(dev);
+ inout.ret=
+ vfc_i2c_sendbuf(dev,inout.addr & 0xff,
+ inout.buffer,inout.len);
+ if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
+ kfree_s(buffer,inout.len);
+ return -EFAULT;
+ }
+ vfc_unlock_device(dev);
+
+ kfree_s(buffer, inout.len);
+
+ break;
+ case VFC_I2C_RECV:
+
+ if(copy_from_user(&inout, (void *)arg, sizeof(inout)))
+ return -EFAULT;
+
+ buffer = kmalloc(inout.len, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ memset(buffer,0,inout.len*sizeof(char));
+ vfc_lock_device(dev);
+ inout.ret=
+ vfc_i2c_recvbuf(dev,inout.addr & 0xff
+ ,buffer,inout.len);
+ vfc_unlock_device(dev);
+
+ if(copy_to_user(inout.buffer, buffer, inout.len)) {
+ kfree_s(buffer,inout.len);
+ return -EFAULT;
+ }
+ if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
+ kfree_s(buffer,inout.len);
+ return -EFAULT;
+ }
+ kfree_s(buffer,inout.len);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int vfc_capture_start(struct vfc_dev *dev)
+{
+ vfc_captstat_reset(dev);
+ dev->control_reg=dev->regs->control;
+ if((dev->control_reg & VFC_STATUS_CAPTURE)) {
+ printk(KERN_ERR "vfc%d: vfc capture status not reset\n",
+ dev->instance);
+ return -EIO;
+ }
+
+ vfc_lock_device(dev);
+ dev->control_reg &= ~VFC_CONTROL_CAPTURE;
+ dev->regs->control=dev->control_reg;
+ dev->control_reg |= VFC_CONTROL_CAPTURE;
+ dev->regs->control=dev->control_reg;
+ dev->control_reg &= ~VFC_CONTROL_CAPTURE;
+ dev->regs->control=dev->control_reg;
+ vfc_unlock_device(dev);
+
+ return 0;
+}
+
+int vfc_capture_poll(struct vfc_dev *dev)
+{
+ int timeout=1000;
+ while(!timeout--) {
+ if((dev->regs->control & VFC_STATUS_CAPTURE)) break;
+ vfc_i2c_delay_no_busy(dev,100);
+ }
+ if(!timeout) {
+ printk(KERN_WARNING "vfc%d: capture timed out\n", dev->instance);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+
+
+static int vfc_set_control_ioctl(struct inode *inode, struct file *file,
+ struct vfc_dev *dev, unsigned long arg)
+{
+ int setcmd,ret=0;
+ if(copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int)))
+ return -EFAULT;
+#if 0
+ VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
+ dev->instance,setcmd));
+#endif
+ switch(setcmd) {
+ case MEMPRST:
+ vfc_lock_device(dev);
+ vfc_memptr_reset(dev);
+ vfc_unlock_device(dev);
+ ret=0;
+ break;
+ case CAPTRCMD:
+ vfc_capture_start(dev);
+ vfc_capture_poll(dev);
+ break;
+ case DIAGMODE:
+ if(suser()) {
+ vfc_lock_device(dev);
+ dev->control_reg |= VFC_CONTROL_DIAGMODE;
+ dev->regs->control = dev->control_reg;
+ vfc_unlock_device(dev);
+ ret=0;
+ } else ret=-EPERM;
+ break;
+ case NORMMODE:
+ vfc_lock_device(dev);
+ dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
+ dev->regs->control = dev->control_reg;
+ vfc_unlock_device(dev);
+ ret=0;
+ break;
+ case CAPTRSTR:
+ vfc_capture_start(dev);
+ ret=0;
+ break;
+ case CAPTRWAIT:
+ vfc_capture_poll(dev);
+ ret=0;
+ break;
+ default:
+ ret=-EINVAL;
+ }
+ return ret;
+}
+
+
+int vfc_port_change_ioctl(struct inode *inode, struct file *file,
+ struct vfc_dev *dev, unsigned long arg)
+{
+ int ret=0;
+ int cmd;
+ if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
+ VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+ "vfc_port_change_ioctl\n",dev->instance));
+ return -EFAULT;
+ }
+
+ VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
+ dev->instance,cmd));
+
+ switch(cmd) {
+ case 1:
+ case 2:
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e;
+ break;
+ case 3:
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
+ break;
+ default:
+ ret=-EINVAL;
+ return ret;
+ break;
+ }
+
+ switch(cmd) {
+ case 1:
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0 | VFC_SAA9051_SS1;
+ break;
+ case 2:
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0;
+ break;
+ case 3:
+ break;
+ default:
+ ret=-EINVAL;
+ return ret;
+ break;
+ }
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2);
+ ret=vfc_update_saa9051(dev);
+ udelay(500);
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2);
+ ret=vfc_update_saa9051(dev);
+ return ret;
+}
+
+int vfc_set_video_ioctl(struct inode *inode, struct file *file,
+ struct vfc_dev *dev, unsigned long arg)
+{
+ int ret=0;
+ int cmd;
+ if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
+ VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+ "vfc_set_video_ioctl\n",dev->instance));
+ return -EFAULT;
+ }
+
+ VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
+ dev->instance,cmd));
+ switch(cmd) {
+
+ case STD_NTSC:
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN |
+ VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS;
+ ret=vfc_update_saa9051(dev);
+ break;
+ case STD_PAL:
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN |
+ VFC_SAA9051_CCFR1 |
+ VFC_SAA9051_CCFR0 |
+ VFC_SAA9051_FS);
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT;
+ ret=vfc_update_saa9051(dev);
+ break;
+
+ case COLOR_ON:
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO;
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &= ~(VFC_SAA9051_BY | VFC_SAA9051_PF);
+ ret=vfc_update_saa9051(dev);
+ break;
+ case MONO:
+ VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO);
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |= VFC_SAA9051_BY | VFC_SAA9051_PF;
+ ret=vfc_update_saa9051(dev);
+ break;
+ default:
+ ret=-EINVAL;
+ break;
+ }
+ return ret;
+}
+
+int vfc_get_video_ioctl(struct inode *inode, struct file *file,
+ struct vfc_dev *dev, unsigned long arg)
+{
+ int ret=0;
+ unsigned int status=NO_LOCK;
+ unsigned char buf[1];
+
+ if(vfc_i2c_recvbuf(dev,VFC_SAA9051_ADDR,buf,1)) {
+ printk(KERN_ERR "vfc%d: Unable to get status\n",dev->instance);
+ return -EIO;
+ }
+
+ if(buf[0] & VFC_SAA9051_HLOCK) {
+ status = NO_LOCK;
+ } else if(buf[0] & VFC_SAA9051_FD) {
+ if(buf[0] & VFC_SAA9051_CD)
+ status=NTSC_COLOR;
+ else
+ status=NTSC_NOCOLOR;
+ } else {
+ if(buf[0] & VFC_SAA9051_CD)
+ status=PAL_COLOR;
+ else
+ status=PAL_NOCOLOR;
+ }
+ VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance,
+ status,buf[0]));
+ if(copy_to_user((void *)arg,&status,sizeof(unsigned int))) {
+ VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+ "vfc_get_video_ioctl\n",dev->instance));
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret=0;
+ unsigned int tmp;
+ struct vfc_dev *dev;
+
+ dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
+ if(!dev) return -ENODEV;
+
+ switch(cmd & 0x0000ffff) {
+ case VFCGCTRL:
+#if 0
+ VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance));
+#endif
+ tmp=dev->regs->control;
+ if(copy_to_user((void *)arg,&tmp,sizeof(unsigned int)))
+ return -EFAULT;
+ ret=0;
+ break;
+ case VFCSCTRL:
+ ret=vfc_set_control_ioctl(inode, file, dev, arg);
+ break;
+ case VFCGVID:
+ ret=vfc_get_video_ioctl(inode,file,dev,arg);
+ break;
+ case VFCSVID:
+ ret=vfc_set_video_ioctl(inode,file,dev,arg);
+ break;
+ case VFCHUE:
+#if 0
+ VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance));
+#endif
+
+ if(copy_from_user(&tmp,(void *)arg,sizeof(unsigned int))) {
+ VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
+ "to IOCTL(VFCHUE)",dev->instance));
+ ret=-EFAULT;
+ } else {
+ VFC_SAA9051_SA(dev,VFC_SAA9051_HUE)=tmp;
+ vfc_update_saa9051(dev);
+ ret=0;
+ }
+ break;
+ case VFCPORTCHG:
+ ret=vfc_port_change_ioctl(inode, file, dev, arg);
+ break;
+ case VFCRDINFO:
+ ret=-EINVAL;
+ VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance));
+ break;
+ default:
+ ret=vfc_debug(vfc_get_dev_ptr(MINOR(inode->i_rdev)),
+ cmd,arg);
+ break;
+ }
+ return ret;
+}
+
+static int vfc_mmap(struct inode *inode, struct file *file,
+ struct vm_area_struct *vma)
+{
+ unsigned int map_size,ret,map_offset;
+ struct vfc_dev *dev;
+
+ dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
+ if(!dev) return -ENODEV;
+
+ map_size=vma->vm_end - vma->vm_start;
+ if(map_size > sizeof(struct vfc_regs))
+ map_size=sizeof(struct vfc_regs);
+
+
+ if(vma->vm_offset & ~PAGE_MASK) return -ENXIO;
+ vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE;
+ map_offset=(unsigned int)dev->phys_regs;
+ ret=io_remap_page_range(vma->vm_start,map_offset,map_size,
+ vma->vm_page_prot, dev->which_io);
+ if(ret) return -EAGAIN;
+ vma->vm_inode=inode;
+ inode->i_count++;
+ return 0;
+}
+
+static long long vfc_lseek(struct inode *inode, struct file *file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static struct file_operations vfc_fops = {
+ vfc_lseek, /* vfc_lseek */
+ NULL, /* vfc_write */
+ NULL, /* vfc_read */
+ NULL, /* vfc_readdir */
+ NULL, /* vfc_poll */
+ vfc_ioctl,
+ vfc_mmap,
+ vfc_open,
+ vfc_release,
+};
+
+
+static int vfc_probe(void)
+{
+ struct linux_sbus *bus;
+ struct linux_sbus_device *sdev = NULL;
+ int ret;
+ int instance=0,cards=0;
+
+ for_all_sbusdev(sdev,bus) {
+ if (strcmp(sdev->prom_name,"vfc") == 0) {
+ cards++;
+ continue;
+ }
+ }
+
+ if (!cards)
+ return -ENODEV;
+
+ vfc_dev_lst=(struct vfc_dev **)kmalloc(sizeof(struct vfc_dev *)*
+ (cards+1),
+ GFP_KERNEL);
+ if(!vfc_dev_lst)
+ return -ENOMEM;
+ memset(vfc_dev_lst,0,sizeof(struct vfc_dev *)*(cards+1));
+ vfc_dev_lst[cards]=NULL;
+
+ ret=register_chrdev(VFC_MAJOR,vfcstr,&vfc_fops);
+ if(ret) {
+ printk(KERN_ERR "Unable to get major number %d\n",VFC_MAJOR);
+ kfree(vfc_dev_lst);
+ return -EIO;
+ }
+
+ instance=0;
+ for_all_sbusdev(sdev,bus) {
+ if (strcmp(sdev->prom_name,"vfc") == 0) {
+ vfc_dev_lst[instance]=(struct vfc_dev *)
+ kmalloc(sizeof(struct vfc_dev), GFP_KERNEL);
+ if(vfc_dev_lst[instance] == NULL) return -ENOMEM;
+ ret=init_vfc_device(sdev,
+ vfc_dev_lst[instance],
+ instance);
+ if(ret) {
+ printk(KERN_ERR "Unable to initialize"
+ " vfc%d device\n",instance);
+ } else {
+ }
+
+ instance++;
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+int vfc_init(void)
+#endif
+{
+#ifdef MODULE
+ register_symtab(0);
+#endif
+ return vfc_probe();
+}
+
+#ifdef MODULE
+static void deinit_vfc_device(struct vfc_dev *dev)
+{
+ if(!dev) return;
+ sparc_free_io((void *)dev->regs,sizeof(struct vfc_regs));
+ kfree(dev);
+}
+
+void cleanup_module(void)
+{
+ struct vfc_dev **devp;
+ unregister_chrdev(VFC_MAJOR,vfcstr);
+ for(devp=vfc_dev_lst;*devp;devp++) {
+ deinit_vfc_device(*devp);
+ }
+ kfree(vfc_dev_lst);
+ return;
+}
+#endif
+
+
diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
new file mode 100644
index 000000000..952eb9875
--- /dev/null
+++ b/drivers/sbus/char/vfc_i2c.c
@@ -0,0 +1,319 @@
+/*
+ * drivers/sbus/char/vfc_i2c.c
+ *
+ * Driver for the Videopix Frame Grabber.
+ *
+ * Functions that support the Phillips i2c(I squared C) bus on the vfc
+ * Documentation for the Phillips I2C bus can be found on the
+ * phillips home page
+ *
+ * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
+ *
+ */
+
+/* NOTE: It seems to me that the documentation regarding the
+pcd8584t/pcf8584 does not show the correct way to address the i2c bus.
+Based on the information on the I2C bus itself and the remainder of
+the Phillips docs the following algorithims apper to be correct. I am
+fairly certain that the flowcharts in the phillips docs are wrong. */
+
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sbus.h>
+
+#if 0
+#define VFC_DEBUG
+#endif
+
+#include "vfc.h"
+#include "vfc_i2c.h"
+
+#define VFC_I2C_READ (0x1)
+#define VFC_I2C_WRITE (0x0)
+
+/******
+ The i2c bus controller chip on the VFC is a pcd8584t, but
+ phillips claims it doesn't exist. As far as I can tell it is
+ identical to the PCF8584 so I treat it like it is the pcf8584.
+
+ NOTE: The pcf8584 only cares
+ about the msb of the word you feed it
+*****/
+
+int vfc_pcf8584_init(struct vfc_dev *dev)
+{
+ dev->regs->i2c_s1=RESET; /* This will also choose
+ register S0_OWN so we can set it*/
+
+ dev->regs->i2c_reg=0x55000000; /* the pcf8584 shifts this
+ value left one bit and uses
+ it as its i2c bus address */
+ dev->regs->i2c_s1=SELECT(S2);
+ dev->regs->i2c_reg=0x14000000; /* this will set the i2c bus at
+ the same speed sun uses,
+ and set another magic bit */
+
+ dev->regs->i2c_s1=CLEAR_I2C_BUS; /* enable the serial port,
+ idle the i2c bus and set
+ the data reg to s0 */
+ udelay(100);
+ return 0;
+}
+
+void vfc_i2c_delay_wakeup(struct vfc_dev *dev)
+{
+ wake_up(&dev->poll_wait);
+}
+
+void vfc_i2c_delay_no_busy(struct vfc_dev *dev,unsigned long usecs)
+{
+ dev->poll_timer.next = NULL;
+ dev->poll_timer.prev = NULL;
+ dev->poll_timer.expires = jiffies +
+ ((unsigned long)usecs*(HZ))/1000000;
+ dev->poll_timer.data=(unsigned long)dev;
+ dev->poll_timer.function=(void *)(unsigned long)vfc_i2c_delay_wakeup;
+ add_timer(&dev->poll_timer);
+ sleep_on(&dev->poll_wait);
+ del_timer(&dev->poll_timer);
+}
+
+void inline vfc_i2c_delay(struct vfc_dev *dev)
+{
+ vfc_i2c_delay_no_busy(dev,100);
+}
+
+int vfc_init_i2c_bus(struct vfc_dev *dev)
+{
+ dev->regs->i2c_s1= ENABLE_SERIAL | ACK;
+ vfc_i2c_reset_bus(dev);
+ return 0;
+}
+
+int vfc_i2c_reset_bus(struct vfc_dev *dev)
+{
+ VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
+ dev->instance));
+ if(!dev) return -EINVAL;
+ if(!dev->regs) return -EINVAL;
+ dev->regs->i2c_s1=SEND_I2C_STOP;
+ dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
+ vfc_i2c_delay(dev);
+ dev->regs->i2c_s1=CLEAR_I2C_BUS;
+ VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
+ dev->instance, dev->regs->i2c_s1));
+ return 0;
+}
+
+int vfc_i2c_wait_for_bus(struct vfc_dev *dev)
+{
+ int timeout=1000;
+
+ while(!(dev->regs->i2c_s1 & BB)) {
+ if(!(timeout--)) return -ETIMEDOUT;
+ vfc_i2c_delay(dev);
+ }
+ return 0;
+}
+
+int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack)
+{
+ int timeout=1000;
+ int s1;
+
+ while((s1=dev->regs->i2c_s1) & PIN) {
+ if(!(timeout--)) return -ETIMEDOUT;
+ vfc_i2c_delay(dev);
+ }
+ if(ack==VFC_I2C_ACK_CHECK) {
+ if(s1 & LRB) return -EIO;
+ }
+ return 0;
+}
+
+#define SHIFT(a) ((a) << 24)
+int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, char mode)
+{
+ int ret,raddr;
+#if 1
+ dev->regs->i2c_s1=SEND_I2C_STOP;
+ dev->regs->i2c_s1=SELECT(S0) | ENABLE_SERIAL;
+ vfc_i2c_delay(dev);
+#endif
+
+ switch(mode) {
+ case VFC_I2C_READ:
+ dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr | 0x1);
+ VFC_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n",
+ dev->instance,addr | 0x1));
+ break;
+ case VFC_I2C_WRITE:
+ dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr & ~0x1);
+ VFC_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
+ dev->instance,addr & ~0x1));
+ break;
+ default:
+ return -EINVAL;
+ }
+ dev->regs->i2c_s1 = SEND_I2C_START;
+ vfc_i2c_delay(dev);
+ ret=vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait
+ for the
+ i2c send
+ to finish
+ here but
+ Sun
+ doesn't,
+ hmm */
+ if(ret) {
+ printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n",
+ dev->instance);
+ return ret;
+ } else if(mode == VFC_I2C_READ) {
+ if((ret=dev->regs->i2c_reg & 0xff000000) != raddr) {
+ printk(KERN_WARNING
+ "vfc%d: returned slave address "
+ "mismatch(%x,%x)\n",
+ dev->instance,raddr,ret);
+ }
+ }
+ return 0;
+}
+
+int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte)
+{
+ int ret;
+ dev->regs->i2c_reg=SHIFT((unsigned int)*byte);
+
+ ret=vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK);
+ switch(ret) {
+ case -ETIMEDOUT:
+ printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n",
+ dev->instance);
+ break;
+ case -EIO:
+ ret=XMIT_LAST_BYTE;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte, int last)
+{
+ int ret;
+ if(last) {
+ dev->regs->i2c_reg=NEGATIVE_ACK;
+ VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: sending negative ack\n",
+ dev->instance));
+ } else {
+ dev->regs->i2c_s1=ACK;
+ }
+
+ ret=vfc_i2c_wait_for_pin(dev,VFC_I2C_NO_ACK_CHECK);
+ if(ret) {
+ printk(KERN_ERR "vfc%d: "
+ "VFC recv byte timed out\n",dev->instance);
+ }
+ *byte=(dev->regs->i2c_reg) >> 24;
+ return ret;
+}
+
+int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr,
+ char *buf, int count)
+{
+ int ret,last;
+
+ if(!(count && buf && dev && dev->regs) ) return -EINVAL;
+
+ if((ret=vfc_i2c_wait_for_bus(dev))) {
+ printk(KERN_ERR "vfc%d: VFC I2C bus busy\n",dev->instance);
+ return ret;
+ }
+
+ if((ret=vfc_i2c_xmit_addr(dev,addr,VFC_I2C_READ))) {
+ dev->regs->i2c_s1=SEND_I2C_STOP;
+ vfc_i2c_delay(dev);
+ return ret;
+ }
+
+ last=0;
+ while(count--) {
+ if(!count) last=1;
+ if((ret=vfc_i2c_recv_byte(dev,buf,last))) {
+ printk(KERN_ERR "vfc%d: "
+ "VFC error while recieving byte\n",
+ dev->instance);
+ }
+ buf++;
+ }
+
+ dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
+ vfc_i2c_delay(dev);
+ return ret;
+}
+
+int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr,
+ char *buf, int count)
+{
+ int ret;
+
+ if(!(buf && dev && dev->regs) ) return -EINVAL;
+
+ if((ret=vfc_i2c_wait_for_bus(dev))) {
+ printk(KERN_ERR "vfc%d: VFC I2C bus busy\n",dev->instance);
+ return ret;
+ }
+
+ if((ret=vfc_i2c_xmit_addr(dev,addr,VFC_I2C_WRITE))) {
+ dev->regs->i2c_s1=SEND_I2C_STOP;
+ vfc_i2c_delay(dev);
+ return ret;
+ }
+
+ while(count--) {
+ ret=vfc_i2c_xmit_byte(dev,buf);
+ switch(ret) {
+ case XMIT_LAST_BYTE:
+ VFC_DEBUG_PRINTK(("vfc%d: "
+ "Reciever ended transmission with "
+ " %d bytes remaining\n",
+ dev->instance,count));
+ ret=0;
+ goto done;
+ break;
+ case 0:
+ break;
+ default:
+ printk(KERN_ERR "vfc%d: "
+ "VFC error while sending byte\n",dev->instance);
+ break;
+ }
+ buf++;
+ }
+done:
+ dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
+
+ vfc_i2c_delay(dev);
+ return ret;
+}
+
+
+
+
+
+
+
+
+
diff --git a/drivers/sbus/char/vfc_i2c.h b/drivers/sbus/char/vfc_i2c.h
new file mode 100644
index 000000000..a2e697320
--- /dev/null
+++ b/drivers/sbus/char/vfc_i2c.h
@@ -0,0 +1,44 @@
+#ifndef _LINUX_VFC_I2C_H_
+#define _LINUX_VFC_I2C_H_
+
+/* control bits */
+#define PIN (0x80000000)
+#define ESO (0x40000000)
+#define ES1 (0x20000000)
+#define ES2 (0x10000000)
+#define ENI (0x08000000)
+#define STA (0x04000000)
+#define STO (0x02000000)
+#define ACK (0x01000000)
+
+/* status bits */
+#define STS (0x20000000)
+#define BER (0x10000000)
+#define LRB (0x08000000)
+#define AAS (0x04000000)
+#define LAB (0x02000000)
+#define BB (0x01000000)
+
+#define SEND_I2C_START (PIN | ESO | STA)
+#define SEND_I2C_STOP (PIN | ESO | STO)
+#define CLEAR_I2C_BUS (PIN | ESO | ACK)
+#define NEGATIVE_ACK ((ESO) & ~ACK)
+
+#define SELECT(a) (a)
+#define S0 (PIN | ESO | ES1)
+#define S0_OWN (PIN)
+#define S2 (PIN | ES1)
+#define S3 (PIN | ES2)
+
+#define ENABLE_SERIAL (PIN | ESO)
+#define DISABLE_SERIAL (PIN)
+#define RESET (PIN)
+
+#define XMIT_LAST_BYTE (1)
+#define VFC_I2C_ACK_CHECK (1)
+#define VFC_I2C_NO_ACK_CHECK (0)
+
+#endif /* _LINUX_VFC_I2C_H_ */
+
+
+
diff --git a/drivers/sbus/char/weitek.c b/drivers/sbus/char/weitek.c
new file mode 100644
index 000000000..0fa0cb5fc
--- /dev/null
+++ b/drivers/sbus/char/weitek.c
@@ -0,0 +1,116 @@
+/* $Id: weitek.c,v 1.9 1997/04/14 17:04:57 jj Exp $
+ * weitek.c: Tadpole P9100/P9000 console driver
+ *
+ * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
+ */
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+
+#include <asm/openprom.h>
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/*
+ * mmap info
+ */
+#define WEITEK_VRAM_OFFSET 0
+#define WEITEK_VRAM_SIZE (2*1024*1024) /* maximum */
+#define WEITEK_GX_REG_OFFSET WEITEK_VRAM_SIZE
+#define WEITEK_GX_REG_SIZE 8192
+#define WEITEK_VID_REG_OFFSET (WEITEK_GX_REG_OFFSET+WEITEK_GX_REG_SIZE)
+#define WEITEK_VID_REG_SIZE 0x1000
+
+#define CONTROL_OFFSET 0
+#define RAMDAC_OFFSET (CONTROL_OFFSET+0x200)
+
+#if 0
+static int
+weitek_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma,
+ long base, fbinfo_t *fb)
+{
+ unsigned int size, page, r, map_size;
+ unsigned int map_offset = 0;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages */
+ vma->vm_flags |= FB_MMAP_VM_FLAGS;
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ){
+ switch (vma->vm_offset+page){
+ case WEITEK_VRAM_OFFSET:
+ map_size = size-page;
+ map_offset = get_phys ((unsigned long) fb->base);
+ if (map_size > fb->type.fb_size)
+ map_size = fb->type.fb_size;
+ break;
+ case WEITEK_GX_REG_OFFSET:
+ map_size = size-page;
+ map_offset = get_phys ((unsigned long) fb->base);
+ if (map_size > fb->type.fb_size)
+ map_size = fb->type.fb_size;
+ break;
+ default:
+ map_size = 0;
+ break;
+ }
+ if (!map_size){
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+ r = io_remap_page_range (vma->vm_start+page,
+ map_offset,
+ map_size, vma->vm_page_prot,
+ fb->space);
+ if (r) return -EAGAIN;
+ page += map_size;
+ }
+ vma->vm_inode = inode;
+ inode->i_count++;
+ return 0;
+}
+#endif
+
+#if 0
+static void
+weitek_loadcmap (void *fbinfo, int index, int count)
+{
+ printk("weitek_cmap: unimplemented!\n");
+}
+#endif
+
+__initfunc(void weitek_setup(fbinfo_t *fb, int slot, u32 addr, int io))
+{
+ extern struct screen_info screen_info;
+
+ printk ("weitek%d at 0x%8.8x\n", slot, addr);
+
+ /* Fill in parameters we left out */
+ fb->type.fb_type = FBTYPE_NOTSUN1;
+ fb->type.fb_cmsize = 256;
+ fb->mmap = 0; /* weitek_mmap; */
+ fb->loadcmap = 0; /* unimplemented */
+ fb->ioctl = 0; /* no special ioctls */
+ fb->reset = 0; /* no special reset */
+
+ /* Map the card registers */
+ if (!fb->base){
+ prom_printf ("Missing mapping routine and no address found\n");
+ }
+}