summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHarald Koerfgen <hkoerfg@web.de>2000-12-30 15:55:57 +0000
committerHarald Koerfgen <hkoerfg@web.de>2000-12-30 15:55:57 +0000
commit5ffede5ab53ed46d1fe59f902062ba06bde59bbd (patch)
tree5ecd8d67d3f1f6c5896e3feff2bda63b1538a338 /drivers
parent2cb8ea0ed322d8fdf15bfb726dd0d684b9eafdaf (diff)
LK201 keyboard and PMAG-BA framebuffer driver for DECstations
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/tc/.cvsignore3
-rw-r--r--drivers/tc/Makefile4
-rw-r--r--drivers/tc/lk201-map.map356
-rw-r--r--drivers/tc/lk201-remap.c150
-rw-r--r--drivers/tc/lk201.c217
-rw-r--r--drivers/tc/lk201.h53
-rw-r--r--drivers/tc/zs.c507
-rw-r--r--drivers/tc/zs.h14
-rw-r--r--drivers/video/Config.in5
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/fbmem.c5
-rw-r--r--drivers/video/pmag-ba-fb.c440
13 files changed, 1598 insertions, 159 deletions
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 57d52cd88..055c42fe8 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -90,6 +90,7 @@ ifeq ($(ARCH),sh)
endif
ifeq ($(CONFIG_DECSTATION),y)
+ KEYMAP =
KEYBD =
SERIAL =
endif
diff --git a/drivers/tc/.cvsignore b/drivers/tc/.cvsignore
index 6d007a06f..caaad2935 100644
--- a/drivers/tc/.cvsignore
+++ b/drivers/tc/.cvsignore
@@ -1,4 +1,3 @@
.depend
.*.flags
-aic7xxx_asm
-aic7xxx_seq.h
+lk201-map.c
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index e378a20c7..18f4ce135 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -21,6 +21,7 @@ obj- :=
obj-$(CONFIG_TC) += tc.o
obj-$(CONFIG_ZS) += zs.o
+obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
# Files that are both resident and modular: remove from modular.
@@ -37,3 +38,6 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
include $(TOPDIR)/Rules.make
+lk201-map.c: lk201-map.map
+ loadkeys --mktable lk201-map.map > lk201-map.c
+
diff --git a/drivers/tc/lk201-map.map b/drivers/tc/lk201-map.map
new file mode 100644
index 000000000..a52acf7f9
--- /dev/null
+++ b/drivers/tc/lk201-map.map
@@ -0,0 +1,356 @@
+# Default kernel keymap. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# Change the above line into
+# keymaps 0-2,4-6,8,12
+# in case you want the entries
+# altgr control keycode 83 = Boot
+# altgr control keycode 111 = Boot
+# below.
+#
+# In fact AltGr is used very little, and one more keymap can
+# be saved by mapping AltGr to Alt (and adapting a few entries):
+# keycode 100 = Alt
+#
+keycode 0x15 = grave tilde
+ alt keycode 0x15 = Escape
+ control keycode 0x15 = Meta_Escape
+keycode 0x16 = one exclam
+ alt keycode 0x16 = Meta_one
+keycode 0x17 = two at at
+ control keycode 0x17 = nul
+ shift control keycode 0x17 = nul
+ alt keycode 0x17 = Meta_two
+keycode 0x18 = three numbersign
+ control keycode 0x18 = Escape
+ alt keycode 0x18 = Meta_three
+keycode 0x19 = four dollar dollar
+ control keycode 0x19 = Control_backslash
+ alt keycode 0x19 = Meta_four
+keycode 0x1a = five percent
+ control keycode 0x1a = Control_bracketright
+ alt keycode 0x1a = Meta_five
+keycode 0x1b = six asciicircum
+ control keycode 0x1b = Control_asciicircum
+ alt keycode 0x1b = Meta_six
+keycode 0x1c = seven ampersand braceleft
+ control keycode 0x1c = Control_underscore
+ alt keycode 0x1c = Meta_seven
+keycode 0x1d = eight asterisk bracketleft
+ control keycode 0x1d = Delete
+ alt keycode 0x1d = Meta_eight
+keycode 0x1e = nine parenleft bracketright
+ alt keycode 0x1e = Meta_nine
+keycode 0x1f = zero parenright braceright
+ alt keycode 0x1f = Meta_zero
+keycode 0x20 = minus underscore backslash
+ control keycode 0x20 = Control_underscore
+ shift control keycode 0x20 = Control_underscore
+ alt keycode 0x20 = Meta_minus
+keycode 0x21 = equal plus
+ alt keycode 0x21 = Meta_equal
+keycode 0x22 = Delete Delete
+ control keycode 0x22 = BackSpace
+ alt keycode 0x22 = Meta_Delete
+keycode 0x2a = Tab Tab
+ alt keycode 0x2a = Meta_Tab
+keycode 0x2b = q
+keycode 0x2c = w
+keycode 0x2d = e
+ altgr keycode 0x2d = Hex_E
+keycode 0x2e = r
+keycode 0x2f = t
+keycode 0x30 = y
+keycode 0x31 = u
+keycode 0x32 = i
+keycode 0x33 = o
+keycode 0x34 = p
+keycode 0x35 = bracketleft braceleft
+ control keycode 0x35 = Escape
+ alt keycode 0x35 = Meta_bracketleft
+keycode 0x36 = bracketright braceright asciitilde
+ control keycode 0x36 = Control_bracketright
+ alt keycode 0x36 = Meta_bracketright
+keycode 0x37 = Return
+ alt keycode 0x37 = Meta_Control_m
+keycode 0x3f = Control
+keycode 0x41 = a
+ altgr keycode 0x41 = Hex_A
+keycode 0x42 = s
+keycode 0x43 = d
+ altgr keycode 0x43 = Hex_D
+keycode 0x44 = f
+ altgr keycode 0x44 = Hex_F
+keycode 0x45 = g
+keycode 0x46 = h
+keycode 0x47 = j
+keycode 0x48 = k
+keycode 0x49 = l
+keycode 0x4a = semicolon colon
+ alt keycode 0x4a = Meta_semicolon
+keycode 0x4b = apostrophe quotedbl
+ control keycode 0x4b = Control_g
+ alt keycode 0x4b = Meta_apostrophe
+# keycode 41 = grave asciitilde
+# control keycode 41 = nul
+# alt keycode 41 = Meta_grave
+keycode 0x52 = Shift
+keycode 0x4c = backslash bar
+ control keycode 0x4c = Control_backslash
+ alt keycode 0x4c = Meta_backslash
+keycode 0x53 = greater less
+keycode 0x54 = z
+keycode 0x55 = x
+keycode 0x56 = c
+ altgr keycode 0x56 = Hex_C
+keycode 0x57 = v
+keycode 0x58 = b
+ altgr keycode 0x58 = Hex_B
+keycode 0x59 = n
+keycode 0x5a = m
+keycode 0x5b = comma less
+ alt keycode 0x5b = Meta_comma
+keycode 0x5c = period greater
+ control keycode 0x5c = Compose
+ alt keycode 0x5c = Meta_period
+keycode 0x5d = slash question
+ control keycode 0x5d = Delete
+ alt keycode 0x5d = Meta_slash
+
+keycode 0x67 = Alt
+keycode 0x68 = space space
+ control keycode 0x68 = nul
+ alt keycode 0x68 = Meta_space
+keycode 0x40 = Caps_Lock
+keycode 0x01 = F1
+ control keycode 0x01 = F1
+ alt keycode 0x01 = Console_1
+ control alt keycode 0x01 = Console_1
+keycode 0x02 = F2
+ control keycode 0x02 = F2
+ alt keycode 0x02 = Console_2
+ control alt keycode 0x02 = Console_2
+keycode 0x03 = F3
+ control keycode 0x03 = F3
+ alt keycode 0x03 = Console_3
+ control alt keycode 0x03 = Console_3
+keycode 0x04 = F4
+ control keycode 0x04 = F4
+ alt keycode 0x04 = Console_4
+ control alt keycode 0x04 = Console_4
+keycode 0x05 = F5
+ control keycode 0x05 = F5
+ alt keycode 0x05 = Console_5
+ control alt keycode 0x05 = Console_5
+keycode 0x06 = F6
+ control keycode 0x06 = F6
+ alt keycode 0x06 = Console_6
+ control alt keycode 0x06 = Console_6
+keycode 0x07 = F7
+ control keycode 0x07 = F7
+ alt keycode 0x07 = Console_7
+ control alt keycode 0x07 = Console_7
+keycode 0x08 = F8
+ control keycode 0x08 = F8
+ alt keycode 0x08 = Console_8
+ control alt keycode 0x08 = Console_8
+keycode 0x09 = F9
+ control keycode 0x09 = F9
+ alt keycode 0x09 = Console_9
+ control alt keycode 0x09 = Console_9
+keycode 0x0a = F10
+ control keycode 0x0a = F10
+ alt keycode 0x0a = Console_10
+ control alt keycode 0x0a = Console_10
+keycode 0x0b = F11
+ control keycode 0x0b = F11
+ alt keycode 0x0b = Console_11
+ control alt keycode 0x0b = Console_11
+keycode 0x0c = F12
+ control keycode 0x0c = F12
+ alt keycode 0x0c = Console_12
+ control alt keycode 0x0c = Console_12
+keycode 0x0d = F13
+ control keycode 0x0d = F13
+ alt keycode 0x0d = Console_13
+ control alt keycode 0x0d = Console_13
+keycode 0x0e = F14
+ control keycode 0x0e = F14
+ alt keycode 0x0e = Console_14
+ control alt keycode 0x0e = Console_14
+
+keycode 0x11 = F17
+ control keycode 0x11 = F17
+ alt keycode 0x11 = Console_17
+ control alt keycode 0x11 = Console_17
+keycode 0x12 = F18
+ control keycode 0x12 = F18
+ alt keycode 0x12 = Console_18
+ control alt keycode 0x12 = Console_18
+keycode 0x13 = F19
+ control keycode 0x13 = F19
+ alt keycode 0x13 = Console_19
+ control alt keycode 0x13 = Console_19
+keycode 0x14 = F20
+ control keycode 0x14 = F20
+ alt keycode 0x14 = Console_20
+ control alt keycode 0x14 = Console_20
+
+
+keycode 0x3b = KP_7
+ alt keycode 0x3b = Ascii_7
+ altgr keycode 0x3b = Hex_7
+keycode 0x3c = KP_8
+ alt keycode 0x3c = Ascii_8
+ altgr keycode 0x3c = Hex_8
+keycode 0x3d = KP_9
+ alt keycode 0x3d = Ascii_9
+ altgr keycode 0x3d = Hex_9
+keycode 0x3e = KP_Subtract
+keycode 0x4e = KP_4
+ alt keycode 0x4e = Ascii_4
+ altgr keycode 0x4e = Hex_4
+keycode 0x4f = KP_5
+ alt keycode 0x4f = Ascii_5
+ altgr keycode 0x4f = Hex_5
+keycode 0x50 = KP_6
+ alt keycode 0x50 = Ascii_6
+ altgr keycode 0x50 = Hex_6
+keycode 0x62 = KP_1
+ alt keycode 0x62 = Ascii_1
+ altgr keycode 0x62 = Hex_1
+keycode 0x63 = KP_2
+ alt keycode 0x63 = Ascii_2
+ altgr keycode 0x63 = Hex_2
+keycode 0x64 = KP_3
+ alt keycode 0x64 = Ascii_3
+ altgr keycode 0x64 = Hex_3
+keycode 0x6b = KP_0
+ alt keycode 0x6b = Ascii_0
+ altgr keycode 0x6b = Hex_0
+keycode 0x6c = KP_Period
+# altgr control keycode 0x6c = Boot
+ control alt keycode 0x6c = Boot
+keycode 0x65 = KP_Enter
+
+keycode 0x3f = Control
+
+# keycode 100 = AltGr
+
+keycode 0x23 = Find
+keycode 0x4d = Up
+keycode 0x39 = Prior
+ shift keycode 0x39 = Scroll_Backward
+keycode 0x5f = Left
+ alt keycode 0x5f = Decr_Console
+keycode 0x61 = Right
+ alt keycode 0x61 = Incr_Console
+keycode 0x38 = Select
+keycode 0x60 = Down
+keycode 0x3a = Next
+ shift keycode 0x3a = Scroll_Forward
+keycode 0x24 = Insert
+keycode 0x25 = Remove
+# altgr control keycode 0x25 = Boot
+ control alt keycode 0x25 = Boot
+
+keycode 0x0f = Help Show_Memory Show_Registers
+ control keycode 0x0f = Show_State
+
+keycode 0x10 = Do
+
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff --git a/drivers/tc/lk201-remap.c b/drivers/tc/lk201-remap.c
new file mode 100644
index 000000000..895041bcc
--- /dev/null
+++ b/drivers/tc/lk201-remap.c
@@ -0,0 +1,150 @@
+/*
+ * Keyboard mappings for DEC LK201/401/501 keyboards
+ *
+ * 17.05.99 Michael Engel (engel@unix-ag.org)
+ *
+ * DEC keyboard generate keycodes in the range 0x56 - 0xfb
+ *
+ * This conflicts with Linux scancode conventions which define
+ * 0x00-0x7f as "normal" and 0x80-0xff as "shifted" scancodes, so we
+ * have to remap the keycodes to 0x00-0x7f with the scancodeRemap
+ * array. The generated scancode is simply the number of the key counted
+ * from the left upper to the right lower corner of the keyboard ...
+ *
+ * These scancodes are then being remapped (I hope ;-)) with the
+ * lk501*map[] arrays which define scancode -> Linux code mapping
+ *
+ * Oh man is this horrible ;-)
+ */
+
+unsigned char scancodeRemap[256] = {
+/* ----- */
+/* 0 */ 0, 0, 0, 0,
+/* ----- */
+/* 4 */ 0, 0, 0, 0,
+/* ----- */
+/* 8 */ 0, 0, 0, 0,
+/* ----- */
+/* c */ 0, 0, 0, 0,
+/* ----- */
+/* 10 */ 0, 0, 0, 0,
+/* ----- */
+/* 14 */ 0, 0, 0, 0,
+/* ----- */
+/* 18 */ 0, 0, 0, 0,
+/* ----- */
+/* 1c */ 0, 0, 0, 0,
+/* ----- */
+/* 20 */ 0, 0, 0, 0,
+/* ----- */
+/* 24 */ 0, 0, 0, 0,
+/* ----- */
+/* 28 */ 0, 0, 0, 0,
+/* ----- */
+/* 2c */ 0, 0, 0, 0,
+/* ----- */
+/* 30 */ 0, 0, 0, 0,
+/* ----- */
+/* 34 */ 0, 0, 0, 0,
+/* ----- */
+/* 38 */ 0, 0, 0, 0,
+/* ----- */
+/* 3c */ 0, 0, 0, 0,
+/* ----- */
+/* 40 */ 0, 0, 0, 0,
+/* ----- */
+/* 44 */ 0, 0, 0, 0,
+/* ----- */
+/* 48 */ 0, 0, 0, 0,
+/* ----- */
+/* 4c */ 0, 0, 0, 0,
+/* ----- */
+/* 50 */ 0, 0, 0, 0,
+/* ----- F1, F2, */
+/* 54 */ 0, 0, 0x01, 0x02,
+/* ----- F3, F4, F5, */
+/* 58 */ 0x03, 0x04, 0x05, 0,
+/* ----- */
+/* 5c */ 0, 0, 0, 0,
+/* ----- */
+/* 60 */ 0, 0, 0, 0,
+/* ----- F6, F7, F8, F9, */
+/* 64 */ 0x06, 0x07, 0x08, 0x09,
+/* ----- F10, */
+/* 68 */ 0x0a, 0, 0, 0,
+/* ----- */
+/* 6c */ 0, 0, 0, 0,
+/* ----- F11, F12, F13, */
+/* 70 */ 0, 0x0b, 0x0c, 0x0d,
+/* ----- F14 */
+/* 74 */ 0x0e, 0, 0, 0,
+/* ----- */
+/* 78 */ 0, 0, 0, 0,
+/* ----- HELP DO */
+/* 7c */ 0x0f, 0x10, 0, 0,
+/* ----- F17 F18 F19 F20 */
+/* 80 */ 0x11, 0x12, 0x13, 0x14,
+/* ----- */
+/* 84 */ 0, 0, 0, 0,
+/* ----- */
+/* 88 */ 0, 0, 0x23, 0x24,
+/* ----- REMOVE SELECT PREVIOUS NEXT */
+/* 8c */ 0x25, 0x38, 0x39, 0x3a,
+/* ----- KP 0 */
+/* 90 */ 0, 0, 0x6b, 0,
+/* ----- KP . KP ENTER KP 1 KP 2 */
+/* 94 */ 0x6c, 0x65, 0x62, 0x63,
+/* ----- KP 3 KP 4 KP 5 KP 6 */
+/* 98 */ 0x64, 0x4e, 0x4f, 0x50,
+/* ----- KP , KP 7 KP 8 KP 9 */
+/* 9c */ 0x51, 0x3b, 0x3c, 0x3d,
+/* ----- KP - KP F1 KP F2 KP F3 */
+/* a0 */ 0x3e, 0x26, 0x27, 0x28,
+/* ----- KP F4 LEFT */
+/* a4 */ 0x29, 0, 0, 0x5f,
+/* ----- RIGHT DOWN UP SHIFT Rt */
+/* a8 */ 0x61, 0x60, 0x4d, 0x5e,
+/* ----- SHIFT CONTROL */
+/* ac */ 0, 0, 0x52, 0x3f,
+/* ----- CAPS ALT */
+/* b0 */ 0x40, 0x67, 0, 0,
+/* ----- */
+/* b4 */ 0, 0, 0, 0,
+/* ----- */
+/* b8 */ 0, 0, 0, 0,
+/* ----- BKSP RET TAB ` */
+/* bc */ 0x22, 0x37, 0x2a, 0x15,
+/* ----- 1 q a z */
+/* c0 */ 0x16, 0x2b, 0x41, 0x54,
+/* ----- 2 w s */
+/* c4 */ 0, 0x17, 0x2c, 0x42,
+/* ----- x < 3 */
+/* c8 */ 0x55, 0x53, 0, 0x18,
+/* ----- e d c */
+/* cc */ 0x2d, 0x43, 0x56, 0,
+/* ----- 4 r f v */
+/* d0 */ 0x19, 0x2e, 0x44, 0x57,
+/* ----- SPACE 5 t */
+/* d4 */ 0x68, 0, 0x1a, 0x2f,
+/* ----- g b 6 */
+/* d8 */ 0x45, 0x58, 0, 0x1b,
+/* ----- y h n */
+/* dc */ 0x30, 0x46, 0x59, 0,
+/* ----- 7 u j m */
+/* e0 */ 0x1c, 0x31, 0x47, 0x5a,
+/* ----- 8 i k */
+/* e4 */ 0, 0x1d, 0x32, 0x48,
+/* ----- , 9 o */
+/* e8 */ 0x5b, 0, 0x1e, 0x33,
+/* ----- l . 0 */
+/* ec */ 0x49, 0x5c, 0, 0x1f,
+/* ----- p ; / */
+/* f0 */ 0x34, 0, 0x4a, 0x5d,
+/* ----- = ] \\ */
+/* f4 */ 0, 0x21, 0x36, 0x4c,
+/* ----- - [ \' */
+/* f8 */ 0, 0x20, 0x35, 0x4b,
+/* ----- */
+/* fc */ 0, 0, 0, 0,
+};
+
diff --git a/drivers/tc/lk201.c b/drivers/tc/lk201.c
new file mode 100644
index 000000000..1ecc40df6
--- /dev/null
+++ b/drivers/tc/lk201.c
@@ -0,0 +1,217 @@
+/*
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kbd_ll.h>
+#include <asm/wbflush.h>
+#include <asm/dec/tc.h>
+#include <asm/dec/machtype.h>
+
+#include "zs.h"
+#include "lk201.h"
+
+#define KEYB_LINE 3
+
+static void __init lk201_init(struct dec_serial *);
+static void __init lk201_info(struct dec_serial *);
+static void lk201_kbd_rx_char(unsigned char, unsigned char);
+
+struct zs_hook lk201_kbdhook = {
+ init_channel: lk201_init,
+ init_info: lk201_info,
+ rx_char: NULL,
+ poll_rx_char: NULL,
+ poll_tx_char: NULL,
+ cflags: B4800 | CS8 | CSTOPB | CLOCAL
+};
+
+/*
+ * This is used during keyboard initialisation
+ */
+static unsigned char lk201_reset_string[] = {
+ LK_CMD_LEDS_ON, LK_PARAM_LED_MASK(0xf), /* show we are resetting */
+ LK_CMD_SET_DEFAULTS,
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 1),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 2),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 3),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 4),
+ LK_CMD_MODE(LK_MODE_DOWN_UP, 5),
+ LK_CMD_MODE(LK_MODE_DOWN_UP, 6),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 7),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 8),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 9),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 10),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 11),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 12),
+ LK_CMD_MODE(LK_MODE_DOWN, 13),
+ LK_CMD_MODE(LK_MODE_RPT_DOWN, 14),
+ LK_CMD_ENB_RPT,
+ LK_CMD_DIS_KEYCLK,
+ LK_CMD_RESUME,
+ LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4),
+ LK_CMD_LEDS_OFF, LK_PARAM_LED_MASK(0xf)
+};
+
+static void __init lk201_reset(struct dec_serial *info)
+{
+ int i;
+
+ for (i = 0; i < sizeof(lk201_reset_string); i++)
+ if(info->hook->poll_tx_char(info, lk201_reset_string[i]))
+ printk(__FUNCTION__" transmit timeout\n");
+}
+
+void kbd_leds(unsigned char leds)
+{
+ return;
+}
+
+int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+ return -EINVAL;
+}
+
+int kbd_getkeycode(unsigned int scancode)
+{
+ return -EINVAL;
+}
+
+int kbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
+{
+ *keycode = scancode;
+ return 1;
+}
+
+char kbd_unexpected_up(unsigned char keycode)
+{
+ return 0x80;
+}
+
+static void lk201_kbd_rx_char(unsigned char ch, unsigned char stat)
+{
+ static int shift_state = 0;
+ static int prev_scancode;
+ unsigned char c = scancodeRemap[ch];
+
+ if (!stat || stat == 4) {
+ switch (ch) {
+ case LK_KEY_ACK:
+ break;
+ case LK_KEY_LOCK:
+ shift_state ^= LK_LOCK;
+ handle_scancode(c, shift_state && LK_LOCK ? 1 : 0);
+ break;
+ case LK_KEY_SHIFT:
+ shift_state ^= LK_SHIFT;
+ handle_scancode(c, shift_state && LK_SHIFT ? 1 : 0);
+ break;
+ case LK_KEY_CTRL:
+ shift_state ^= LK_CTRL;
+ handle_scancode(c, shift_state && LK_CTRL ? 1 : 0);
+ break;
+ case LK_KEY_COMP:
+ shift_state ^= LK_COMP;
+ handle_scancode(c, shift_state && LK_COMP ? 1 : 0);
+ break;
+ case LK_KEY_RELEASE:
+ if (shift_state & LK_SHIFT)
+ handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0);
+ if (shift_state & LK_CTRL)
+ handle_scancode(scancodeRemap[LK_KEY_CTRL], 0);
+ if (shift_state & LK_COMP)
+ handle_scancode(scancodeRemap[LK_KEY_COMP], 0);
+ if (shift_state & LK_LOCK)
+ handle_scancode(scancodeRemap[LK_KEY_LOCK], 0);
+ shift_state = 0;
+ break;
+ case LK_KEY_REPEAT:
+ handle_scancode(prev_scancode, 1);
+ break;
+ default:
+ prev_scancode = c;
+ handle_scancode(c, 1);
+ break;
+ }
+ } else
+ printk("Error reading LKx01 keyboard: 0x%02x\n", stat);
+}
+
+static void __init lk201_info(struct dec_serial *info)
+{
+}
+
+static void __init lk201_init(struct dec_serial *info)
+{
+ unsigned int ch, id;
+
+ printk("DECstation LK keyboard driver v0.04... ");
+
+ lk201_reset(info);
+ udelay(10000);
+
+ /*
+ * Detect wether there is an LK201 or an LK401
+ * The LK401 has ALT keys...
+ */
+ info->hook->poll_tx_char(info, LK_CMD_REQ_ID);
+ while((ch = info->hook->poll_rx_char(info)) > 0)
+ id = ch;
+
+ switch (id) {
+ case 1:
+ printk("LK201 detected\n");
+ break;
+ case 2:
+ printk("LK401 detected\n");
+ break;
+ default:
+ printk("unkown keyboard, ID %d\n", id);
+ }
+
+ /*
+ * now we're ready
+ */
+ info->hook->rx_char = lk201_kbd_rx_char;
+}
+
+void __init kbd_init_hw(void)
+{
+ extern int register_zs_hook(unsigned int, struct zs_hook *);
+ extern int unregister_zs_hook(unsigned int);
+
+ if (TURBOCHANNEL) {
+ if (mips_machtype != MACH_DS5000_XX) {
+ /*
+ * This is not a MAXINE, so:
+ *
+ * kbd_init_hw() is being called before
+ * rs_init() so just register the kbd hook
+ * and let zs_init do the rest :-)
+ */
+ if (mips_machtype == MACH_DS5000_200)
+ printk("LK201 Support for DS5000/200 not yet ready ...\n");
+ else
+ if(!register_zs_hook(KEYB_LINE, &lk201_kbdhook))
+ unregister_zs_hook(KEYB_LINE);
+ }
+ } else {
+ /*
+ * TODO: modify dz.c to allow similar hooks
+ * for LK201 handling on DS2100, Ds3100, and DS5000/200
+ */
+ printk("LK201 Support for DS3100 not yet ready ...\n");
+ }
+}
+
+
+
+
diff --git a/drivers/tc/lk201.h b/drivers/tc/lk201.h
new file mode 100644
index 000000000..5a7450e83
--- /dev/null
+++ b/drivers/tc/lk201.h
@@ -0,0 +1,53 @@
+/*
+ * Commands to the keyboard processor
+ */
+
+#define LK_PARAM 0x80 /* start/end parameter list */
+
+#define LK_CMD_RESUME 0x8b
+#define LK_CMD_INHIBIT 0xb9
+#define LK_CMD_LEDS_ON 0x13 /* 1 param: led bitmask */
+#define LK_CMD_LEDS_OFF 0x11 /* 1 param: led bitmask */
+#define LK_CMD_DIS_KEYCLK 0x99
+#define LK_CMD_ENB_KEYCLK 0x1b /* 1 param: volume */
+#define LK_CMD_DIS_CTLCLK 0xb9
+#define LK_CMD_ENB_CTLCLK 0xbb
+#define LK_CMD_SOUND_CLK 0x9f
+#define LK_CMD_DIS_BELL 0xa1
+#define LK_CMD_ENB_BELL 0x23 /* 1 param: volume */
+#define LK_CMD_BELL 0xa7
+#define LK_CMD_TMP_NORPT 0xc1
+#define LK_CMD_ENB_RPT 0xe3
+#define LK_CMD_DIS_RPT 0xe1
+#define LK_CMD_RPT_TO_DOWN 0xd9
+#define LK_CMD_REQ_ID 0xab
+#define LK_CMD_POWER_UP 0xfd
+#define LK_CMD_TEST_MODE 0xcb
+#define LK_CMD_SET_DEFAULTS 0xd3
+
+/* there are 4 leds, represent them in the low 4 bits of a byte */
+#define LK_PARAM_LED_MASK(ledbmap) (LK_PARAM|(ledbmap))
+
+/* max volume is 0, lowest is 0x7 */
+#define LK_PARAM_VOLUME(v) (LK_PARAM|((v)&0x7))
+
+/* mode set command(s) details */
+#define LK_MODE_DOWN 0x0
+#define LK_MODE_RPT_DOWN 0x2
+#define LK_MODE_DOWN_UP 0x6
+#define LK_CMD_MODE(m,div) (LK_PARAM|(div<<3)|m)
+
+#define LK_SHIFT 1<<0
+#define LK_CTRL 1<<1
+#define LK_LOCK 1<<2
+#define LK_COMP 1<<3
+
+#define LK_KEY_SHIFT 174
+#define LK_KEY_CTRL 175
+#define LK_KEY_LOCK 176
+#define LK_KEY_COMP 177
+#define LK_KEY_RELEASE 179
+#define LK_KEY_REPEAT 180
+#define LK_KEY_ACK 186
+
+extern unsigned char scancodeRemap[256]; \ No newline at end of file
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index a8707ffb9..8ab788199 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -1,20 +1,17 @@
/*
* decserial.c: Serial port driver for IOASIC DECsatations.
*
- * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
* Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
*
* DECstation changes
- * Copyright (C) 1998 Harald Koerfgen (Harald.Koerfgen@home.ivm.de)
+ * Copyright (C) 1998-2000 Harald Koerfgen (Harald.Koerfgen@home.ivm.de)
* Copyright (C) 2000 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
*
* For the rest of the code the original Copyright applies:
* Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*
- * Keyboard and mouse are not supported right now. If you want to change this,
- * you might want to have a look at drivers/sbus/char/sunserial.c to see
- * how this might be done. HK
*/
#include <linux/config.h>
@@ -33,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h>
#endif
@@ -45,10 +43,17 @@
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/wbflush.h>
+#include <asm/bootinfo.h>
+#ifdef CONFIG_DECSTATION
#include <asm/dec/interrupts.h>
#include <asm/dec/machtype.h>
#include <asm/dec/tc.h>
#include <asm/dec/ioasic_addrs.h>
+#endif
+#ifdef CONFIG_BAGET_MIPS
+#include <asm/baget/baget.h>
+unsigned long system_base;
+#endif
#ifdef CONFIG_KGDB
#include <asm/kgdb.h>
#endif
@@ -66,11 +71,60 @@
*/
#define NUM_SERIAL 2 /* Max number of ZS chips supported */
#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
+#define CHANNEL_A_NR (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
+ /* Number of channel A in the chip */
+#define ZS_CHAN_IO_SIZE 8
+#define ZS_CLOCK 7372800 /* Z8530 RTxC input clock rate */
#define RECOVERY_DELAY udelay(2)
-struct dec_zschannel zs_channels[NUM_CHANNELS];
+struct zs_parms {
+ unsigned long scc0;
+ unsigned long scc1;
+ int channel_a_offset;
+ int channel_b_offset;
+ int irq;
+ int clock;
+};
+
+static struct zs_parms *zs_parms;
+
+#ifdef CONFIG_DECSTATION
+static struct zs_parms ds_parms = {
+ scc0 : SCC0,
+ scc1 : SCC1,
+ channel_a_offset : 1,
+ channel_b_offset : 9,
+ irq : SERIAL,
+ clock : ZS_CLOCK
+};
+#endif
+#ifdef CONFIG_BAGET_MIPS
+static struct zs_parms baget_parms = {
+ scc0 : UNI_SCC0,
+ scc1 : UNI_SCC1,
+ channel_a_offset : 9,
+ channel_b_offset : 1,
+ irq : BAGET_SCC_IRQ,
+ clock : 14745000
+};
+#endif
+#ifdef CONFIG_DECSTATION
+#define DS_BUS_PRESENT (IOASIC)
+#else
+#define DS_BUS_PRESENT 0
+#endif
+
+#ifdef CONFIG_BAGET_MIPS
+#define BAGET_BUS_PRESENT (mips_machtype == MACH_BAGET202)
+#else
+#define BAGET_BUS_PRESENT 0
+#endif
+
+#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT)
+
+struct dec_zschannel zs_channels[NUM_CHANNELS];
struct dec_serial zs_soft[NUM_CHANNELS];
int zs_channels_found;
struct dec_serial *zs_chain; /* list of all channels */
@@ -85,20 +139,6 @@ static struct console sercons;
static unsigned long break_pressed; /* break, really ... */
#endif
-#ifdef CONFIG_KGDB
-struct dec_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
- 9, 0x80, /* reset A side (CHRA) */
- 13, 0, /* set baud rate divisor */
- 12, 1,
- 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */
- 11, 0x50, /* clocks = br gen (RCBR | TCBR) */
- 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
- 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/
- 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
-#endif
-
static unsigned char zs_init_regs[16] __initdata = {
0, /* write 0 */
0, /* write 1 */
@@ -115,8 +155,6 @@ static unsigned char zs_init_regs[16] __initdata = {
0 /* write 15 */
};
-#define ZS_CLOCK 7372800 /* Z8530 RTxC input clock rate */
-
DECLARE_TASK_QUEUE(tq_zs_serial);
struct tty_driver serial_driver, callout_driver;
@@ -138,6 +176,12 @@ static int serial_refcount;
#undef SERIAL_DEBUG_THROTTLE
#undef SERIAL_PARANOIA_CHECK
+#undef ZS_DEBUG_REGS
+
+#ifdef SERIAL_DEBUG_THROTTLE
+#define _tty_name(tty,buf) tty_name(tty,buf)
+#endif
+
#define RS_STROBE_TIME 10
#define RS_ISR_PASS_LIMIT 256
@@ -265,16 +309,18 @@ static inline void load_zsregs(struct dec_zschannel *channel,
}
/* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct dec_serial *ss, int set)
+static inline void zs_rtsdtr(struct dec_serial *info, int set)
{
- if (ss->zs_channel != ss->zs_chan_a) {
- if (set)
- ss->zs_chan_a->curregs[5] |= (RTS | DTR);
- else
- ss->zs_chan_a->curregs[5] &= ~(RTS | DTR);
- write_zsreg(ss->zs_chan_a, 5, ss->zs_chan_a->curregs[5]);
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if(set) {
+ info->zs_channel->curregs[5] |= (RTS | DTR);
+ } else {
+ info->zs_channel->curregs[5] &= ~(RTS | DTR);
}
- return;
+ write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+ restore_flags(flags);
}
/* Utility routines for the Zilog */
@@ -290,7 +336,7 @@ static inline int get_zsbaud(struct dec_serial *ss)
*/
brg = (read_zsreg(channel, 13) << 8);
brg |= read_zsreg(channel, 12);
- return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+ return BRG_TO_BPS(brg, (zs_parms->clock/(ss->clk_divisor)));
}
/* On receive, this clears errors and the receiver interrupts */
@@ -336,16 +382,7 @@ static _INLINE_ void receive_chars(struct dec_serial *info,
stat = read_zsreg(info->zs_channel, R1);
ch = read_zsdata(info->zs_channel);
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel) {
- if (ch == 0x03 || ch == '$')
- breakpoint();
- if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
- write_zsreg(info->zs_channel, R0, ERR_RES);
- return;
- }
-#endif
- if (!tty)
+ if (!tty && !info->hook && !info->hook->rx_char)
continue;
if (tty_break) {
@@ -388,6 +425,11 @@ static _INLINE_ void receive_chars(struct dec_serial *info,
}
#endif
+ if (info->hook && info->hook->rx_char) {
+ (*info->hook->rx_char)(ch, flag);
+ return;
+ }
+
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
static int flip_buf_ovf;
++flip_buf_ovf;
@@ -523,7 +565,30 @@ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
status_handle(info);
}
}
+
+ /* Why do we need this ? */
+ write_zsreg(info->zs_channel, 0, RES_H_IUS);
+}
+
+#ifdef ZS_DEBUG_REGS
+void zs_dump (void) {
+ int i, j;
+ for (i = 0; i < zs_channels_found; i++) {
+ struct dec_zschannel *ch = &zs_channels[i];
+ if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
+ for (j = 0; j < 15; j++) {
+ printk("W%d = 0x%x\t",
+ j, (int)ch->curregs[j]);
+ }
+ for (j = 0; j < 15; j++) {
+ printk("R%d = 0x%x\t",
+ j, (int)read_zsreg(ch,j));
+ }
+ printk("\n\n");
+ }
+ }
}
+#endif
/*
* -------------------------------------------------------------------
@@ -609,7 +674,7 @@ static void do_softint(void *private_)
}
}
-static int startup(struct dec_serial * info)
+int zs_startup(struct dec_serial * info)
{
unsigned long flags;
@@ -714,8 +779,7 @@ static void shutdown(struct dec_serial * info)
info->zs_channel->curregs[5] &= ~TxENAB;
write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
if (!info->tty || C_HUPCL(info->tty)) {
- info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
- write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+ zs_rtsdtr(info, 0);
}
if (info->tty)
@@ -731,29 +795,33 @@ static void shutdown(struct dec_serial * info)
*/
static void change_speed(struct dec_serial *info)
{
- unsigned short port;
unsigned cflag;
int i;
- int brg;
+ int brg, bits;
unsigned long flags;
+ if (!info->hook) {
if (!info->tty || !info->tty->termios)
return;
cflag = info->tty->termios->c_cflag;
- if (!(port = info->port))
+ if (!info->port)
return;
+ } else {
+ cflag = info->hook->cflags;
+ }
i = cflag & CBAUD;
-
save_flags(flags); cli();
info->zs_baud = baud_table[i];
info->clk_divisor = 16;
-
- switch (info->zs_baud) {
- default:
+ if (info->zs_baud) {
info->zs_channel->curregs[4] = X16CLK;
- brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+ brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
info->zs_channel->curregs[12] = (brg & 255);
info->zs_channel->curregs[13] = ((brg >> 8) & 255);
+ zs_rtsdtr(info, 1);
+ } else {
+ zs_rtsdtr(info, 0);
+ return;
}
/* byte size and parity */
@@ -761,24 +829,31 @@ static void change_speed(struct dec_serial *info)
info->zs_channel->curregs[5] &= ~TxNBITS_MASK;
switch (cflag & CSIZE) {
case CS5:
+ bits = 7;
info->zs_channel->curregs[3] |= Rx5;
info->zs_channel->curregs[5] |= Tx5;
break;
case CS6:
+ bits = 8;
info->zs_channel->curregs[3] |= Rx6;
info->zs_channel->curregs[5] |= Tx6;
break;
case CS7:
+ bits = 9;
info->zs_channel->curregs[3] |= Rx7;
info->zs_channel->curregs[5] |= Tx7;
break;
case CS8:
default: /* defaults to 8 bits */
+ bits = 10;
info->zs_channel->curregs[3] |= Rx8;
info->zs_channel->curregs[5] |= Tx8;
break;
}
+ info->timeout = ((info->xmit_fifo_size*HZ*bits) / info->zs_baud);
+ info->timeout += HZ/50; /* Add .02 seconds of slop */
+
info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
if (cflag & CSTOPB) {
info->zs_channel->curregs[4] |= SB2;
@@ -945,17 +1020,7 @@ static void rs_throttle(struct tty_struct * tty)
}
if (C_CRTSCTS(tty)) {
- /*
- * Here we want to turn off the RTS line. On Macintoshes,
- * we only get the DTR line, which goes to both DTR and
- * RTS on the modem. RTS doesn't go out to the serial
- * port socket. So you should make sure your modem is
- * set to ignore DTR if you're using CRTSCTS.
- */
- save_flags(flags); cli();
- info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
- write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
- restore_flags(flags);
+ zs_rtsdtr(info, 0);
}
}
@@ -987,11 +1052,7 @@ static void rs_unthrottle(struct tty_struct * tty)
}
if (C_CRTSCTS(tty)) {
- /* Assert RTS and DTR lines */
- save_flags(flags); cli();
- info->zs_chan_a->curregs[5] |= DTR | RTS;
- write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
- restore_flags(flags);
+ zs_rtsdtr(info, 1);
}
}
@@ -1062,7 +1123,7 @@ static int set_serial_info(struct dec_serial * info,
info->closing_wait = new_serial.closing_wait;
check_and_exit:
- retval = startup(info);
+ retval = zs_startup(info);
return retval;
}
@@ -1093,7 +1154,7 @@ static int get_modem_info(struct dec_serial *info, unsigned int *value)
unsigned int result;
cli();
- control = info->zs_chan_a->curregs[5];
+ control = info->zs_channel->curregs[5];
status = read_zsreg(info->zs_channel, 0);
sti();
result = ((control & RTS) ? TIOCM_RTS: 0)
@@ -1118,19 +1179,20 @@ static int set_modem_info(struct dec_serial *info, unsigned int cmd,
cli();
switch (cmd) {
case TIOCMBIS:
- info->zs_chan_a->curregs[5] |= bits;
+ info->zs_channel->curregs[5] |= bits;
break;
case TIOCMBIC:
- info->zs_chan_a->curregs[5] &= ~bits;
+ info->zs_channel->curregs[5] &= ~bits;
break;
case TIOCMSET:
- info->zs_chan_a->curregs[5] = (info->zs_chan_a->curregs[5] & ~(DTR | RTS)) | bits;
+ info->zs_channel->curregs[5] =
+ (info->zs_channel->curregs[5] & ~(DTR | RTS)) | bits;
break;
default:
sti();
return -EINVAL;
}
- write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+ write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
sti();
return 0;
}
@@ -1163,10 +1225,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
int error;
struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel)
+ if (info->hook)
return -ENODEV;
-#endif
+
if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
return -ENODEV;
@@ -1537,10 +1598,9 @@ int rs_open(struct tty_struct *tty, struct file * filp)
return -ENODEV;
info = zs_soft + line;
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel)
+ if (info->hook)
return -ENODEV;
-#endif
+
if (serial_paranoia_check(info, tty->device, "rs_open"))
return -ENODEV;
#ifdef SERIAL_DEBUG_OPEN
@@ -1570,7 +1630,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
/*
* Start up serial port
*/
- retval = startup(info);
+ retval = zs_startup(info);
if (retval)
return retval;
@@ -1612,7 +1672,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
static void __init show_serial_version(void)
{
- printk("DECstation Z8530 serial driver version 0.03\n");
+ printk("DECstation Z8530 serial driver version 0.05\n");
}
/* Initialize Z8530s zs_channels
@@ -1626,7 +1686,7 @@ static void __init probe_sccs(void)
/*
* did we get here by accident?
*/
- if(!IOASIC) {
+ if(!BUS_PRESENT) {
printk("Not on JUNKIO machine, skipping probe_sccs\n");
return;
}
@@ -1637,19 +1697,36 @@ static void __init probe_sccs(void)
* system_base for this case :-(. HK
*/
switch(mips_machtype) {
+#ifdef CONFIG_DECSTATION
case MACH_DS5000_2X0:
system_base = 0xbf800000;
n_chips = 2;
+ zs_parms = &ds_parms;
break;
case MACH_DS5000_1XX:
system_base = 0xbc000000;
n_chips = 2;
+ zs_parms = &ds_parms;
break;
case MACH_DS5000_XX:
system_base = 0xbc000000;
n_chips = 1;
+ zs_parms = &ds_parms;
+ break;
+#endif
+#ifdef CONFIG_BAGET_MIPS
+ case MACH_BAGET202:
+ system_base = UNI_IO_BASE;
+ n_chips = 2;
+ zs_parms = &baget_parms;
+ zs_init_regs[2] = 0x8;
break;
+#endif
+ default:
+ panic("zs: unsupported bus");
}
+ if (!zs_parms)
+ panic("zs: uninitialized parms");
pp = &zs_chain;
@@ -1660,16 +1737,44 @@ static void __init probe_sccs(void)
/*
* The sccs reside on the high byte of the 16 bit IOBUS
*/
- zs_channels[n_channels].control = (volatile unsigned char *)
- system_base + (0 == chip ? SCC0 : SCC1) + (0 == channel ? 1 : 9);
- zs_channels[n_channels].data = zs_channels[n_channels].control + 4;
+ zs_channels[n_channels].control =
+ (volatile unsigned char *)system_base +
+ (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
+ (0 == channel ? zs_parms->channel_a_offset :
+ zs_parms->channel_b_offset);
+ zs_channels[n_channels].data =
+ zs_channels[n_channels].control + 4;
+
+#ifndef CONFIG_SERIAL_CONSOLE
+ /*
+ * We're called early and memory managment isn't up, yet.
+ * Thus check_region would fail.
+ */
+ if (check_region((unsigned long)
+ zs_channels[n_channels].control,
+ ZS_CHAN_IO_SIZE) < 0) {
+ panic("SCC I/O region is not free");
+ }
+ request_region((unsigned long)
+ zs_channels[n_channels].control,
+ ZS_CHAN_IO_SIZE, "SCC");
+#endif
zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
- zs_soft[n_channels].irq = SERIAL;
-
- if (0 == channel)
- zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels+1];
+ zs_soft[n_channels].irq = zs_parms->irq;
+
+ /*
+ * Identification of channel A. Location of channel A
+ * inside chip depends on mapping of internal address
+ * the chip decodes channels by.
+ * CHANNEL_A_NR returns either 0 (in case of
+ * DECstations) or 1 (in case of Baget).
+ */
+ if (CHANNEL_A_NR == channel)
+ zs_soft[n_channels].zs_chan_a =
+ &zs_channels[n_channels+1-2*CHANNEL_A_NR];
else
- zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels];
+ zs_soft[n_channels].zs_chan_a =
+ &zs_channels[n_channels];
*pp = &zs_soft[n_channels];
pp = &zs_soft[n_channels].zs_next;
@@ -1705,7 +1810,7 @@ int __init zs_init(void)
unsigned long flags;
struct dec_serial *info;
- if(!IOASIC)
+ if(!BUS_PRESENT)
return -ENODEV;
/* Setup base handler, and timer table. */
@@ -1780,36 +1885,25 @@ int __init zs_init(void)
save_flags(flags); cli();
for (channel = 0; channel < zs_channels_found; ++channel) {
-#ifdef CONFIG_KGDB
- if (zs_soft[channel].kgdb_channel) {
- continue;
- }
-#endif
+ if (zs_soft[channel].hook &&
+ zs_soft[channel].hook->init_channel)
+ (*zs_soft[channel].hook->init_channel)(&zs_soft[channel]);
+
zs_soft[channel].clk_divisor = 16;
zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
- if (request_irq(SERIAL, rs_interrupt, SA_SHIRQ,
+ if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ,
"SCC", &zs_soft[channel]))
printk(KERN_ERR "decserial: can't get irq %d\n",
- SERIAL);
-
- /* If console serial line, then enable interrupts. */
-/* if (zs_soft[channel].is_cons) {
- write_zsreg(zs_soft[channel].zs_channel, R1,
- (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
- write_zsreg(zs_soft[channel].zs_channel, R9,
- (VIS | MIE));
- }
-*/
+ zs_parms->irq);
}
for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
{
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel) {
+ if (info->hook && info->hook->init_info) {
+ (*info->hook->init_info)(info);
continue;
}
-#endif
info->magic = SERIAL_MAGIC;
info->port = (int) info->zs_channel->control;
info->line = i;
@@ -1858,38 +1952,115 @@ void unregister_serial(int line)
}
/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
+ * polling I/O routines
*/
-#ifdef CONFIG_SERIAL_CONSOLE
+static int
+zs_poll_tx_char(struct dec_serial *info, unsigned char ch)
+{
+ struct dec_zschannel *chan = info->zs_channel;
+ int ret;
+ if(chan) {
+ int loops = 10000;
+// int nine = read_zsreg(chan, R9);
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- */
+ RECOVERY_DELAY;
+// write_zsreg(chan, R9, nine & ~MIE);
+ wbflush();
+ RECOVERY_DELAY;
+
+ while (!(*(chan->control) & Tx_BUF_EMP) && --loops)
+ RECOVERY_DELAY;
-/* This is for console output */
-static void
-zs_console_putchar(struct dec_serial *info, char ch)
+ if (loops) {
+ ret = 0;
+ *(chan->data) = ch;
+ wbflush();
+ RECOVERY_DELAY;
+ } else
+ ret = -EAGAIN;
+
+// write_zsreg(chan, R9, nine);
+ wbflush();
+ RECOVERY_DELAY;
+
+ return ret;
+ }
+
+ return -ENODEV;
+}
+
+static int
+zs_poll_rx_char(struct dec_serial *info)
{
- int loops = 10000;
- unsigned long flags;
+ struct dec_zschannel *chan = info->zs_channel;
+ int ret;
- if(!info->zs_channel)
- return;
+ if(chan) {
+ int loops = 10000;
- save_flags(flags); cli();
+ while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+ loops--;
- while (!(*(info->zs_channel->control) & Tx_BUF_EMP) && --loops)
- RECOVERY_DELAY;
- *(info->zs_channel->data) = ch;
- wbflush(); RECOVERY_DELAY;
+ if (loops)
+ ret = read_zsdata(chan);
+ else
+ ret = -EAGAIN;
- restore_flags(flags);
+ return ret;
+ } else
+ return -ENODEV;
+}
+
+unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook)
+{
+ struct dec_serial *info = &zs_soft[channel];
+
+ if (info->hook) {
+ printk(__FUNCTION__": line %d has already a hook registered\n", channel);
+
+ return 0;
+ } else {
+ if (zs_chain == 0)
+ probe_sccs();
+
+ if (!(info->flags & ZILOG_INITIALIZED))
+ zs_startup(info);
+
+ hook->poll_rx_char = zs_poll_rx_char;
+ hook->poll_tx_char = zs_poll_tx_char;
+ info->hook = hook;
+
+ return 1;
+ }
}
+unsigned int unregister_zs_hook(unsigned int channel)
+{
+ struct dec_serial *info = &zs_soft[channel];
+
+ if (info->hook) {
+ info->hook = NULL;
+ return 1;
+ } else {
+ printk(__FUNCTION__": trying to unregister hook on line %d,"
+ " but none is registered\n", channel);
+ return 0;
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
static void serial_console_write(struct console *co, const char *s,
unsigned count)
{
@@ -1898,28 +2069,11 @@ static void serial_console_write(struct console *co, const char *s,
info = zs_soft + co->index;
-#if 0
- /*
- * disable master interrupt if necessary
- */
- nine = info->zs_channel->curregs[9];
- if(nine & MIE)
- write_zsreg(info->zs_channel, R9, nine & ~MIE);
-#endif
- /*
- * do it
- */
for (i = 0; i < count; i++, s++) {
if(*s == '\n')
- zs_console_putchar(info, '\r');
- zs_console_putchar(info, *s);
+ zs_poll_tx_char(info, '\r');
+ zs_poll_tx_char(info, *s);
}
- /*
- * restore master interrupt enable
- */
-#if 0
- write_zsreg(info->zs_channel, R9, nine);
-#endif
}
/*
@@ -1927,7 +2081,11 @@ static void serial_console_write(struct console *co, const char *s,
*/
static int serial_console_wait_key(struct console *co)
{
- return 0;
+ struct dec_serial *info;
+
+ info = zs_soft + co->index;
+
+ return zs_poll_rx_char(info);
}
static kdev_t serial_console_device(struct console *c)
@@ -1951,7 +2109,7 @@ static int __init serial_console_setup(struct console *co, char *options)
char *s;
unsigned long flags;
- if(!IOASIC)
+ if(!BUS_PRESENT)
return -ENODEV;
info = zs_soft + co->index;
@@ -2080,6 +2238,18 @@ void __init zs_serial_console_init(void)
#endif /* ifdef CONFIG_SERIAL_CONSOLE */
#ifdef CONFIG_KGDB
+struct dec_zschannel *zs_kgdbchan;
+static unsigned char scc_inittab[] = {
+ 9, 0x80, /* reset A side (CHRA) */
+ 13, 0, /* set baud rate divisor */
+ 12, 1,
+ 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */
+ 11, 0x50, /* clocks = br gen (RCBR | TCBR) */
+ 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
+ 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/
+ 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/
+};
+
/* These are for receiving and sending characters under the kgdb
* source level kernel debugger.
*/
@@ -2114,6 +2284,24 @@ void kgdb_interruptible(int yes)
write_zsreg(chan, 1, one);
write_zsreg(chan, 9, nine);
}
+
+static void kgdbhook_init_channel(struct dec_serial* info)
+{
+}
+
+static void kgdbhook_init_info(struct dec_serial* info)
+{
+}
+
+static void kgdbhook_rx_char(struct dec_serial* info,
+ unsigned char ch, unsigned char stat)
+{
+ if (ch == 0x03 || ch == '$')
+ breakpoint();
+ if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+}
+
/* This sets up the serial port we're using, and turns on
* interrupts for that channel, so kgdb is usable once we're done.
*/
@@ -2122,7 +2310,7 @@ static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps)
int brg;
int i, x;
volatile char *sccc = ms->control;
- brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+ brg = BPS_TO_BRG(bps, zs_parms->clock/16);
printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
for (i = 20000; i != 0; --i) {
x = *sccc; eieio();
@@ -2137,6 +2325,13 @@ static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps)
* for /dev/ttyb which is determined in setup_arch() from the
* boot command line flags.
*/
+struct zs_hook zs_kgdbhook = {
+ init_channel : kgdbhook_init_channel,
+ init_info : kgdbhook_init_info,
+ cflags : B38400|CS8|CLOCAL,
+ rx_char : kgdbhook_rx_char,
+}
+
void __init zs_kgdb_hook(int tty_num)
{
/* Find out how many Z8530 SCCs we have */
@@ -2147,8 +2342,7 @@ void __init zs_kgdb_hook(int tty_num)
zs_soft[tty_num].change_needed = 0;
zs_soft[tty_num].clk_divisor = 16;
zs_soft[tty_num].zs_baud = 38400;
- zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */
- zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+ zs_soft[tty_num].hook = &zs_kgdbhook; /* This runs kgdb */
/* Turn on transmitter/receiver at 8-bits/char */
kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
printk("KGDB: on channel %d initialized\n", tty_num);
@@ -2156,3 +2350,4 @@ void __init zs_kgdb_hook(int tty_num)
}
#endif /* ifdef CONFIG_KGDB */
+
diff --git a/drivers/tc/zs.h b/drivers/tc/zs.h
index e10e1c3d2..6f210ac4e 100644
--- a/drivers/tc/zs.h
+++ b/drivers/tc/zs.h
@@ -89,6 +89,18 @@ struct dec_zschannel {
unsigned char curregs[NUM_ZSREGS];
};
+struct dec_serial;
+
+struct zs_hook {
+ void (*init_channel)(struct dec_serial* info);
+ void (*init_info)(struct dec_serial* info);
+ void (*rx_char)(unsigned char ch, unsigned char stat);
+ int (*poll_rx_char)(struct dec_serial* info);
+ int (*poll_tx_char)(struct dec_serial* info,
+ unsigned char ch);
+ unsigned cflags;
+};
+
struct dec_serial {
struct dec_serial *zs_next; /* For IRQ servicing chain */
struct dec_zschannel *zs_channel; /* Channel registers */
@@ -97,7 +109,7 @@ struct dec_serial {
char soft_carrier; /* Use soft carrier on this channel */
char break_abort; /* Is serial console in, so process brk/abrt */
- char kgdb_channel; /* Kgdb is running on this channel */
+ struct zs_hook *hook; /* Hook on this channel */
char is_cons; /* Is this our console. */
unsigned char tx_active; /* character is being xmitted */
unsigned char tx_stopped; /* output is suspended */
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index 2a48d4d7c..866df0ea5 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -155,6 +155,11 @@ if [ "$CONFIG_FB" = "y" ]; then
if [ "$CONFIG_HD64461" = "y" ]; then
tristate ' HD64461 Frame Buffer support' CONFIG_FB_HIT
fi
+ if [ "$CONFIG_DECSTATION" = "y" ]; then
+ if [ "$CONFIG_TC" = "y" ]; then
+ bool ' PMAG-BA TURBOchannel framebuffer support' CONFIG_FB_PMAGBA
+ fi
+ fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
fi
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 331343d15..96de87f86 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o
obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o
obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o
obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
+obj-$(CONFIG_FB_PMAGBA) += pmag-ba-fb.o
ifeq ($(CONFIG_FB_MATROX),y)
SUB_DIRS += matrox
@@ -183,3 +184,4 @@ promcon_tbl.c: prom.uni ../char/conmakehash
-e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c
promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h
+
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 7b3d49822..ba6d70289 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -113,6 +113,8 @@ extern int tdfxfb_init(void);
extern int tdfxfb_setup(char*);
extern int sisfb_init(void);
extern int sisfb_setup(char*);
+extern int pmagbafb_init(void);
+extern int pmagbafb_setup(char *);
static struct {
const char *name;
@@ -267,6 +269,9 @@ static struct {
/* Not a real frame buffer device... */
{ "resolver", NULL, resolver_video_setup },
#endif
+#ifdef CONFIG_FB_PMAGBA
+ { "pmagbafb", pmagbafb_init, pmagbafb_setup },
+#endif
#ifdef CONFIG_FB_VIRTUAL
/*
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
new file mode 100644
index 000000000..7987082fc
--- /dev/null
+++ b/drivers/video/pmag-ba-fb.c
@@ -0,0 +1,440 @@
+/*
+ * linux/drivers/video/pmagbafb.c
+ *
+ * PMAG-BA TurboChannel framebuffer card support ... derived from:
+ * "HP300 Topcat framebuffer support (derived from macfb of all things)
+ * Phil Blundell <philb@gnu.org> 1998", the original code can be
+ * found in the file hpfb.c in the same directory.
+ *
+ * Based on digital document:
+ * "PMAG-BA TURBOchannel Color Frame Buffer
+ * Functional Specification", Revision 1.2, August 27, 1990
+ *
+ * DECstation related code Copyright (C) 1999, 2000 by
+ * Michael Engel <engel@unix-ag.org>, Karsten Merker <merker@guug.de>
+ * and Harald Koerfgen <harald@unix-ag.org>.
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <asm/bootinfo.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
+/*
+ * Bt459 RAM DAC register base offset (rel. to TC slot base address)
+ */
+#define BT459_OFFSET 0x00200000
+
+/*
+ * Begin of DECstation 5000/xx onboard framebuffer memory, resolution
+ * is 1024x864x8
+ */
+#define PMAG_BA_ONBOARD_FBMEM_OFFSET 0x00000000
+
+struct ramdac_regs {
+ unsigned char addr_low;
+ unsigned char pad0[3];
+ unsigned char addr_hi;
+ unsigned char pad1[3];
+ unsigned char data;
+ unsigned char pad2[3];
+ unsigned char cmap;
+};
+
+struct my_fb_info {
+ struct fb_info info;
+ struct ramdac_regs *bt459_regs;
+ unsigned long pmagba_fb_start;
+ unsigned long pmagba_fb_size;
+ unsigned long pmagba_fb_line_length;
+};
+
+static struct display disp;
+/*
+ * Max 3 TURBOchannel slots -> max 3 PMAG-BA :)
+ */
+static struct my_fb_info pmagba_fb_info[3];
+
+static struct fb_var_screeninfo pmagbafb_defined = {
+ 0, 0, 0, 0, /* W,H, W, H (virtual) load xres,xres_virtual */
+ 0, 0, /* virtual -> visible no offset */
+ 0, /* depth -> load bits_per_pixel */
+ 0, /* greyscale ? */
+ {0, 0, 0}, /* R */
+ {0, 0, 0}, /* G */
+ {0, 0, 0}, /* B */
+ {0, 0, 0}, /* transparency */
+ 0, /* standard pixel format */
+ FB_ACTIVATE_NOW,
+ 274, 195, /* 14" monitor */
+ FB_ACCEL_NONE,
+ 0L, 0L, 0L, 0L, 0L,
+ 0L, 0L, 0, /* No sync info */
+ FB_VMODE_NONINTERLACED,
+ {0, 0, 0, 0, 0, 0}
+};
+
+struct pmagbafb_par {
+};
+
+static int currcon = 0;
+struct pmagbafb_par current_par;
+
+static void pmagbafb_encode_var(struct fb_var_screeninfo *var,
+ struct pmagbafb_par *par)
+{
+ int i = 0;
+ var->xres = 1024;
+ var->yres = 864;
+ var->xres_virtual = 1024;
+ var->yres_virtual = 864;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->bits_per_pixel = 8;
+ var->grayscale = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->nonstd = 0;
+ var->activate = 1;
+ var->height = -1;
+ var->width = -1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->pixclock = 0;
+ var->sync = 0;
+ var->left_margin = 0;
+ var->right_margin = 0;
+ var->upper_margin = 0;
+ var->lower_margin = 0;
+ var->hsync_len = 0;
+ var->vsync_len = 0;
+ for (i = 0; i < arraysize(var->reserved); i++)
+ var->reserved[i] = 0;
+}
+
+static void pmagbafb_get_par(struct pmagbafb_par *par)
+{
+ *par = current_par;
+}
+
+static int pmagba_fb_update_var(int con, struct fb_info *info)
+{
+ return 0;
+}
+
+static int pmagba_do_fb_set_var(struct fb_var_screeninfo *var,
+ int isactive)
+{
+ struct pmagbafb_par par;
+
+ pmagbafb_get_par(&par);
+ pmagbafb_encode_var(var, &par);
+ return 0;
+}
+
+/*
+ * Turn hardware cursor off
+ */
+void pmagbafb_erase_cursor(struct my_fb_info *info)
+{
+ info->bt459_regs->addr_low = 0;
+ info->bt459_regs->addr_hi = 3;
+ info->bt459_regs->data = 0;
+}
+
+/*
+ * Write to a Bt459 color map register
+ */
+void bt459_write_colormap(struct my_fb_info *info,
+ int reg, __u8 red, __u8 green, __u8 blue)
+{
+ info->bt459_regs->addr_low = (__u8) reg;
+ info->bt459_regs->addr_hi = 0;
+ info->bt459_regs->cmap = red;
+ info->bt459_regs->cmap = green;
+ info->bt459_regs->cmap = blue;
+}
+
+/*
+ * Get the palette
+ */
+
+static int pmagbafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ unsigned int i;
+ unsigned int length;
+
+ if (((cmap->start) + (cmap->len)) >= 256) {
+ length = 256 - (cmap->start);
+ } else {
+ length = cmap->len;
+ }
+ for (i = 0; i < length; i++) {
+ /*
+ * TODO
+ */
+ }
+ return 0;
+}
+
+/*
+ * Set the palette.
+ */
+static int pmagbafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ unsigned int i;
+ __u8 cmap_red, cmap_green, cmap_blue;
+ unsigned int length;
+
+ if (((cmap->start) + (cmap->len)) >= 256)
+ length = 256 - (cmap->start);
+ else
+ length = cmap->len;
+
+ for (i = 0; i < length; i++) {
+ cmap_red = ((cmap->red[i]) >> 8); /* The cmap fields are 16 bits */
+ cmap_green = ((cmap->green[i]) >> 8); /* wide, but the harware colormap */
+ cmap_blue = ((cmap->blue[i]) >> 8); /* registers are only 8 bits wide */
+
+ bt459_write_colormap((struct my_fb_info *) info,
+ cmap->start + i, cmap_red, cmap_green,
+ cmap_blue);
+ }
+ return 0;
+}
+
+static int pmagbafb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct pmagbafb_par par;
+ if (con == -1) {
+ pmagbafb_get_par(&par);
+ pmagbafb_encode_var(var, &par);
+ } else
+ *var = fb_display[con].var;
+ return 0;
+}
+
+
+static int pmagbafb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ int err;
+
+ if ((err = pmagba_do_fb_set_var(var, 1)))
+ return err;
+ return 0;
+}
+
+static void pmagbafb_encode_fix(struct fb_fix_screeninfo *fix,
+ struct pmagbafb_par *par,
+ struct my_fb_info *info)
+{
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, "PMAG-BA");
+
+ /*
+ * X works, but screen wraps ...
+ */
+ fix->smem_start = info->pmagba_fb_start;
+ fix->smem_len = info->pmagba_fb_size;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+ fix->ywrapstep = 0;
+ fix->line_length = info->pmagba_fb_line_length;
+}
+
+static int pmagbafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct pmagbafb_par par;
+
+ pmagbafb_get_par(&par);
+ pmagbafb_encode_fix(fix, &par, (struct my_fb_info *) info);
+
+ return 0;
+}
+
+
+static int pmagbafb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+static int pmagbafb_switch(int con, struct fb_info *info)
+{
+ pmagba_do_fb_set_var(&fb_display[con].var, 1);
+ currcon = con;
+
+ return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void pmagbafb_blank(int blank, struct fb_info *info)
+{
+ /* Not supported */
+}
+
+static int pmagbafb_open(struct fb_info *info, int user)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+ MOD_INC_USE_COUNT;
+ return (0);
+}
+
+static void pmagbafb_set_disp(int con, struct my_fb_info *info)
+{
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &disp; /* used during initialization */
+
+ pmagbafb_get_fix(&fix, con, (struct fb_info *) info);
+
+ display->screen_base = (char *) fix.smem_start;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ display->can_soft_blank = 0;
+ display->inverse = 0;
+
+ display->dispsw = &fbcon_cfb8;
+}
+
+static int pmagbafb_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return (0);
+}
+
+static struct fb_ops pmagbafb_ops = {
+ owner: THIS_MODULE,
+ fb_open: pmagbafb_open,
+ fb_release: pmagbafb_release,
+ fb_get_fix: pmagbafb_get_fix,
+ fb_get_var: pmagbafb_get_var,
+ fb_set_var: pmagbafb_set_var,
+ fb_get_cmap: pmagbafb_get_cmap,
+ fb_set_cmap: pmagbafb_set_cmap,
+ fb_ioctl: pmagbafb_ioctl,
+ fb_mmap: 0,
+ fb_rasterimg: 0
+};
+
+int __init pmagbafb_init_one(int slot)
+{
+ unsigned long base_addr = get_tc_base_addr(slot);
+ struct my_fb_info *ip =
+ (struct my_fb_info *) &pmagba_fb_info[slot];
+
+ printk("PMAG-BA framebuffer in slot %d\n", slot);
+
+ /*
+ * Framebuffer display memory base address and friends
+ */
+ ip->bt459_regs = (struct ramdac_regs *) (base_addr + BT459_OFFSET);
+ ip->pmagba_fb_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET;
+ ip->pmagba_fb_size = 1024 * 864;
+ ip->pmagba_fb_line_length = 1024;
+
+ /*
+ * Configure the Bt459 RAM DAC
+ */
+ pmagbafb_erase_cursor(ip);
+
+ /*
+ * Fill in the available video resolution
+ */
+
+ pmagbafb_defined.xres = 1024;
+ pmagbafb_defined.yres = 864;
+ pmagbafb_defined.xres_virtual = 1024;
+ pmagbafb_defined.yres_virtual = 864;
+ pmagbafb_defined.bits_per_pixel = 8;
+
+ /*
+ * Let there be consoles..
+ */
+ strcpy(ip->info.modename, "PMAG-BA");
+ ip->info.changevar = NULL;
+ ip->info.node = -1;
+ ip->info.fbops = &pmagbafb_ops;
+ ip->info.disp = &disp;
+ ip->info.switch_con = &pmagbafb_switch;
+ ip->info.updatevar = &pmagba_fb_update_var;
+ ip->info.blank = &pmagbafb_blank;
+ ip->info.flags = FBINFO_FLAG_DEFAULT;
+
+ pmagba_do_fb_set_var(&pmagbafb_defined, 1);
+ pmagbafb_get_var(&disp.var, -1, (struct fb_info *) ip);
+ pmagbafb_set_disp(-1, ip);
+
+ if (register_framebuffer((struct fb_info *) ip) < 0)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Initialise the framebuffer
+ */
+
+int __init pmagbafb_init(void)
+{
+ int sid;
+ int found = 0;
+
+ if (TURBOCHANNEL) {
+ while ((sid = search_tc_card("PMAG-BA")) >= 0) {
+ found = 1;
+ claim_tc_card(sid);
+ pmagbafb_init_one(sid);
+ }
+ return found ? 0 : -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+}
+
+int __init pmagbafb_setup(char *options)
+{
+ return 0;
+}