diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/tc/.cvsignore | 3 | ||||
-rw-r--r-- | drivers/tc/Makefile | 4 | ||||
-rw-r--r-- | drivers/tc/lk201-map.map | 356 | ||||
-rw-r--r-- | drivers/tc/lk201-remap.c | 150 | ||||
-rw-r--r-- | drivers/tc/lk201.c | 217 | ||||
-rw-r--r-- | drivers/tc/lk201.h | 53 | ||||
-rw-r--r-- | drivers/tc/zs.c | 507 | ||||
-rw-r--r-- | drivers/tc/zs.h | 14 | ||||
-rw-r--r-- | drivers/video/Config.in | 5 | ||||
-rw-r--r-- | drivers/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/fbmem.c | 5 | ||||
-rw-r--r-- | drivers/video/pmag-ba-fb.c | 440 |
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; +} |