diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/input/keyboard |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r-- | drivers/input/keyboard/Kconfig | 185 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 19 | ||||
-rw-r--r-- | drivers/input/keyboard/amikbd.c | 241 | ||||
-rw-r--r-- | drivers/input/keyboard/atkbd.c | 1148 | ||||
-rw-r--r-- | drivers/input/keyboard/corgikbd.c | 361 | ||||
-rw-r--r-- | drivers/input/keyboard/hil_kbd.c | 375 | ||||
-rw-r--r-- | drivers/input/keyboard/hilkbd.c | 343 | ||||
-rw-r--r-- | drivers/input/keyboard/hpps2atkbd.h | 110 | ||||
-rw-r--r-- | drivers/input/keyboard/lkkbd.c | 752 | ||||
-rw-r--r-- | drivers/input/keyboard/locomokbd.c | 309 | ||||
-rw-r--r-- | drivers/input/keyboard/maple_keyb.c | 190 | ||||
-rw-r--r-- | drivers/input/keyboard/newtonkbd.c | 184 | ||||
-rw-r--r-- | drivers/input/keyboard/sunkbd.c | 353 | ||||
-rw-r--r-- | drivers/input/keyboard/xtkbd.c | 188 |
14 files changed, 4758 insertions, 0 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig new file mode 100644 index 000000000000..e55dee390775 --- /dev/null +++ b/drivers/input/keyboard/Kconfig | |||
@@ -0,0 +1,185 @@ | |||
1 | # | ||
2 | # Input core configuration | ||
3 | # | ||
4 | menuconfig INPUT_KEYBOARD | ||
5 | bool "Keyboards" if EMBEDDED || !X86 | ||
6 | default y | ||
7 | help | ||
8 | Say Y here, and a list of supported keyboards will be displayed. | ||
9 | This option doesn't affect the kernel. | ||
10 | |||
11 | If unsure, say Y. | ||
12 | |||
13 | if INPUT_KEYBOARD | ||
14 | |||
15 | config KEYBOARD_ATKBD | ||
16 | tristate "AT keyboard" if !PC | ||
17 | default y | ||
18 | select SERIO | ||
19 | select SERIO_LIBPS2 | ||
20 | select SERIO_I8042 if PC | ||
21 | select SERIO_GSCPS2 if GSC | ||
22 | help | ||
23 | Say Y here if you want to use a standard AT or PS/2 keyboard. Usually | ||
24 | you'll need this, unless you have a different type keyboard (USB, ADB | ||
25 | or other). This also works for AT and PS/2 keyboards connected over a | ||
26 | PS/2 to serial converter. | ||
27 | |||
28 | If unsure, say Y. | ||
29 | |||
30 | To compile this driver as a module, choose M here: the | ||
31 | module will be called atkbd. | ||
32 | |||
33 | config KEYBOARD_ATKBD_HP_KEYCODES | ||
34 | bool "Use HP keyboard scancodes" | ||
35 | depends on PARISC && KEYBOARD_ATKBD | ||
36 | default y | ||
37 | help | ||
38 | Say Y here if you have a PA-RISC machine and want to use an AT or | ||
39 | PS/2 keyboard, and your keyboard uses keycodes that are specific to | ||
40 | PA-RISC keyboards. | ||
41 | |||
42 | Say N if you use a standard keyboard. | ||
43 | |||
44 | config KEYBOARD_ATKBD_RDI_KEYCODES | ||
45 | bool "Use PrecisionBook keyboard scancodes" | ||
46 | depends on KEYBOARD_ATKBD_HP_KEYCODES | ||
47 | default n | ||
48 | help | ||
49 | If you have an RDI PrecisionBook, say Y here if you want to use its | ||
50 | built-in keyboard (as opposed to an external keyboard). | ||
51 | |||
52 | The PrecisionBook has five keys that conflict with those used by most | ||
53 | AT and PS/2 keyboards. These are as follows: | ||
54 | |||
55 | PrecisionBook Standard AT or PS/2 | ||
56 | |||
57 | F1 F12 | ||
58 | Left Ctrl Left Alt | ||
59 | Caps Lock Left Ctrl | ||
60 | Right Ctrl Caps Lock | ||
61 | Left 102nd key (the key to the right of Left Shift) | ||
62 | |||
63 | If you say N here, and use the PrecisionBook keyboard, then each key | ||
64 | in the left-hand column will be interpreted as the corresponding key | ||
65 | in the right-hand column. | ||
66 | |||
67 | If you say Y here, and use an external keyboard, then each key in the | ||
68 | right-hand column will be interpreted as the key shown in the | ||
69 | left-hand column. | ||
70 | |||
71 | config KEYBOARD_SUNKBD | ||
72 | tristate "Sun Type 4 and Type 5 keyboard" | ||
73 | select SERIO | ||
74 | help | ||
75 | Say Y here if you want to use a Sun Type 4 or Type 5 keyboard, | ||
76 | connected either to the Sun keyboard connector or to an serial | ||
77 | (RS-232) port via a simple adapter. | ||
78 | |||
79 | To compile this driver as a module, choose M here: the | ||
80 | module will be called sunkbd. | ||
81 | |||
82 | config KEYBOARD_LKKBD | ||
83 | tristate "DECstation/VAXstation LK201/LK401 keyboard" | ||
84 | select SERIO | ||
85 | help | ||
86 | Say Y here if you want to use a LK201 or LK401 style serial | ||
87 | keyboard. This keyboard is also useable on PCs if you attach | ||
88 | it with the inputattach program. The connector pinout is | ||
89 | described within lkkbd.c. | ||
90 | |||
91 | To compile this driver as a module, choose M here: the | ||
92 | module will be called lkkbd. | ||
93 | |||
94 | config KEYBOARD_LOCOMO | ||
95 | tristate "LoCoMo Keyboard Support" | ||
96 | depends on SHARP_LOCOMO | ||
97 | help | ||
98 | Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA | ||
99 | |||
100 | To compile this driver as a module, choose M here: the | ||
101 | module will be called locomokbd. | ||
102 | |||
103 | config KEYBOARD_XTKBD | ||
104 | tristate "XT keyboard" | ||
105 | select SERIO | ||
106 | help | ||
107 | Say Y here if you want to use the old IBM PC/XT keyboard (or | ||
108 | compatible) on your system. This is only possible with a | ||
109 | parallel port keyboard adapter, you cannot connect it to the | ||
110 | keyboard port on a PC that runs Linux. | ||
111 | |||
112 | To compile this driver as a module, choose M here: the | ||
113 | module will be called xtkbd. | ||
114 | |||
115 | config KEYBOARD_NEWTON | ||
116 | tristate "Newton keyboard" | ||
117 | select SERIO | ||
118 | help | ||
119 | Say Y here if you have a Newton keyboard on a serial port. | ||
120 | |||
121 | To compile this driver as a module, choose M here: the | ||
122 | module will be called newtonkbd. | ||
123 | |||
124 | config KEYBOARD_CORGI | ||
125 | tristate "Corgi keyboard" | ||
126 | depends on PXA_SHARPSL | ||
127 | default y | ||
128 | help | ||
129 | Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx | ||
130 | series of PDAs. | ||
131 | |||
132 | To compile this driver as a module, choose M here: the | ||
133 | module will be called corgikbd. | ||
134 | |||
135 | config KEYBOARD_MAPLE | ||
136 | tristate "Maple bus keyboard" | ||
137 | depends on SH_DREAMCAST && MAPLE | ||
138 | help | ||
139 | Say Y here if you have a DreamCast console running Linux and have | ||
140 | a keyboard attached to its Maple bus. | ||
141 | |||
142 | To compile this driver as a module, choose M here: the | ||
143 | module will be called maple_keyb. | ||
144 | |||
145 | config KEYBOARD_AMIGA | ||
146 | tristate "Amiga keyboard" | ||
147 | depends on AMIGA | ||
148 | help | ||
149 | Say Y here if you are running Linux on any AMIGA and have a keyboard | ||
150 | attached. | ||
151 | |||
152 | To compile this driver as a module, choose M here: the | ||
153 | module will be called amikbd. | ||
154 | |||
155 | config KEYBOARD_HIL_OLD | ||
156 | tristate "HP HIL keyboard support (simple driver)" | ||
157 | depends on GSC | ||
158 | default y | ||
159 | help | ||
160 | The "Human Interface Loop" is a older, 8-channel USB-like | ||
161 | controller used in several Hewlett Packard models. This driver | ||
162 | was adapted from the one written for m68k/hp300, and implements | ||
163 | support for a keyboard attached to the HIL port, but not for | ||
164 | any other types of HIL input devices like mice or tablets. | ||
165 | However, it has been thoroughly tested and is stable. | ||
166 | |||
167 | If you want full HIL support including support for multiple | ||
168 | keyboards, mices and tablets, you have to enable the | ||
169 | "HP System Device Controller i8042 Support" in the input/serio | ||
170 | submenu. | ||
171 | |||
172 | config KEYBOARD_HIL | ||
173 | tristate "HP HIL keyboard support" | ||
174 | depends on GSC | ||
175 | default y | ||
176 | select HP_SDC | ||
177 | select HIL_MLC | ||
178 | select SERIO | ||
179 | help | ||
180 | The "Human Interface Loop" is a older, 8-channel USB-like | ||
181 | controller used in several Hewlett Packard models. | ||
182 | This driver implements support for HIL-keyboards attached | ||
183 | to your machine, so normally you should say Y here. | ||
184 | |||
185 | endif | ||
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile new file mode 100644 index 000000000000..b02eeceea3c3 --- /dev/null +++ b/drivers/input/keyboard/Makefile | |||
@@ -0,0 +1,19 @@ | |||
1 | # | ||
2 | # Makefile for the input core drivers. | ||
3 | # | ||
4 | |||
5 | # Each configuration option enables a list of files. | ||
6 | |||
7 | obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o | ||
8 | obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o | ||
9 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o | ||
10 | obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o | ||
11 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o | ||
12 | obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o | ||
13 | obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o | ||
14 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o | ||
15 | obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o | ||
16 | obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o | ||
17 | obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o | ||
18 | obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o | ||
19 | |||
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c new file mode 100644 index 000000000000..4e8e8ea214ab --- /dev/null +++ b/drivers/input/keyboard/amikbd.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * $Id: amikbd.c,v 1.13 2002/02/01 16:02:24 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Hamish Macdonald | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Amiga keyboard driver for Linux/m68k | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/input.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/interrupt.h> | ||
39 | |||
40 | #include <asm/amigaints.h> | ||
41 | #include <asm/amigahw.h> | ||
42 | #include <asm/irq.h> | ||
43 | |||
44 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
45 | MODULE_DESCRIPTION("Amiga keyboard driver"); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | |||
48 | static unsigned char amikbd_keycode[0x78] = { | ||
49 | [0] = KEY_GRAVE, | ||
50 | [1] = KEY_1, | ||
51 | [2] = KEY_2, | ||
52 | [3] = KEY_3, | ||
53 | [4] = KEY_4, | ||
54 | [5] = KEY_5, | ||
55 | [6] = KEY_6, | ||
56 | [7] = KEY_7, | ||
57 | [8] = KEY_8, | ||
58 | [9] = KEY_9, | ||
59 | [10] = KEY_0, | ||
60 | [11] = KEY_MINUS, | ||
61 | [12] = KEY_EQUAL, | ||
62 | [13] = KEY_BACKSLASH, | ||
63 | [15] = KEY_KP0, | ||
64 | [16] = KEY_Q, | ||
65 | [17] = KEY_W, | ||
66 | [18] = KEY_E, | ||
67 | [19] = KEY_R, | ||
68 | [20] = KEY_T, | ||
69 | [21] = KEY_Y, | ||
70 | [22] = KEY_U, | ||
71 | [23] = KEY_I, | ||
72 | [24] = KEY_O, | ||
73 | [25] = KEY_P, | ||
74 | [26] = KEY_LEFTBRACE, | ||
75 | [27] = KEY_RIGHTBRACE, | ||
76 | [29] = KEY_KP1, | ||
77 | [30] = KEY_KP2, | ||
78 | [31] = KEY_KP3, | ||
79 | [32] = KEY_A, | ||
80 | [33] = KEY_S, | ||
81 | [34] = KEY_D, | ||
82 | [35] = KEY_F, | ||
83 | [36] = KEY_G, | ||
84 | [37] = KEY_H, | ||
85 | [38] = KEY_J, | ||
86 | [39] = KEY_K, | ||
87 | [40] = KEY_L, | ||
88 | [41] = KEY_SEMICOLON, | ||
89 | [42] = KEY_APOSTROPHE, | ||
90 | [43] = KEY_BACKSLASH, | ||
91 | [45] = KEY_KP4, | ||
92 | [46] = KEY_KP5, | ||
93 | [47] = KEY_KP6, | ||
94 | [48] = KEY_102ND, | ||
95 | [49] = KEY_Z, | ||
96 | [50] = KEY_X, | ||
97 | [51] = KEY_C, | ||
98 | [52] = KEY_V, | ||
99 | [53] = KEY_B, | ||
100 | [54] = KEY_N, | ||
101 | [55] = KEY_M, | ||
102 | [56] = KEY_COMMA, | ||
103 | [57] = KEY_DOT, | ||
104 | [58] = KEY_SLASH, | ||
105 | [60] = KEY_KPDOT, | ||
106 | [61] = KEY_KP7, | ||
107 | [62] = KEY_KP8, | ||
108 | [63] = KEY_KP9, | ||
109 | [64] = KEY_SPACE, | ||
110 | [65] = KEY_BACKSPACE, | ||
111 | [66] = KEY_TAB, | ||
112 | [67] = KEY_KPENTER, | ||
113 | [68] = KEY_ENTER, | ||
114 | [69] = KEY_ESC, | ||
115 | [70] = KEY_DELETE, | ||
116 | [74] = KEY_KPMINUS, | ||
117 | [76] = KEY_UP, | ||
118 | [77] = KEY_DOWN, | ||
119 | [78] = KEY_RIGHT, | ||
120 | [79] = KEY_LEFT, | ||
121 | [80] = KEY_F1, | ||
122 | [81] = KEY_F2, | ||
123 | [82] = KEY_F3, | ||
124 | [83] = KEY_F4, | ||
125 | [84] = KEY_F5, | ||
126 | [85] = KEY_F6, | ||
127 | [86] = KEY_F7, | ||
128 | [87] = KEY_F8, | ||
129 | [88] = KEY_F9, | ||
130 | [89] = KEY_F10, | ||
131 | [90] = KEY_KPLEFTPAREN, | ||
132 | [91] = KEY_KPRIGHTPAREN, | ||
133 | [92] = KEY_KPSLASH, | ||
134 | [93] = KEY_KPASTERISK, | ||
135 | [94] = KEY_KPPLUS, | ||
136 | [95] = KEY_HELP, | ||
137 | [96] = KEY_LEFTSHIFT, | ||
138 | [97] = KEY_RIGHTSHIFT, | ||
139 | [98] = KEY_CAPSLOCK, | ||
140 | [99] = KEY_LEFTCTRL, | ||
141 | [100] = KEY_LEFTALT, | ||
142 | [101] = KEY_RIGHTALT, | ||
143 | [102] = KEY_LEFTMETA, | ||
144 | [103] = KEY_RIGHTMETA | ||
145 | }; | ||
146 | |||
147 | static const char *amikbd_messages[8] = { | ||
148 | [0] = KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n", | ||
149 | [1] = KERN_WARNING "amikbd: keyboard lost sync\n", | ||
150 | [2] = KERN_WARNING "amikbd: keyboard buffer overflow\n", | ||
151 | [3] = KERN_WARNING "amikbd: keyboard controller failure\n", | ||
152 | [4] = KERN_ERR "amikbd: keyboard selftest failure\n", | ||
153 | [5] = KERN_INFO "amikbd: initiate power-up key stream\n", | ||
154 | [6] = KERN_INFO "amikbd: terminate power-up key stream\n", | ||
155 | [7] = KERN_WARNING "amikbd: keyboard interrupt\n" | ||
156 | }; | ||
157 | |||
158 | static struct input_dev amikbd_dev; | ||
159 | |||
160 | static char *amikbd_name = "Amiga keyboard"; | ||
161 | static char *amikbd_phys = "amikbd/input0"; | ||
162 | |||
163 | static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) | ||
164 | { | ||
165 | unsigned char scancode, down; | ||
166 | |||
167 | scancode = ~ciaa.sdr; /* get and invert scancode (keyboard is active low) */ | ||
168 | ciaa.cra |= 0x40; /* switch SP pin to output for handshake */ | ||
169 | udelay(85); /* wait until 85 us have expired */ | ||
170 | ciaa.cra &= ~0x40; /* switch CIA serial port to input mode */ | ||
171 | |||
172 | down = !(scancode & 1); /* lowest bit is release bit */ | ||
173 | scancode >>= 1; | ||
174 | |||
175 | if (scancode < 0x78) { /* scancodes < 0x78 are keys */ | ||
176 | |||
177 | scancode = amikbd_keycode[scancode]; | ||
178 | |||
179 | input_regs(&amikbd_dev, fp); | ||
180 | |||
181 | if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */ | ||
182 | input_report_key(&amikbd_dev, scancode, 1); | ||
183 | input_report_key(&amikbd_dev, scancode, 0); | ||
184 | input_sync(&amikbd_dev); | ||
185 | } else { | ||
186 | input_report_key(&amikbd_dev, scancode, down); | ||
187 | input_sync(&amikbd_dev); | ||
188 | } | ||
189 | } else /* scancodes >= 0x78 are error codes */ | ||
190 | printk(amikbd_messages[scancode - 0x78]); | ||
191 | |||
192 | return IRQ_HANDLED; | ||
193 | } | ||
194 | |||
195 | static int __init amikbd_init(void) | ||
196 | { | ||
197 | int i; | ||
198 | |||
199 | if (!AMIGAHW_PRESENT(AMI_KEYBOARD)) | ||
200 | return -EIO; | ||
201 | |||
202 | if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb")) | ||
203 | return -EBUSY; | ||
204 | |||
205 | init_input_dev(&amikbd_dev); | ||
206 | |||
207 | amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
208 | amikbd_dev.keycode = amikbd_keycode; | ||
209 | amikbd_dev.keycodesize = sizeof(unsigned char); | ||
210 | amikbd_dev.keycodemax = ARRAY_SIZE(amikbd_keycode); | ||
211 | |||
212 | for (i = 0; i < 0x78; i++) | ||
213 | if (amikbd_keycode[i]) | ||
214 | set_bit(amikbd_keycode[i], amikbd_dev.keybit); | ||
215 | |||
216 | ciaa.cra &= ~0x41; /* serial data in, turn off TA */ | ||
217 | request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", amikbd_interrupt); | ||
218 | |||
219 | amikbd_dev.name = amikbd_name; | ||
220 | amikbd_dev.phys = amikbd_phys; | ||
221 | amikbd_dev.id.bustype = BUS_AMIGA; | ||
222 | amikbd_dev.id.vendor = 0x0001; | ||
223 | amikbd_dev.id.product = 0x0001; | ||
224 | amikbd_dev.id.version = 0x0100; | ||
225 | |||
226 | input_register_device(&amikbd_dev); | ||
227 | |||
228 | printk(KERN_INFO "input: %s\n", amikbd_name); | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static void __exit amikbd_exit(void) | ||
234 | { | ||
235 | input_unregister_device(&amikbd_dev); | ||
236 | free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt); | ||
237 | release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100); | ||
238 | } | ||
239 | |||
240 | module_init(amikbd_init); | ||
241 | module_exit(amikbd_exit); | ||
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c new file mode 100644 index 000000000000..f7304f0ce542 --- /dev/null +++ b/drivers/input/keyboard/atkbd.c | |||
@@ -0,0 +1,1148 @@ | |||
1 | /* | ||
2 | * AT and PS/2 keyboard driver | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * This driver can handle standard AT keyboards and PS/2 keyboards in | ||
15 | * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb | ||
16 | * input-only controllers and AT keyboards connected over a one way RS232 | ||
17 | * converter. | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/input.h> | ||
27 | #include <linux/serio.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <linux/libps2.h> | ||
30 | |||
31 | #define DRIVER_DESC "AT and PS/2 keyboard driver" | ||
32 | |||
33 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | ||
34 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | static int atkbd_set = 2; | ||
38 | module_param_named(set, atkbd_set, int, 0); | ||
39 | MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)"); | ||
40 | |||
41 | #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) | ||
42 | static int atkbd_reset; | ||
43 | #else | ||
44 | static int atkbd_reset = 1; | ||
45 | #endif | ||
46 | module_param_named(reset, atkbd_reset, bool, 0); | ||
47 | MODULE_PARM_DESC(reset, "Reset keyboard during initialization"); | ||
48 | |||
49 | static int atkbd_softrepeat; | ||
50 | module_param_named(softrepeat, atkbd_softrepeat, bool, 0); | ||
51 | MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); | ||
52 | |||
53 | static int atkbd_softraw = 1; | ||
54 | module_param_named(softraw, atkbd_softraw, bool, 0); | ||
55 | MODULE_PARM_DESC(softraw, "Use software generated rawmode"); | ||
56 | |||
57 | static int atkbd_scroll = 1; | ||
58 | module_param_named(scroll, atkbd_scroll, bool, 0); | ||
59 | MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); | ||
60 | |||
61 | static int atkbd_extra; | ||
62 | module_param_named(extra, atkbd_extra, bool, 0); | ||
63 | MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards"); | ||
64 | |||
65 | __obsolete_setup("atkbd_set="); | ||
66 | __obsolete_setup("atkbd_reset"); | ||
67 | __obsolete_setup("atkbd_softrepeat="); | ||
68 | |||
69 | /* | ||
70 | * Scancode to keycode tables. These are just the default setting, and | ||
71 | * are loadable via an userland utility. | ||
72 | */ | ||
73 | |||
74 | static unsigned char atkbd_set2_keycode[512] = { | ||
75 | |||
76 | #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES | ||
77 | |||
78 | /* XXX: need a more general approach */ | ||
79 | |||
80 | #include "hpps2atkbd.h" /* include the keyboard scancodes */ | ||
81 | |||
82 | #else | ||
83 | 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117, | ||
84 | 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0, | ||
85 | 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183, | ||
86 | 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185, | ||
87 | 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, | ||
88 | 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85, | ||
89 | 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0, | ||
90 | 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, | ||
91 | |||
92 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
93 | 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125, | ||
94 | 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127, | ||
95 | 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142, | ||
96 | 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0, | ||
97 | 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0, | ||
98 | 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112, | ||
99 | 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0, | ||
100 | |||
101 | 0, 0, 0, 65, 99, | ||
102 | #endif | ||
103 | }; | ||
104 | |||
105 | static unsigned char atkbd_set3_keycode[512] = { | ||
106 | |||
107 | 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, | ||
108 | 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, | ||
109 | 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, | ||
110 | 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66, | ||
111 | 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68, | ||
112 | 113,114, 40, 43, 26, 13, 87, 99, 97, 54, 28, 27, 43, 43, 88, 70, | ||
113 | 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104, | ||
114 | 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55,183, | ||
115 | |||
116 | 184,185,186,187, 74, 94, 92, 93, 0, 0, 0,125,126,127,112, 0, | ||
117 | 0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168, | ||
118 | 148,149,147,140 | ||
119 | }; | ||
120 | |||
121 | static unsigned char atkbd_unxlate_table[128] = { | ||
122 | 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, | ||
123 | 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, | ||
124 | 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, | ||
125 | 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, | ||
126 | 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, | ||
127 | 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, | ||
128 | 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, | ||
129 | 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 | ||
130 | }; | ||
131 | |||
132 | #define ATKBD_CMD_SETLEDS 0x10ed | ||
133 | #define ATKBD_CMD_GSCANSET 0x11f0 | ||
134 | #define ATKBD_CMD_SSCANSET 0x10f0 | ||
135 | #define ATKBD_CMD_GETID 0x02f2 | ||
136 | #define ATKBD_CMD_SETREP 0x10f3 | ||
137 | #define ATKBD_CMD_ENABLE 0x00f4 | ||
138 | #define ATKBD_CMD_RESET_DIS 0x00f5 | ||
139 | #define ATKBD_CMD_SETALL_MBR 0x00fa | ||
140 | #define ATKBD_CMD_RESET_BAT 0x02ff | ||
141 | #define ATKBD_CMD_RESEND 0x00fe | ||
142 | #define ATKBD_CMD_EX_ENABLE 0x10ea | ||
143 | #define ATKBD_CMD_EX_SETLEDS 0x20eb | ||
144 | #define ATKBD_CMD_OK_GETID 0x02e8 | ||
145 | |||
146 | #define ATKBD_RET_ACK 0xfa | ||
147 | #define ATKBD_RET_NAK 0xfe | ||
148 | #define ATKBD_RET_BAT 0xaa | ||
149 | #define ATKBD_RET_EMUL0 0xe0 | ||
150 | #define ATKBD_RET_EMUL1 0xe1 | ||
151 | #define ATKBD_RET_RELEASE 0xf0 | ||
152 | #define ATKBD_RET_HANGUEL 0xf1 | ||
153 | #define ATKBD_RET_HANJA 0xf2 | ||
154 | #define ATKBD_RET_ERR 0xff | ||
155 | |||
156 | #define ATKBD_KEY_UNKNOWN 0 | ||
157 | #define ATKBD_KEY_NULL 255 | ||
158 | |||
159 | #define ATKBD_SCR_1 254 | ||
160 | #define ATKBD_SCR_2 253 | ||
161 | #define ATKBD_SCR_4 252 | ||
162 | #define ATKBD_SCR_8 251 | ||
163 | #define ATKBD_SCR_CLICK 250 | ||
164 | #define ATKBD_SCR_LEFT 249 | ||
165 | #define ATKBD_SCR_RIGHT 248 | ||
166 | |||
167 | #define ATKBD_SPECIAL 248 | ||
168 | |||
169 | static struct { | ||
170 | unsigned char keycode; | ||
171 | unsigned char set2; | ||
172 | } atkbd_scroll_keys[] = { | ||
173 | { ATKBD_SCR_1, 0xc5 }, | ||
174 | { ATKBD_SCR_2, 0xa9 }, | ||
175 | { ATKBD_SCR_4, 0xb6 }, | ||
176 | { ATKBD_SCR_8, 0xa7 }, | ||
177 | { ATKBD_SCR_CLICK, 0xe0 }, | ||
178 | { ATKBD_SCR_LEFT, 0xcb }, | ||
179 | { ATKBD_SCR_RIGHT, 0xd2 }, | ||
180 | }; | ||
181 | |||
182 | /* | ||
183 | * The atkbd control structure | ||
184 | */ | ||
185 | |||
186 | struct atkbd { | ||
187 | |||
188 | struct ps2dev ps2dev; | ||
189 | |||
190 | /* Written only during init */ | ||
191 | char name[64]; | ||
192 | char phys[32]; | ||
193 | struct input_dev dev; | ||
194 | |||
195 | unsigned short id; | ||
196 | unsigned char keycode[512]; | ||
197 | unsigned char set; | ||
198 | unsigned char translated; | ||
199 | unsigned char extra; | ||
200 | unsigned char write; | ||
201 | unsigned char softrepeat; | ||
202 | unsigned char softraw; | ||
203 | unsigned char scroll; | ||
204 | unsigned char enabled; | ||
205 | |||
206 | /* Accessed only from interrupt */ | ||
207 | unsigned char emul; | ||
208 | unsigned char resend; | ||
209 | unsigned char release; | ||
210 | unsigned char bat_xl; | ||
211 | unsigned int last; | ||
212 | unsigned long time; | ||
213 | }; | ||
214 | |||
215 | static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, | ||
216 | ssize_t (*handler)(struct atkbd *, char *)); | ||
217 | static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, | ||
218 | ssize_t (*handler)(struct atkbd *, const char *, size_t)); | ||
219 | #define ATKBD_DEFINE_ATTR(_name) \ | ||
220 | static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ | ||
221 | static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \ | ||
222 | static ssize_t atkbd_do_show_##_name(struct device *d, char *b) \ | ||
223 | { \ | ||
224 | return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ | ||
225 | } \ | ||
226 | static ssize_t atkbd_do_set_##_name(struct device *d, const char *b, size_t s) \ | ||
227 | { \ | ||
228 | return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \ | ||
229 | } \ | ||
230 | static struct device_attribute atkbd_attr_##_name = \ | ||
231 | __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name); | ||
232 | |||
233 | ATKBD_DEFINE_ATTR(extra); | ||
234 | ATKBD_DEFINE_ATTR(scroll); | ||
235 | ATKBD_DEFINE_ATTR(set); | ||
236 | ATKBD_DEFINE_ATTR(softrepeat); | ||
237 | ATKBD_DEFINE_ATTR(softraw); | ||
238 | |||
239 | |||
240 | static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) | ||
241 | { | ||
242 | input_regs(dev, regs); | ||
243 | if (value == 3) { | ||
244 | input_report_key(dev, code, 1); | ||
245 | input_sync(dev); | ||
246 | input_report_key(dev, code, 0); | ||
247 | } else | ||
248 | input_event(dev, EV_KEY, code, value); | ||
249 | input_sync(dev); | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * atkbd_interrupt(). Here takes place processing of data received from | ||
254 | * the keyboard into events. | ||
255 | */ | ||
256 | |||
257 | static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, | ||
258 | unsigned int flags, struct pt_regs *regs) | ||
259 | { | ||
260 | struct atkbd *atkbd = serio_get_drvdata(serio); | ||
261 | unsigned int code = data; | ||
262 | int scroll = 0, hscroll = 0, click = -1; | ||
263 | int value; | ||
264 | |||
265 | #ifdef ATKBD_DEBUG | ||
266 | printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags); | ||
267 | #endif | ||
268 | |||
269 | #if !defined(__i386__) && !defined (__x86_64__) | ||
270 | if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { | ||
271 | printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags); | ||
272 | serio_write(serio, ATKBD_CMD_RESEND); | ||
273 | atkbd->resend = 1; | ||
274 | goto out; | ||
275 | } | ||
276 | |||
277 | if (!flags && data == ATKBD_RET_ACK) | ||
278 | atkbd->resend = 0; | ||
279 | #endif | ||
280 | |||
281 | if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK)) | ||
282 | if (ps2_handle_ack(&atkbd->ps2dev, data)) | ||
283 | goto out; | ||
284 | |||
285 | if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD)) | ||
286 | if (ps2_handle_response(&atkbd->ps2dev, data)) | ||
287 | goto out; | ||
288 | |||
289 | if (!atkbd->enabled) | ||
290 | goto out; | ||
291 | |||
292 | input_event(&atkbd->dev, EV_MSC, MSC_RAW, code); | ||
293 | |||
294 | if (atkbd->translated) { | ||
295 | |||
296 | if (atkbd->emul || | ||
297 | !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 || | ||
298 | code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA || | ||
299 | code == ATKBD_RET_ERR || | ||
300 | (code == ATKBD_RET_BAT && !atkbd->bat_xl))) { | ||
301 | atkbd->release = code >> 7; | ||
302 | code &= 0x7f; | ||
303 | } | ||
304 | |||
305 | if (!atkbd->emul && | ||
306 | (code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) | ||
307 | atkbd->bat_xl = !atkbd->release; | ||
308 | } | ||
309 | |||
310 | switch (code) { | ||
311 | case ATKBD_RET_BAT: | ||
312 | atkbd->enabled = 0; | ||
313 | serio_rescan(atkbd->ps2dev.serio); | ||
314 | goto out; | ||
315 | case ATKBD_RET_EMUL0: | ||
316 | atkbd->emul = 1; | ||
317 | goto out; | ||
318 | case ATKBD_RET_EMUL1: | ||
319 | atkbd->emul = 2; | ||
320 | goto out; | ||
321 | case ATKBD_RET_RELEASE: | ||
322 | atkbd->release = 1; | ||
323 | goto out; | ||
324 | case ATKBD_RET_HANGUEL: | ||
325 | atkbd_report_key(&atkbd->dev, regs, KEY_HANGUEL, 3); | ||
326 | goto out; | ||
327 | case ATKBD_RET_HANJA: | ||
328 | atkbd_report_key(&atkbd->dev, regs, KEY_HANJA, 3); | ||
329 | goto out; | ||
330 | case ATKBD_RET_ERR: | ||
331 | printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); | ||
332 | goto out; | ||
333 | } | ||
334 | |||
335 | if (atkbd->set != 3) | ||
336 | code = (code & 0x7f) | ((code & 0x80) << 1); | ||
337 | if (atkbd->emul) { | ||
338 | if (--atkbd->emul) | ||
339 | goto out; | ||
340 | code |= (atkbd->set != 3) ? 0x80 : 0x100; | ||
341 | } | ||
342 | |||
343 | if (atkbd->keycode[code] != ATKBD_KEY_NULL) | ||
344 | input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code); | ||
345 | |||
346 | switch (atkbd->keycode[code]) { | ||
347 | case ATKBD_KEY_NULL: | ||
348 | break; | ||
349 | case ATKBD_KEY_UNKNOWN: | ||
350 | if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) { | ||
351 | printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, " | ||
352 | "like XFree86, might be trying access hardware directly.\n", | ||
353 | data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); | ||
354 | } else { | ||
355 | printk(KERN_WARNING "atkbd.c: Unknown key %s " | ||
356 | "(%s set %d, code %#x on %s).\n", | ||
357 | atkbd->release ? "released" : "pressed", | ||
358 | atkbd->translated ? "translated" : "raw", | ||
359 | atkbd->set, code, serio->phys); | ||
360 | printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' " | ||
361 | "to make it known.\n", | ||
362 | code & 0x80 ? "e0" : "", code & 0x7f); | ||
363 | } | ||
364 | input_sync(&atkbd->dev); | ||
365 | break; | ||
366 | case ATKBD_SCR_1: | ||
367 | scroll = 1 - atkbd->release * 2; | ||
368 | break; | ||
369 | case ATKBD_SCR_2: | ||
370 | scroll = 2 - atkbd->release * 4; | ||
371 | break; | ||
372 | case ATKBD_SCR_4: | ||
373 | scroll = 4 - atkbd->release * 8; | ||
374 | break; | ||
375 | case ATKBD_SCR_8: | ||
376 | scroll = 8 - atkbd->release * 16; | ||
377 | break; | ||
378 | case ATKBD_SCR_CLICK: | ||
379 | click = !atkbd->release; | ||
380 | break; | ||
381 | case ATKBD_SCR_LEFT: | ||
382 | hscroll = -1; | ||
383 | break; | ||
384 | case ATKBD_SCR_RIGHT: | ||
385 | hscroll = 1; | ||
386 | break; | ||
387 | default: | ||
388 | value = atkbd->release ? 0 : | ||
389 | (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key))); | ||
390 | |||
391 | switch (value) { /* Workaround Toshiba laptop multiple keypress */ | ||
392 | case 0: | ||
393 | atkbd->last = 0; | ||
394 | break; | ||
395 | case 1: | ||
396 | atkbd->last = code; | ||
397 | atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev.rep[REP_DELAY]) / 2; | ||
398 | break; | ||
399 | case 2: | ||
400 | if (!time_after(jiffies, atkbd->time) && atkbd->last == code) | ||
401 | value = 1; | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value); | ||
406 | } | ||
407 | |||
408 | if (atkbd->scroll) { | ||
409 | input_regs(&atkbd->dev, regs); | ||
410 | if (click != -1) | ||
411 | input_report_key(&atkbd->dev, BTN_MIDDLE, click); | ||
412 | input_report_rel(&atkbd->dev, REL_WHEEL, scroll); | ||
413 | input_report_rel(&atkbd->dev, REL_HWHEEL, hscroll); | ||
414 | input_sync(&atkbd->dev); | ||
415 | } | ||
416 | |||
417 | atkbd->release = 0; | ||
418 | out: | ||
419 | return IRQ_HANDLED; | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Event callback from the input module. Events that change the state of | ||
424 | * the hardware are processed here. | ||
425 | */ | ||
426 | |||
427 | static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
428 | { | ||
429 | struct atkbd *atkbd = dev->private; | ||
430 | const short period[32] = | ||
431 | { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, | ||
432 | 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 }; | ||
433 | const short delay[4] = | ||
434 | { 250, 500, 750, 1000 }; | ||
435 | unsigned char param[2]; | ||
436 | int i, j; | ||
437 | |||
438 | if (!atkbd->write) | ||
439 | return -1; | ||
440 | |||
441 | switch (type) { | ||
442 | |||
443 | case EV_LED: | ||
444 | |||
445 | param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) | ||
446 | | (test_bit(LED_NUML, dev->led) ? 2 : 0) | ||
447 | | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); | ||
448 | ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS); | ||
449 | |||
450 | if (atkbd->extra) { | ||
451 | param[0] = 0; | ||
452 | param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) | ||
453 | | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) | ||
454 | | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) | ||
455 | | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) | ||
456 | | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); | ||
457 | ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS); | ||
458 | } | ||
459 | |||
460 | return 0; | ||
461 | |||
462 | |||
463 | case EV_REP: | ||
464 | |||
465 | if (atkbd->softrepeat) return 0; | ||
466 | |||
467 | i = j = 0; | ||
468 | while (i < 32 && period[i] < dev->rep[REP_PERIOD]) i++; | ||
469 | while (j < 4 && delay[j] < dev->rep[REP_DELAY]) j++; | ||
470 | dev->rep[REP_PERIOD] = period[i]; | ||
471 | dev->rep[REP_DELAY] = delay[j]; | ||
472 | param[0] = i | (j << 5); | ||
473 | ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | return -1; | ||
479 | } | ||
480 | |||
481 | /* | ||
482 | * atkbd_enable() signals that interrupt handler is allowed to | ||
483 | * generate input events. | ||
484 | */ | ||
485 | |||
486 | static inline void atkbd_enable(struct atkbd *atkbd) | ||
487 | { | ||
488 | serio_pause_rx(atkbd->ps2dev.serio); | ||
489 | atkbd->enabled = 1; | ||
490 | serio_continue_rx(atkbd->ps2dev.serio); | ||
491 | } | ||
492 | |||
493 | /* | ||
494 | * atkbd_disable() tells input handler that all incoming data except | ||
495 | * for ACKs and command response should be dropped. | ||
496 | */ | ||
497 | |||
498 | static inline void atkbd_disable(struct atkbd *atkbd) | ||
499 | { | ||
500 | serio_pause_rx(atkbd->ps2dev.serio); | ||
501 | atkbd->enabled = 0; | ||
502 | serio_continue_rx(atkbd->ps2dev.serio); | ||
503 | } | ||
504 | |||
505 | /* | ||
506 | * atkbd_probe() probes for an AT keyboard on a serio port. | ||
507 | */ | ||
508 | |||
509 | static int atkbd_probe(struct atkbd *atkbd) | ||
510 | { | ||
511 | struct ps2dev *ps2dev = &atkbd->ps2dev; | ||
512 | unsigned char param[2]; | ||
513 | |||
514 | /* | ||
515 | * Some systems, where the bit-twiddling when testing the io-lines of the | ||
516 | * controller may confuse the keyboard need a full reset of the keyboard. On | ||
517 | * these systems the BIOS also usually doesn't do it for us. | ||
518 | */ | ||
519 | |||
520 | if (atkbd_reset) | ||
521 | if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT)) | ||
522 | printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys); | ||
523 | |||
524 | /* | ||
525 | * Then we check the keyboard ID. We should get 0xab83 under normal conditions. | ||
526 | * Some keyboards report different values, but the first byte is always 0xab or | ||
527 | * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this | ||
528 | * should make sure we don't try to set the LEDs on it. | ||
529 | */ | ||
530 | |||
531 | param[0] = param[1] = 0xa5; /* initialize with invalid values */ | ||
532 | if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) { | ||
533 | |||
534 | /* | ||
535 | * If the get ID command failed, we check if we can at least set the LEDs on | ||
536 | * the keyboard. This should work on every keyboard out there. It also turns | ||
537 | * the LEDs off, which we want anyway. | ||
538 | */ | ||
539 | param[0] = 0; | ||
540 | if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) | ||
541 | return -1; | ||
542 | atkbd->id = 0xabba; | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */ | ||
547 | param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */ | ||
548 | param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */ | ||
549 | return -1; | ||
550 | |||
551 | atkbd->id = (param[0] << 8) | param[1]; | ||
552 | |||
553 | if (atkbd->id == 0xaca1 && atkbd->translated) { | ||
554 | printk(KERN_ERR "atkbd.c: NCD terminal keyboards are only supported on non-translating\n"); | ||
555 | printk(KERN_ERR "atkbd.c: controllers. Use i8042.direct=1 to disable translation.\n"); | ||
556 | return -1; | ||
557 | } | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | /* | ||
563 | * atkbd_select_set checks if a keyboard has a working Set 3 support, and | ||
564 | * sets it into that. Unfortunately there are keyboards that can be switched | ||
565 | * to Set 3, but don't work well in that (BTC Multimedia ...) | ||
566 | */ | ||
567 | |||
568 | static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra) | ||
569 | { | ||
570 | struct ps2dev *ps2dev = &atkbd->ps2dev; | ||
571 | unsigned char param[2]; | ||
572 | |||
573 | atkbd->extra = 0; | ||
574 | /* | ||
575 | * For known special keyboards we can go ahead and set the correct set. | ||
576 | * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and | ||
577 | * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards. | ||
578 | */ | ||
579 | |||
580 | if (atkbd->translated) | ||
581 | return 2; | ||
582 | |||
583 | if (atkbd->id == 0xaca1) { | ||
584 | param[0] = 3; | ||
585 | ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET); | ||
586 | return 3; | ||
587 | } | ||
588 | |||
589 | if (allow_extra) { | ||
590 | param[0] = 0x71; | ||
591 | if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) { | ||
592 | atkbd->extra = 1; | ||
593 | return 2; | ||
594 | } | ||
595 | } | ||
596 | |||
597 | if (target_set != 3) | ||
598 | return 2; | ||
599 | |||
600 | if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) { | ||
601 | atkbd->id = param[0] << 8 | param[1]; | ||
602 | return 2; | ||
603 | } | ||
604 | |||
605 | param[0] = 3; | ||
606 | if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) | ||
607 | return 2; | ||
608 | |||
609 | param[0] = 0; | ||
610 | if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET)) | ||
611 | return 2; | ||
612 | |||
613 | if (param[0] != 3) { | ||
614 | param[0] = 2; | ||
615 | if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) | ||
616 | return 2; | ||
617 | } | ||
618 | |||
619 | ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR); | ||
620 | |||
621 | return 3; | ||
622 | } | ||
623 | |||
624 | static int atkbd_activate(struct atkbd *atkbd) | ||
625 | { | ||
626 | struct ps2dev *ps2dev = &atkbd->ps2dev; | ||
627 | unsigned char param[1]; | ||
628 | |||
629 | /* | ||
630 | * Set the LEDs to a defined state. | ||
631 | */ | ||
632 | |||
633 | param[0] = 0; | ||
634 | if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) | ||
635 | return -1; | ||
636 | |||
637 | /* | ||
638 | * Set autorepeat to fastest possible. | ||
639 | */ | ||
640 | |||
641 | param[0] = 0; | ||
642 | if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP)) | ||
643 | return -1; | ||
644 | |||
645 | /* | ||
646 | * Enable the keyboard to receive keystrokes. | ||
647 | */ | ||
648 | |||
649 | if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) { | ||
650 | printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n", | ||
651 | ps2dev->serio->phys); | ||
652 | return -1; | ||
653 | } | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | /* | ||
659 | * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a | ||
660 | * reboot. | ||
661 | */ | ||
662 | |||
663 | static void atkbd_cleanup(struct serio *serio) | ||
664 | { | ||
665 | struct atkbd *atkbd = serio_get_drvdata(serio); | ||
666 | ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT); | ||
667 | } | ||
668 | |||
669 | |||
670 | /* | ||
671 | * atkbd_disconnect() closes and frees. | ||
672 | */ | ||
673 | |||
674 | static void atkbd_disconnect(struct serio *serio) | ||
675 | { | ||
676 | struct atkbd *atkbd = serio_get_drvdata(serio); | ||
677 | |||
678 | atkbd_disable(atkbd); | ||
679 | |||
680 | /* make sure we don't have a command in flight */ | ||
681 | synchronize_kernel(); | ||
682 | flush_scheduled_work(); | ||
683 | |||
684 | device_remove_file(&serio->dev, &atkbd_attr_extra); | ||
685 | device_remove_file(&serio->dev, &atkbd_attr_scroll); | ||
686 | device_remove_file(&serio->dev, &atkbd_attr_set); | ||
687 | device_remove_file(&serio->dev, &atkbd_attr_softrepeat); | ||
688 | device_remove_file(&serio->dev, &atkbd_attr_softraw); | ||
689 | |||
690 | input_unregister_device(&atkbd->dev); | ||
691 | serio_close(serio); | ||
692 | serio_set_drvdata(serio, NULL); | ||
693 | kfree(atkbd); | ||
694 | } | ||
695 | |||
696 | |||
697 | /* | ||
698 | * atkbd_set_device_attrs() initializes keyboard's keycode table | ||
699 | * according to the selected scancode set | ||
700 | */ | ||
701 | |||
702 | static void atkbd_set_keycode_table(struct atkbd *atkbd) | ||
703 | { | ||
704 | int i, j; | ||
705 | |||
706 | memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); | ||
707 | |||
708 | if (atkbd->translated) { | ||
709 | for (i = 0; i < 128; i++) { | ||
710 | atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; | ||
711 | atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; | ||
712 | if (atkbd->scroll) | ||
713 | for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++) | ||
714 | if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2) | ||
715 | atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode; | ||
716 | } | ||
717 | } else if (atkbd->set == 3) { | ||
718 | memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); | ||
719 | } else { | ||
720 | memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); | ||
721 | |||
722 | if (atkbd->scroll) | ||
723 | for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) | ||
724 | atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | /* | ||
729 | * atkbd_set_device_attrs() sets up keyboard's input device structure | ||
730 | */ | ||
731 | |||
732 | static void atkbd_set_device_attrs(struct atkbd *atkbd) | ||
733 | { | ||
734 | int i; | ||
735 | |||
736 | memset(&atkbd->dev, 0, sizeof(struct input_dev)); | ||
737 | |||
738 | init_input_dev(&atkbd->dev); | ||
739 | |||
740 | atkbd->dev.name = atkbd->name; | ||
741 | atkbd->dev.phys = atkbd->phys; | ||
742 | atkbd->dev.id.bustype = BUS_I8042; | ||
743 | atkbd->dev.id.vendor = 0x0001; | ||
744 | atkbd->dev.id.product = atkbd->translated ? 1 : atkbd->set; | ||
745 | atkbd->dev.id.version = atkbd->id; | ||
746 | atkbd->dev.event = atkbd_event; | ||
747 | atkbd->dev.private = atkbd; | ||
748 | atkbd->dev.dev = &atkbd->ps2dev.serio->dev; | ||
749 | |||
750 | atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); | ||
751 | |||
752 | if (atkbd->write) { | ||
753 | atkbd->dev.evbit[0] |= BIT(EV_LED); | ||
754 | atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); | ||
755 | } | ||
756 | |||
757 | if (atkbd->extra) | ||
758 | atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | | ||
759 | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); | ||
760 | |||
761 | if (!atkbd->softrepeat) { | ||
762 | atkbd->dev.rep[REP_DELAY] = 250; | ||
763 | atkbd->dev.rep[REP_PERIOD] = 33; | ||
764 | } | ||
765 | |||
766 | atkbd->dev.mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); | ||
767 | |||
768 | if (atkbd->scroll) { | ||
769 | atkbd->dev.evbit[0] |= BIT(EV_REL); | ||
770 | atkbd->dev.relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL); | ||
771 | set_bit(BTN_MIDDLE, atkbd->dev.keybit); | ||
772 | } | ||
773 | |||
774 | atkbd->dev.keycode = atkbd->keycode; | ||
775 | atkbd->dev.keycodesize = sizeof(unsigned char); | ||
776 | atkbd->dev.keycodemax = ARRAY_SIZE(atkbd_set2_keycode); | ||
777 | |||
778 | for (i = 0; i < 512; i++) | ||
779 | if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) | ||
780 | set_bit(atkbd->keycode[i], atkbd->dev.keybit); | ||
781 | } | ||
782 | |||
783 | /* | ||
784 | * atkbd_connect() is called when the serio module finds an interface | ||
785 | * that isn't handled yet by an appropriate device driver. We check if | ||
786 | * there is an AT keyboard out there and if yes, we register ourselves | ||
787 | * to the input module. | ||
788 | */ | ||
789 | |||
790 | static int atkbd_connect(struct serio *serio, struct serio_driver *drv) | ||
791 | { | ||
792 | struct atkbd *atkbd; | ||
793 | int err; | ||
794 | |||
795 | if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL))) | ||
796 | return - ENOMEM; | ||
797 | |||
798 | memset(atkbd, 0, sizeof(struct atkbd)); | ||
799 | |||
800 | ps2_init(&atkbd->ps2dev, serio); | ||
801 | |||
802 | switch (serio->id.type) { | ||
803 | |||
804 | case SERIO_8042_XL: | ||
805 | atkbd->translated = 1; | ||
806 | case SERIO_8042: | ||
807 | if (serio->write) | ||
808 | atkbd->write = 1; | ||
809 | break; | ||
810 | } | ||
811 | |||
812 | atkbd->softraw = atkbd_softraw; | ||
813 | atkbd->softrepeat = atkbd_softrepeat; | ||
814 | atkbd->scroll = atkbd_scroll; | ||
815 | |||
816 | if (!atkbd->write) | ||
817 | atkbd->softrepeat = 1; | ||
818 | |||
819 | if (atkbd->softrepeat) | ||
820 | atkbd->softraw = 1; | ||
821 | |||
822 | serio_set_drvdata(serio, atkbd); | ||
823 | |||
824 | err = serio_open(serio, drv); | ||
825 | if (err) { | ||
826 | serio_set_drvdata(serio, NULL); | ||
827 | kfree(atkbd); | ||
828 | return err; | ||
829 | } | ||
830 | |||
831 | if (atkbd->write) { | ||
832 | |||
833 | if (atkbd_probe(atkbd)) { | ||
834 | serio_close(serio); | ||
835 | serio_set_drvdata(serio, NULL); | ||
836 | kfree(atkbd); | ||
837 | return -ENODEV; | ||
838 | } | ||
839 | |||
840 | atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); | ||
841 | atkbd_activate(atkbd); | ||
842 | |||
843 | } else { | ||
844 | atkbd->set = 2; | ||
845 | atkbd->id = 0xab00; | ||
846 | } | ||
847 | |||
848 | if (atkbd->extra) | ||
849 | sprintf(atkbd->name, "AT Set 2 Extra keyboard"); | ||
850 | else | ||
851 | sprintf(atkbd->name, "AT %s Set %d keyboard", | ||
852 | atkbd->translated ? "Translated" : "Raw", atkbd->set); | ||
853 | |||
854 | sprintf(atkbd->phys, "%s/input0", serio->phys); | ||
855 | |||
856 | atkbd_set_keycode_table(atkbd); | ||
857 | atkbd_set_device_attrs(atkbd); | ||
858 | |||
859 | input_register_device(&atkbd->dev); | ||
860 | |||
861 | device_create_file(&serio->dev, &atkbd_attr_extra); | ||
862 | device_create_file(&serio->dev, &atkbd_attr_scroll); | ||
863 | device_create_file(&serio->dev, &atkbd_attr_set); | ||
864 | device_create_file(&serio->dev, &atkbd_attr_softrepeat); | ||
865 | device_create_file(&serio->dev, &atkbd_attr_softraw); | ||
866 | |||
867 | atkbd_enable(atkbd); | ||
868 | |||
869 | printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); | ||
870 | |||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | /* | ||
875 | * atkbd_reconnect() tries to restore keyboard into a sane state and is | ||
876 | * most likely called on resume. | ||
877 | */ | ||
878 | |||
879 | static int atkbd_reconnect(struct serio *serio) | ||
880 | { | ||
881 | struct atkbd *atkbd = serio_get_drvdata(serio); | ||
882 | struct serio_driver *drv = serio->drv; | ||
883 | unsigned char param[1]; | ||
884 | |||
885 | if (!atkbd || !drv) { | ||
886 | printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); | ||
887 | return -1; | ||
888 | } | ||
889 | |||
890 | atkbd_disable(atkbd); | ||
891 | |||
892 | if (atkbd->write) { | ||
893 | param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0) | ||
894 | | (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0) | ||
895 | | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0); | ||
896 | |||
897 | if (atkbd_probe(atkbd)) | ||
898 | return -1; | ||
899 | if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) | ||
900 | return -1; | ||
901 | |||
902 | atkbd_activate(atkbd); | ||
903 | |||
904 | if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) | ||
905 | return -1; | ||
906 | } | ||
907 | |||
908 | atkbd_enable(atkbd); | ||
909 | |||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | static struct serio_device_id atkbd_serio_ids[] = { | ||
914 | { | ||
915 | .type = SERIO_8042, | ||
916 | .proto = SERIO_ANY, | ||
917 | .id = SERIO_ANY, | ||
918 | .extra = SERIO_ANY, | ||
919 | }, | ||
920 | { | ||
921 | .type = SERIO_8042_XL, | ||
922 | .proto = SERIO_ANY, | ||
923 | .id = SERIO_ANY, | ||
924 | .extra = SERIO_ANY, | ||
925 | }, | ||
926 | { | ||
927 | .type = SERIO_RS232, | ||
928 | .proto = SERIO_PS2SER, | ||
929 | .id = SERIO_ANY, | ||
930 | .extra = SERIO_ANY, | ||
931 | }, | ||
932 | { 0 } | ||
933 | }; | ||
934 | |||
935 | MODULE_DEVICE_TABLE(serio, atkbd_serio_ids); | ||
936 | |||
937 | static struct serio_driver atkbd_drv = { | ||
938 | .driver = { | ||
939 | .name = "atkbd", | ||
940 | }, | ||
941 | .description = DRIVER_DESC, | ||
942 | .id_table = atkbd_serio_ids, | ||
943 | .interrupt = atkbd_interrupt, | ||
944 | .connect = atkbd_connect, | ||
945 | .reconnect = atkbd_reconnect, | ||
946 | .disconnect = atkbd_disconnect, | ||
947 | .cleanup = atkbd_cleanup, | ||
948 | }; | ||
949 | |||
950 | static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, | ||
951 | ssize_t (*handler)(struct atkbd *, char *)) | ||
952 | { | ||
953 | struct serio *serio = to_serio_port(dev); | ||
954 | int retval; | ||
955 | |||
956 | retval = serio_pin_driver(serio); | ||
957 | if (retval) | ||
958 | return retval; | ||
959 | |||
960 | if (serio->drv != &atkbd_drv) { | ||
961 | retval = -ENODEV; | ||
962 | goto out; | ||
963 | } | ||
964 | |||
965 | retval = handler((struct atkbd *)serio_get_drvdata(serio), buf); | ||
966 | |||
967 | out: | ||
968 | serio_unpin_driver(serio); | ||
969 | return retval; | ||
970 | } | ||
971 | |||
972 | static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, | ||
973 | ssize_t (*handler)(struct atkbd *, const char *, size_t)) | ||
974 | { | ||
975 | struct serio *serio = to_serio_port(dev); | ||
976 | struct atkbd *atkbd; | ||
977 | int retval; | ||
978 | |||
979 | retval = serio_pin_driver(serio); | ||
980 | if (retval) | ||
981 | return retval; | ||
982 | |||
983 | if (serio->drv != &atkbd_drv) { | ||
984 | retval = -ENODEV; | ||
985 | goto out; | ||
986 | } | ||
987 | |||
988 | atkbd = serio_get_drvdata(serio); | ||
989 | atkbd_disable(atkbd); | ||
990 | retval = handler(atkbd, buf, count); | ||
991 | atkbd_enable(atkbd); | ||
992 | |||
993 | out: | ||
994 | serio_unpin_driver(serio); | ||
995 | return retval; | ||
996 | } | ||
997 | |||
998 | static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) | ||
999 | { | ||
1000 | return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0); | ||
1001 | } | ||
1002 | |||
1003 | static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) | ||
1004 | { | ||
1005 | unsigned long value; | ||
1006 | char *rest; | ||
1007 | |||
1008 | if (!atkbd->write) | ||
1009 | return -EIO; | ||
1010 | |||
1011 | value = simple_strtoul(buf, &rest, 10); | ||
1012 | if (*rest || value > 1) | ||
1013 | return -EINVAL; | ||
1014 | |||
1015 | if (atkbd->extra != value) { | ||
1016 | /* unregister device as it's properties will change */ | ||
1017 | input_unregister_device(&atkbd->dev); | ||
1018 | atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); | ||
1019 | atkbd_activate(atkbd); | ||
1020 | atkbd_set_device_attrs(atkbd); | ||
1021 | input_register_device(&atkbd->dev); | ||
1022 | } | ||
1023 | return count; | ||
1024 | } | ||
1025 | |||
1026 | static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) | ||
1027 | { | ||
1028 | return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0); | ||
1029 | } | ||
1030 | |||
1031 | static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) | ||
1032 | { | ||
1033 | unsigned long value; | ||
1034 | char *rest; | ||
1035 | |||
1036 | value = simple_strtoul(buf, &rest, 10); | ||
1037 | if (*rest || value > 1) | ||
1038 | return -EINVAL; | ||
1039 | |||
1040 | if (atkbd->scroll != value) { | ||
1041 | /* unregister device as it's properties will change */ | ||
1042 | input_unregister_device(&atkbd->dev); | ||
1043 | atkbd->scroll = value; | ||
1044 | atkbd_set_keycode_table(atkbd); | ||
1045 | atkbd_set_device_attrs(atkbd); | ||
1046 | input_register_device(&atkbd->dev); | ||
1047 | } | ||
1048 | return count; | ||
1049 | } | ||
1050 | |||
1051 | static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf) | ||
1052 | { | ||
1053 | return sprintf(buf, "%d\n", atkbd->set); | ||
1054 | } | ||
1055 | |||
1056 | static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) | ||
1057 | { | ||
1058 | unsigned long value; | ||
1059 | char *rest; | ||
1060 | |||
1061 | if (!atkbd->write) | ||
1062 | return -EIO; | ||
1063 | |||
1064 | value = simple_strtoul(buf, &rest, 10); | ||
1065 | if (*rest || (value != 2 && value != 3)) | ||
1066 | return -EINVAL; | ||
1067 | |||
1068 | if (atkbd->set != value) { | ||
1069 | /* unregister device as it's properties will change */ | ||
1070 | input_unregister_device(&atkbd->dev); | ||
1071 | atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); | ||
1072 | atkbd_activate(atkbd); | ||
1073 | atkbd_set_keycode_table(atkbd); | ||
1074 | atkbd_set_device_attrs(atkbd); | ||
1075 | input_register_device(&atkbd->dev); | ||
1076 | } | ||
1077 | return count; | ||
1078 | } | ||
1079 | |||
1080 | static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf) | ||
1081 | { | ||
1082 | return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0); | ||
1083 | } | ||
1084 | |||
1085 | static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) | ||
1086 | { | ||
1087 | unsigned long value; | ||
1088 | char *rest; | ||
1089 | |||
1090 | if (!atkbd->write) | ||
1091 | return -EIO; | ||
1092 | |||
1093 | value = simple_strtoul(buf, &rest, 10); | ||
1094 | if (*rest || value > 1) | ||
1095 | return -EINVAL; | ||
1096 | |||
1097 | if (atkbd->softrepeat != value) { | ||
1098 | /* unregister device as it's properties will change */ | ||
1099 | input_unregister_device(&atkbd->dev); | ||
1100 | atkbd->softrepeat = value; | ||
1101 | if (atkbd->softrepeat) | ||
1102 | atkbd->softraw = 1; | ||
1103 | atkbd_set_device_attrs(atkbd); | ||
1104 | input_register_device(&atkbd->dev); | ||
1105 | } | ||
1106 | |||
1107 | return count; | ||
1108 | } | ||
1109 | |||
1110 | |||
1111 | static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) | ||
1112 | { | ||
1113 | return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0); | ||
1114 | } | ||
1115 | |||
1116 | static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) | ||
1117 | { | ||
1118 | unsigned long value; | ||
1119 | char *rest; | ||
1120 | |||
1121 | value = simple_strtoul(buf, &rest, 10); | ||
1122 | if (*rest || value > 1) | ||
1123 | return -EINVAL; | ||
1124 | |||
1125 | if (atkbd->softraw != value) { | ||
1126 | /* unregister device as it's properties will change */ | ||
1127 | input_unregister_device(&atkbd->dev); | ||
1128 | atkbd->softraw = value; | ||
1129 | atkbd_set_device_attrs(atkbd); | ||
1130 | input_register_device(&atkbd->dev); | ||
1131 | } | ||
1132 | return count; | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | static int __init atkbd_init(void) | ||
1137 | { | ||
1138 | serio_register_driver(&atkbd_drv); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static void __exit atkbd_exit(void) | ||
1143 | { | ||
1144 | serio_unregister_driver(&atkbd_drv); | ||
1145 | } | ||
1146 | |||
1147 | module_init(atkbd_init); | ||
1148 | module_exit(atkbd_exit); | ||
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c new file mode 100644 index 000000000000..0f1220a0ceb5 --- /dev/null +++ b/drivers/input/keyboard/corgikbd.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | * Keyboard driver for Sharp Corgi models (SL-C7xx) | ||
3 | * | ||
4 | * Copyright (c) 2004-2005 Richard Purdie | ||
5 | * | ||
6 | * Based on xtkbd.c/locomkbd.c | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/input.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <asm/irq.h> | ||
22 | |||
23 | #include <asm/arch/corgi.h> | ||
24 | #include <asm/arch/hardware.h> | ||
25 | #include <asm/arch/pxa-regs.h> | ||
26 | #include <asm/hardware/scoop.h> | ||
27 | |||
28 | #define KB_ROWS 8 | ||
29 | #define KB_COLS 12 | ||
30 | #define KB_ROWMASK(r) (1 << (r)) | ||
31 | #define SCANCODE(r,c) ( ((r)<<4) + (c) + 1 ) | ||
32 | /* zero code, 124 scancodes + 3 hinge combinations */ | ||
33 | #define NR_SCANCODES ( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 ) | ||
34 | #define SCAN_INTERVAL (HZ/10) | ||
35 | #define CORGIKBD_PRESSED 1 | ||
36 | |||
37 | #define HINGE_SCAN_INTERVAL (HZ/4) | ||
38 | |||
39 | #define CORGI_KEY_CALENDER KEY_F1 | ||
40 | #define CORGI_KEY_ADDRESS KEY_F2 | ||
41 | #define CORGI_KEY_FN KEY_F3 | ||
42 | #define CORGI_KEY_OFF KEY_SUSPEND | ||
43 | #define CORGI_KEY_EXOK KEY_F5 | ||
44 | #define CORGI_KEY_EXCANCEL KEY_F6 | ||
45 | #define CORGI_KEY_EXJOGDOWN KEY_F7 | ||
46 | #define CORGI_KEY_EXJOGUP KEY_F8 | ||
47 | #define CORGI_KEY_JAP1 KEY_LEFTCTRL | ||
48 | #define CORGI_KEY_JAP2 KEY_LEFTALT | ||
49 | #define CORGI_KEY_OK KEY_F11 | ||
50 | #define CORGI_KEY_MENU KEY_F12 | ||
51 | #define CORGI_HINGE_0 KEY_KP0 | ||
52 | #define CORGI_HINGE_1 KEY_KP1 | ||
53 | #define CORGI_HINGE_2 KEY_KP2 | ||
54 | |||
55 | static unsigned char corgikbd_keycode[NR_SCANCODES] = { | ||
56 | 0, /* 0 */ | ||
57 | 0, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, 0, 0, 0, 0, 0, 0, 0, /* 1-16 */ | ||
58 | 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, 0, 0, 0, 0, 0, 0, 0, /* 17-32 */ | ||
59 | KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */ | ||
60 | CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */ | ||
61 | CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, /* 65-80 */ | ||
62 | KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */ | ||
63 | KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */ | ||
64 | CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0, /* 113-124 */ | ||
65 | CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2 /* 125-127 */ | ||
66 | }; | ||
67 | |||
68 | |||
69 | struct corgikbd { | ||
70 | unsigned char keycode[ARRAY_SIZE(corgikbd_keycode)]; | ||
71 | struct input_dev input; | ||
72 | char phys[32]; | ||
73 | |||
74 | unsigned char state[ARRAY_SIZE(corgikbd_keycode)]; | ||
75 | spinlock_t lock; | ||
76 | |||
77 | struct timer_list timer; | ||
78 | struct timer_list htimer; | ||
79 | }; | ||
80 | |||
81 | static void handle_scancode(unsigned int pressed,unsigned int scancode, struct corgikbd *corgikbd_data) | ||
82 | { | ||
83 | if (pressed && !(corgikbd_data->state[scancode] & CORGIKBD_PRESSED)) { | ||
84 | corgikbd_data->state[scancode] |= CORGIKBD_PRESSED; | ||
85 | input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 1); | ||
86 | if (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF) | ||
87 | input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1); | ||
88 | } else if (!pressed && corgikbd_data->state[scancode] & CORGIKBD_PRESSED) { | ||
89 | corgikbd_data->state[scancode] &= ~CORGIKBD_PRESSED; | ||
90 | input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 0); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | #define KB_DISCHARGE_DELAY 10 | ||
95 | #define KB_ACTIVATE_DELAY 10 | ||
96 | |||
97 | /* Helper functions for reading the keyboard matrix | ||
98 | * Note: We should really be using pxa_gpio_mode to alter GPDR but it | ||
99 | * requires a function call per GPIO bit which is excessive | ||
100 | * when we need to access 12 bits at once multiple times. | ||
101 | * These functions must be called within local_irq_save()/local_irq_restore() | ||
102 | * or similar. | ||
103 | */ | ||
104 | static inline void corgikbd_discharge_all(void) | ||
105 | { | ||
106 | // STROBE All HiZ | ||
107 | GPCR2 = CORGI_GPIO_ALL_STROBE_BIT; | ||
108 | GPDR2 &= ~CORGI_GPIO_ALL_STROBE_BIT; | ||
109 | } | ||
110 | |||
111 | static inline void corgikbd_activate_all(void) | ||
112 | { | ||
113 | // STROBE ALL -> High | ||
114 | GPSR2 = CORGI_GPIO_ALL_STROBE_BIT; | ||
115 | GPDR2 |= CORGI_GPIO_ALL_STROBE_BIT; | ||
116 | |||
117 | udelay(KB_DISCHARGE_DELAY); | ||
118 | |||
119 | // Clear any interrupts we may have triggered when altering the GPIO lines | ||
120 | GEDR1 = CORGI_GPIO_HIGH_SENSE_BIT; | ||
121 | GEDR2 = CORGI_GPIO_LOW_SENSE_BIT; | ||
122 | } | ||
123 | |||
124 | static inline void corgikbd_activate_col(int col) | ||
125 | { | ||
126 | // STROBE col -> High, not col -> HiZ | ||
127 | GPSR2 = CORGI_GPIO_STROBE_BIT(col); | ||
128 | GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col); | ||
129 | } | ||
130 | |||
131 | static inline void corgikbd_reset_col(int col) | ||
132 | { | ||
133 | // STROBE col -> Low | ||
134 | GPCR2 = CORGI_GPIO_STROBE_BIT(col); | ||
135 | // STROBE col -> out, not col -> HiZ | ||
136 | GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col); | ||
137 | } | ||
138 | |||
139 | #define GET_ROWS_STATUS(c) (((GPLR1 & CORGI_GPIO_HIGH_SENSE_BIT) >> CORGI_GPIO_HIGH_SENSE_RSHIFT) | ((GPLR2 & CORGI_GPIO_LOW_SENSE_BIT) << CORGI_GPIO_LOW_SENSE_LSHIFT)) | ||
140 | |||
141 | /* | ||
142 | * The corgi keyboard only generates interrupts when a key is pressed. | ||
143 | * When a key is pressed, we enable a timer which then scans the | ||
144 | * keyboard to detect when the key is released. | ||
145 | */ | ||
146 | |||
147 | /* Scan the hardware keyboard and push any changes up through the input layer */ | ||
148 | static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs) | ||
149 | { | ||
150 | unsigned int row, col, rowd, scancode; | ||
151 | unsigned long flags; | ||
152 | unsigned int num_pressed; | ||
153 | |||
154 | spin_lock_irqsave(&corgikbd_data->lock, flags); | ||
155 | |||
156 | if (regs) | ||
157 | input_regs(&corgikbd_data->input, regs); | ||
158 | |||
159 | num_pressed = 0; | ||
160 | for (col = 0; col < KB_COLS; col++) { | ||
161 | /* | ||
162 | * Discharge the output driver capacitatance | ||
163 | * in the keyboard matrix. (Yes it is significant..) | ||
164 | */ | ||
165 | |||
166 | corgikbd_discharge_all(); | ||
167 | udelay(KB_DISCHARGE_DELAY); | ||
168 | |||
169 | corgikbd_activate_col(col); | ||
170 | udelay(KB_ACTIVATE_DELAY); | ||
171 | |||
172 | rowd = GET_ROWS_STATUS(col); | ||
173 | for (row = 0; row < KB_ROWS; row++) { | ||
174 | scancode = SCANCODE(row, col); | ||
175 | handle_scancode((rowd & KB_ROWMASK(row)), scancode, corgikbd_data); | ||
176 | if (rowd & KB_ROWMASK(row)) | ||
177 | num_pressed++; | ||
178 | } | ||
179 | corgikbd_reset_col(col); | ||
180 | } | ||
181 | |||
182 | corgikbd_activate_all(); | ||
183 | |||
184 | input_sync(&corgikbd_data->input); | ||
185 | |||
186 | /* if any keys are pressed, enable the timer */ | ||
187 | if (num_pressed) | ||
188 | mod_timer(&corgikbd_data->timer, jiffies + SCAN_INTERVAL); | ||
189 | |||
190 | spin_unlock_irqrestore(&corgikbd_data->lock, flags); | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * corgi keyboard interrupt handler. | ||
195 | */ | ||
196 | static irqreturn_t corgikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
197 | { | ||
198 | struct corgikbd *corgikbd_data = dev_id; | ||
199 | |||
200 | if (!timer_pending(&corgikbd_data->timer)) { | ||
201 | /** wait chattering delay **/ | ||
202 | udelay(20); | ||
203 | corgikbd_scankeyboard(corgikbd_data, regs); | ||
204 | } | ||
205 | |||
206 | return IRQ_HANDLED; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * corgi timer checking for released keys | ||
211 | */ | ||
212 | static void corgikbd_timer_callback(unsigned long data) | ||
213 | { | ||
214 | struct corgikbd *corgikbd_data = (struct corgikbd *) data; | ||
215 | corgikbd_scankeyboard(corgikbd_data, NULL); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * The hinge switches generate no interrupt so they need to be | ||
220 | * monitored by a timer. | ||
221 | * | ||
222 | * When we detect changes, we debounce it and then pass the three | ||
223 | * positions the system can take as keypresses to the input system. | ||
224 | */ | ||
225 | |||
226 | #define HINGE_STABLE_COUNT 2 | ||
227 | static int sharpsl_hinge_state; | ||
228 | static int hinge_count; | ||
229 | |||
230 | static void corgikbd_hinge_timer(unsigned long data) | ||
231 | { | ||
232 | struct corgikbd *corgikbd_data = (struct corgikbd *) data; | ||
233 | unsigned long gprr; | ||
234 | unsigned long flags; | ||
235 | |||
236 | gprr = read_scoop_reg(SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB); | ||
237 | if (gprr != sharpsl_hinge_state) { | ||
238 | hinge_count = 0; | ||
239 | sharpsl_hinge_state = gprr; | ||
240 | } else if (hinge_count < HINGE_STABLE_COUNT) { | ||
241 | hinge_count++; | ||
242 | if (hinge_count >= HINGE_STABLE_COUNT) { | ||
243 | spin_lock_irqsave(&corgikbd_data->lock, flags); | ||
244 | |||
245 | handle_scancode((sharpsl_hinge_state == 0x00), 125, corgikbd_data); /* Keyboard with Landscape Screen */ | ||
246 | handle_scancode((sharpsl_hinge_state == 0x08), 126, corgikbd_data); /* No Keyboard with Portrait Screen */ | ||
247 | handle_scancode((sharpsl_hinge_state == 0x0c), 127, corgikbd_data); /* Keyboard and Screen Closed */ | ||
248 | input_sync(&corgikbd_data->input); | ||
249 | |||
250 | spin_unlock_irqrestore(&corgikbd_data->lock, flags); | ||
251 | } | ||
252 | } | ||
253 | mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL); | ||
254 | } | ||
255 | |||
256 | static int __init corgikbd_probe(struct device *dev) | ||
257 | { | ||
258 | int i; | ||
259 | struct corgikbd *corgikbd; | ||
260 | |||
261 | corgikbd = kcalloc(1, sizeof(struct corgikbd), GFP_KERNEL); | ||
262 | if (!corgikbd) | ||
263 | return -ENOMEM; | ||
264 | |||
265 | dev_set_drvdata(dev,corgikbd); | ||
266 | strcpy(corgikbd->phys, "corgikbd/input0"); | ||
267 | |||
268 | spin_lock_init(corgikbd->lock); | ||
269 | |||
270 | /* Init Keyboard rescan timer */ | ||
271 | init_timer(&corgikbd->timer); | ||
272 | corgikbd->timer.function = corgikbd_timer_callback; | ||
273 | corgikbd->timer.data = (unsigned long) corgikbd; | ||
274 | |||
275 | /* Init Hinge Timer */ | ||
276 | init_timer(&corgikbd->htimer); | ||
277 | corgikbd->htimer.function = corgikbd_hinge_timer; | ||
278 | corgikbd->htimer.data = (unsigned long) corgikbd; | ||
279 | |||
280 | init_input_dev(&corgikbd->input); | ||
281 | corgikbd->input.private = corgikbd; | ||
282 | corgikbd->input.name = "Corgi Keyboard"; | ||
283 | corgikbd->input.dev = dev; | ||
284 | corgikbd->input.phys = corgikbd->phys; | ||
285 | corgikbd->input.id.bustype = BUS_HOST; | ||
286 | corgikbd->input.id.vendor = 0x0001; | ||
287 | corgikbd->input.id.product = 0x0001; | ||
288 | corgikbd->input.id.version = 0x0100; | ||
289 | corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR); | ||
290 | corgikbd->input.keycode = corgikbd->keycode; | ||
291 | corgikbd->input.keycodesize = sizeof(unsigned char); | ||
292 | corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode); | ||
293 | |||
294 | memcpy(corgikbd->keycode, corgikbd_keycode, sizeof(corgikbd->keycode)); | ||
295 | for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++) | ||
296 | set_bit(corgikbd->keycode[i], corgikbd->input.keybit); | ||
297 | clear_bit(0, corgikbd->input.keybit); | ||
298 | |||
299 | input_register_device(&corgikbd->input); | ||
300 | mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL); | ||
301 | |||
302 | /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ | ||
303 | for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) { | ||
304 | pxa_gpio_mode(CORGI_GPIO_KEY_SENSE(i) | GPIO_IN); | ||
305 | if (request_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd_interrupt, | ||
306 | SA_INTERRUPT, "corgikbd", corgikbd)) | ||
307 | printk(KERN_WARNING "corgikbd: Can't get IRQ: %d!\n", i); | ||
308 | else | ||
309 | set_irq_type(CORGI_IRQ_GPIO_KEY_SENSE(i),IRQT_RISING); | ||
310 | } | ||
311 | |||
312 | /* Set Strobe lines as outputs - set high */ | ||
313 | for (i = 0; i < CORGI_KEY_STROBE_NUM; i++) | ||
314 | pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH); | ||
315 | |||
316 | printk(KERN_INFO "input: Corgi Keyboard Registered\n"); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static int corgikbd_remove(struct device *dev) | ||
322 | { | ||
323 | int i; | ||
324 | struct corgikbd *corgikbd = dev_get_drvdata(dev); | ||
325 | |||
326 | for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) | ||
327 | free_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd); | ||
328 | |||
329 | del_timer_sync(&corgikbd->htimer); | ||
330 | del_timer_sync(&corgikbd->timer); | ||
331 | |||
332 | input_unregister_device(&corgikbd->input); | ||
333 | |||
334 | kfree(corgikbd); | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static struct device_driver corgikbd_driver = { | ||
340 | .name = "corgi-keyboard", | ||
341 | .bus = &platform_bus_type, | ||
342 | .probe = corgikbd_probe, | ||
343 | .remove = corgikbd_remove, | ||
344 | }; | ||
345 | |||
346 | static int __devinit corgikbd_init(void) | ||
347 | { | ||
348 | return driver_register(&corgikbd_driver); | ||
349 | } | ||
350 | |||
351 | static void __exit corgikbd_exit(void) | ||
352 | { | ||
353 | driver_unregister(&corgikbd_driver); | ||
354 | } | ||
355 | |||
356 | module_init(corgikbd_init); | ||
357 | module_exit(corgikbd_exit); | ||
358 | |||
359 | MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); | ||
360 | MODULE_DESCRIPTION("Corgi Keyboard Driver"); | ||
361 | MODULE_LICENSE("GPLv2"); | ||
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c new file mode 100644 index 000000000000..ef78bffed5e7 --- /dev/null +++ b/drivers/input/keyboard/hil_kbd.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * Generic linux-input device driver for keyboard devices | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/hil.h> | ||
35 | #include <linux/input.h> | ||
36 | #include <linux/serio.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/pci_ids.h> | ||
42 | |||
43 | #define PREFIX "HIL KEYB: " | ||
44 | #define HIL_GENERIC_NAME "HIL keyboard" | ||
45 | |||
46 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
47 | MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); | ||
48 | MODULE_LICENSE("Dual BSD/GPL"); | ||
49 | |||
50 | #define HIL_KBD_MAX_LENGTH 16 | ||
51 | |||
52 | #define HIL_KBD_SET1_UPBIT 0x01 | ||
53 | #define HIL_KBD_SET1_SHIFT 1 | ||
54 | static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] = | ||
55 | { HIL_KEYCODES_SET1 }; | ||
56 | |||
57 | #define HIL_KBD_SET2_UPBIT 0x01 | ||
58 | #define HIL_KBD_SET2_SHIFT 1 | ||
59 | /* Set2 is user defined */ | ||
60 | |||
61 | #define HIL_KBD_SET3_UPBIT 0x80 | ||
62 | #define HIL_KBD_SET3_SHIFT 0 | ||
63 | static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] = | ||
64 | { HIL_KEYCODES_SET3 }; | ||
65 | |||
66 | static char hil_language[][16] = { HIL_LOCALE_MAP }; | ||
67 | |||
68 | struct hil_kbd { | ||
69 | struct input_dev dev; | ||
70 | struct serio *serio; | ||
71 | |||
72 | /* Input buffer and index for packets from HIL bus. */ | ||
73 | hil_packet data[HIL_KBD_MAX_LENGTH]; | ||
74 | int idx4; /* four counts per packet */ | ||
75 | |||
76 | /* Raw device info records from HIL bus, see hil.h for fields. */ | ||
77 | char idd[HIL_KBD_MAX_LENGTH]; /* DID byte and IDD record */ | ||
78 | char rsc[HIL_KBD_MAX_LENGTH]; /* RSC record */ | ||
79 | char exd[HIL_KBD_MAX_LENGTH]; /* EXD record */ | ||
80 | char rnm[HIL_KBD_MAX_LENGTH + 1]; /* RNM record + NULL term. */ | ||
81 | |||
82 | /* Something to sleep around with. */ | ||
83 | struct semaphore sem; | ||
84 | }; | ||
85 | |||
86 | /* Process a complete packet after transfer from the HIL */ | ||
87 | static void hil_kbd_process_record(struct hil_kbd *kbd) | ||
88 | { | ||
89 | struct input_dev *dev = &kbd->dev; | ||
90 | hil_packet *data = kbd->data; | ||
91 | hil_packet p; | ||
92 | int idx, i, cnt; | ||
93 | |||
94 | idx = kbd->idx4/4; | ||
95 | p = data[idx - 1]; | ||
96 | |||
97 | if ((p & ~HIL_CMDCT_POL) == | ||
98 | (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report; | ||
99 | if ((p & ~HIL_CMDCT_RPL) == | ||
100 | (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report; | ||
101 | |||
102 | /* Not a poll response. See if we are loading config records. */ | ||
103 | switch (p & HIL_PKT_DATA_MASK) { | ||
104 | case HIL_CMD_IDD: | ||
105 | for (i = 0; i < idx; i++) | ||
106 | kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; | ||
107 | for (; i < HIL_KBD_MAX_LENGTH; i++) | ||
108 | kbd->idd[i] = 0; | ||
109 | break; | ||
110 | case HIL_CMD_RSC: | ||
111 | for (i = 0; i < idx; i++) | ||
112 | kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK; | ||
113 | for (; i < HIL_KBD_MAX_LENGTH; i++) | ||
114 | kbd->rsc[i] = 0; | ||
115 | break; | ||
116 | case HIL_CMD_EXD: | ||
117 | for (i = 0; i < idx; i++) | ||
118 | kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; | ||
119 | for (; i < HIL_KBD_MAX_LENGTH; i++) | ||
120 | kbd->exd[i] = 0; | ||
121 | break; | ||
122 | case HIL_CMD_RNM: | ||
123 | for (i = 0; i < idx; i++) | ||
124 | kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK; | ||
125 | for (; i < HIL_KBD_MAX_LENGTH + 1; i++) | ||
126 | kbd->rnm[i] = '\0'; | ||
127 | break; | ||
128 | default: | ||
129 | /* These occur when device isn't present */ | ||
130 | if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; | ||
131 | /* Anything else we'd like to know about. */ | ||
132 | printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); | ||
133 | break; | ||
134 | } | ||
135 | goto out; | ||
136 | |||
137 | report: | ||
138 | cnt = 1; | ||
139 | switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) { | ||
140 | case HIL_POL_CHARTYPE_NONE: | ||
141 | break; | ||
142 | case HIL_POL_CHARTYPE_ASCII: | ||
143 | while (cnt < idx - 1) | ||
144 | input_report_key(dev, kbd->data[cnt++] & 0x7f, 1); | ||
145 | break; | ||
146 | case HIL_POL_CHARTYPE_RSVD1: | ||
147 | case HIL_POL_CHARTYPE_RSVD2: | ||
148 | case HIL_POL_CHARTYPE_BINARY: | ||
149 | while (cnt < idx - 1) | ||
150 | input_report_key(dev, kbd->data[cnt++], 1); | ||
151 | break; | ||
152 | case HIL_POL_CHARTYPE_SET1: | ||
153 | while (cnt < idx - 1) { | ||
154 | unsigned int key; | ||
155 | int up; | ||
156 | key = kbd->data[cnt++]; | ||
157 | up = key & HIL_KBD_SET1_UPBIT; | ||
158 | key &= (~HIL_KBD_SET1_UPBIT & 0xff); | ||
159 | key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT]; | ||
160 | if (key != KEY_RESERVED) | ||
161 | input_report_key(dev, key, !up); | ||
162 | } | ||
163 | break; | ||
164 | case HIL_POL_CHARTYPE_SET2: | ||
165 | while (cnt < idx - 1) { | ||
166 | unsigned int key; | ||
167 | int up; | ||
168 | key = kbd->data[cnt++]; | ||
169 | up = key & HIL_KBD_SET2_UPBIT; | ||
170 | key &= (~HIL_KBD_SET1_UPBIT & 0xff); | ||
171 | key = key >> HIL_KBD_SET2_SHIFT; | ||
172 | if (key != KEY_RESERVED) | ||
173 | input_report_key(dev, key, !up); | ||
174 | } | ||
175 | break; | ||
176 | case HIL_POL_CHARTYPE_SET3: | ||
177 | while (cnt < idx - 1) { | ||
178 | unsigned int key; | ||
179 | int up; | ||
180 | key = kbd->data[cnt++]; | ||
181 | up = key & HIL_KBD_SET3_UPBIT; | ||
182 | key &= (~HIL_KBD_SET1_UPBIT & 0xff); | ||
183 | key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT]; | ||
184 | if (key != KEY_RESERVED) | ||
185 | input_report_key(dev, key, !up); | ||
186 | } | ||
187 | break; | ||
188 | } | ||
189 | out: | ||
190 | kbd->idx4 = 0; | ||
191 | up(&kbd->sem); | ||
192 | } | ||
193 | |||
194 | static void hil_kbd_process_err(struct hil_kbd *kbd) { | ||
195 | printk(KERN_WARNING PREFIX "errored HIL packet\n"); | ||
196 | kbd->idx4 = 0; | ||
197 | up(&kbd->sem); | ||
198 | } | ||
199 | |||
200 | static irqreturn_t hil_kbd_interrupt(struct serio *serio, | ||
201 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
202 | { | ||
203 | struct hil_kbd *kbd; | ||
204 | hil_packet packet; | ||
205 | int idx; | ||
206 | |||
207 | kbd = (struct hil_kbd *)serio->private; | ||
208 | if (kbd == NULL) { | ||
209 | BUG(); | ||
210 | return IRQ_HANDLED; | ||
211 | } | ||
212 | |||
213 | if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) { | ||
214 | hil_kbd_process_err(kbd); | ||
215 | return IRQ_HANDLED; | ||
216 | } | ||
217 | idx = kbd->idx4/4; | ||
218 | if (!(kbd->idx4 % 4)) kbd->data[idx] = 0; | ||
219 | packet = kbd->data[idx]; | ||
220 | packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8); | ||
221 | kbd->data[idx] = packet; | ||
222 | |||
223 | /* Records of N 4-byte hil_packets must terminate with a command. */ | ||
224 | if ((++(kbd->idx4)) % 4) return IRQ_HANDLED; | ||
225 | if ((packet & 0xffff0000) != HIL_ERR_INT) { | ||
226 | hil_kbd_process_err(kbd); | ||
227 | return IRQ_HANDLED; | ||
228 | } | ||
229 | if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd); | ||
230 | return IRQ_HANDLED; | ||
231 | } | ||
232 | |||
233 | static void hil_kbd_disconnect(struct serio *serio) | ||
234 | { | ||
235 | struct hil_kbd *kbd; | ||
236 | |||
237 | kbd = (struct hil_kbd *)serio->private; | ||
238 | if (kbd == NULL) { | ||
239 | BUG(); | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | input_unregister_device(&kbd->dev); | ||
244 | serio_close(serio); | ||
245 | kfree(kbd); | ||
246 | } | ||
247 | |||
248 | static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv) | ||
249 | { | ||
250 | struct hil_kbd *kbd; | ||
251 | uint8_t did, *idd; | ||
252 | int i; | ||
253 | |||
254 | if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; | ||
255 | |||
256 | if (!(kbd = kmalloc(sizeof(struct hil_kbd), GFP_KERNEL))) return; | ||
257 | memset(kbd, 0, sizeof(struct hil_kbd)); | ||
258 | |||
259 | if (serio_open(serio, drv)) goto bail0; | ||
260 | |||
261 | serio->private = kbd; | ||
262 | kbd->serio = serio; | ||
263 | kbd->dev.private = kbd; | ||
264 | |||
265 | init_MUTEX_LOCKED(&(kbd->sem)); | ||
266 | |||
267 | /* Get device info. MLC driver supplies devid/status/etc. */ | ||
268 | serio->write(serio, 0); | ||
269 | serio->write(serio, 0); | ||
270 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
271 | serio->write(serio, HIL_CMD_IDD); | ||
272 | down(&(kbd->sem)); | ||
273 | |||
274 | serio->write(serio, 0); | ||
275 | serio->write(serio, 0); | ||
276 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
277 | serio->write(serio, HIL_CMD_RSC); | ||
278 | down(&(kbd->sem)); | ||
279 | |||
280 | serio->write(serio, 0); | ||
281 | serio->write(serio, 0); | ||
282 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
283 | serio->write(serio, HIL_CMD_RNM); | ||
284 | down(&(kbd->sem)); | ||
285 | |||
286 | serio->write(serio, 0); | ||
287 | serio->write(serio, 0); | ||
288 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
289 | serio->write(serio, HIL_CMD_EXD); | ||
290 | down(&(kbd->sem)); | ||
291 | |||
292 | up(&(kbd->sem)); | ||
293 | |||
294 | did = kbd->idd[0]; | ||
295 | idd = kbd->idd + 1; | ||
296 | switch (did & HIL_IDD_DID_TYPE_MASK) { | ||
297 | case HIL_IDD_DID_TYPE_KB_INTEGRAL: | ||
298 | case HIL_IDD_DID_TYPE_KB_ITF: | ||
299 | case HIL_IDD_DID_TYPE_KB_RSVD: | ||
300 | case HIL_IDD_DID_TYPE_CHAR: | ||
301 | printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", | ||
302 | did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); | ||
303 | break; | ||
304 | default: | ||
305 | goto bail1; | ||
306 | } | ||
307 | |||
308 | if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { | ||
309 | printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n"); | ||
310 | goto bail1; | ||
311 | } | ||
312 | |||
313 | |||
314 | kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
315 | kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); | ||
316 | kbd->dev.keycodemax = HIL_KEYCODES_SET1_TBLSIZE; | ||
317 | kbd->dev.keycodesize = sizeof(hil_kbd_set1[0]); | ||
318 | kbd->dev.keycode = hil_kbd_set1; | ||
319 | kbd->dev.name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; | ||
320 | kbd->dev.phys = "hpkbd/input0"; /* XXX */ | ||
321 | |||
322 | kbd->dev.id.bustype = BUS_HIL; | ||
323 | kbd->dev.id.vendor = PCI_VENDOR_ID_HP; | ||
324 | kbd->dev.id.product = 0x0001; /* TODO: get from kbd->rsc */ | ||
325 | kbd->dev.id.version = 0x0100; /* TODO: get from kbd->rsc */ | ||
326 | kbd->dev.dev = &serio->dev; | ||
327 | |||
328 | for (i = 0; i < 128; i++) { | ||
329 | set_bit(hil_kbd_set1[i], kbd->dev.keybit); | ||
330 | set_bit(hil_kbd_set3[i], kbd->dev.keybit); | ||
331 | } | ||
332 | clear_bit(0, kbd->dev.keybit); | ||
333 | |||
334 | input_register_device(&kbd->dev); | ||
335 | printk(KERN_INFO "input: %s, ID: %d\n", | ||
336 | kbd->dev.name, did); | ||
337 | |||
338 | serio->write(serio, 0); | ||
339 | serio->write(serio, 0); | ||
340 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
341 | serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ | ||
342 | down(&(kbd->sem)); | ||
343 | up(&(kbd->sem)); | ||
344 | |||
345 | return; | ||
346 | bail1: | ||
347 | serio_close(serio); | ||
348 | bail0: | ||
349 | kfree(kbd); | ||
350 | } | ||
351 | |||
352 | |||
353 | struct serio_driver hil_kbd_serio_drv = { | ||
354 | .driver = { | ||
355 | .name = "hil_kbd", | ||
356 | }, | ||
357 | .description = "HP HIL keyboard driver", | ||
358 | .connect = hil_kbd_connect, | ||
359 | .disconnect = hil_kbd_disconnect, | ||
360 | .interrupt = hil_kbd_interrupt | ||
361 | }; | ||
362 | |||
363 | static int __init hil_kbd_init(void) | ||
364 | { | ||
365 | serio_register_driver(&hil_kbd_serio_drv); | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static void __exit hil_kbd_exit(void) | ||
370 | { | ||
371 | serio_unregister_driver(&hil_kbd_serio_drv); | ||
372 | } | ||
373 | |||
374 | module_init(hil_kbd_init); | ||
375 | module_exit(hil_kbd_exit); | ||
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c new file mode 100644 index 000000000000..eecb77db0847 --- /dev/null +++ b/drivers/input/keyboard/hilkbd.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * linux/drivers/hil/hilkbd.c | ||
3 | * | ||
4 | * Copyright (C) 1998 Philip Blundell <philb@gnu.org> | ||
5 | * Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai> | ||
6 | * Copyright (C) 1999-2003 Helge Deller <deller@gmx.de> | ||
7 | * | ||
8 | * Very basic HP Human Interface Loop (HIL) driver. | ||
9 | * This driver handles the keyboard on HP300 (m68k) and on some | ||
10 | * HP700 (parisc) series machines. | ||
11 | * | ||
12 | * | ||
13 | * This file is subject to the terms and conditions of the GNU General Public | ||
14 | * License version 2. See the file COPYING in the main directory of this | ||
15 | * archive for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/pci_ids.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/hil.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | |||
29 | |||
30 | MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller"); | ||
31 | MODULE_DESCRIPTION("HIL keyboard driver (basic functionality)"); | ||
32 | MODULE_LICENSE("GPL v2"); | ||
33 | |||
34 | |||
35 | #if defined(CONFIG_PARISC) | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | #include <asm/hardware.h> | ||
39 | #include <asm/parisc-device.h> | ||
40 | static unsigned long hil_base; /* HPA for the HIL device */ | ||
41 | static unsigned int hil_irq; | ||
42 | #define HILBASE hil_base /* HPPA (parisc) port address */ | ||
43 | #define HIL_DATA 0x800 | ||
44 | #define HIL_CMD 0x801 | ||
45 | #define HIL_IRQ hil_irq | ||
46 | #define hil_readb(p) gsc_readb(p) | ||
47 | #define hil_writeb(v,p) gsc_writeb((v),(p)) | ||
48 | |||
49 | #elif defined(CONFIG_HP300) | ||
50 | |||
51 | #define HILBASE 0xf0428000 /* HP300 (m86k) port address */ | ||
52 | #define HIL_DATA 0x1 | ||
53 | #define HIL_CMD 0x3 | ||
54 | #define HIL_IRQ 2 | ||
55 | #define hil_readb(p) readb(p) | ||
56 | #define hil_writeb(v,p) writeb((v),(p)) | ||
57 | |||
58 | #else | ||
59 | #error "HIL is not supported on this platform" | ||
60 | #endif | ||
61 | |||
62 | |||
63 | |||
64 | /* HIL helper functions */ | ||
65 | |||
66 | #define hil_busy() (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY) | ||
67 | #define hil_data_available() (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY) | ||
68 | #define hil_status() (hil_readb(HILBASE + HIL_CMD)) | ||
69 | #define hil_command(x) do { hil_writeb((x), HILBASE + HIL_CMD); } while (0) | ||
70 | #define hil_read_data() (hil_readb(HILBASE + HIL_DATA)) | ||
71 | #define hil_write_data(x) do { hil_writeb((x), HILBASE + HIL_DATA); } while (0) | ||
72 | |||
73 | /* HIL constants */ | ||
74 | |||
75 | #define HIL_BUSY 0x02 | ||
76 | #define HIL_DATA_RDY 0x01 | ||
77 | |||
78 | #define HIL_SETARD 0xA0 /* set auto-repeat delay */ | ||
79 | #define HIL_SETARR 0xA2 /* set auto-repeat rate */ | ||
80 | #define HIL_SETTONE 0xA3 /* set tone generator */ | ||
81 | #define HIL_CNMT 0xB2 /* clear nmi */ | ||
82 | #define HIL_INTON 0x5C /* Turn on interrupts. */ | ||
83 | #define HIL_INTOFF 0x5D /* Turn off interrupts. */ | ||
84 | |||
85 | #define HIL_READKBDSADR 0xF9 | ||
86 | #define HIL_WRITEKBDSADR 0xE9 | ||
87 | |||
88 | static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = | ||
89 | { HIL_KEYCODES_SET1 }; | ||
90 | |||
91 | /* HIL structure */ | ||
92 | static struct { | ||
93 | struct input_dev dev; | ||
94 | |||
95 | unsigned int curdev; | ||
96 | |||
97 | unsigned char s; | ||
98 | unsigned char c; | ||
99 | int valid; | ||
100 | |||
101 | unsigned char data[16]; | ||
102 | unsigned int ptr; | ||
103 | spinlock_t lock; | ||
104 | |||
105 | void *dev_id; /* native bus device */ | ||
106 | } hil_dev; | ||
107 | |||
108 | |||
109 | static void poll_finished(void) | ||
110 | { | ||
111 | int down; | ||
112 | int key; | ||
113 | unsigned char scode; | ||
114 | |||
115 | switch (hil_dev.data[0]) { | ||
116 | case 0x40: | ||
117 | down = (hil_dev.data[1] & 1) == 0; | ||
118 | scode = hil_dev.data[1] >> 1; | ||
119 | key = hphilkeyb_keycode[scode]; | ||
120 | input_report_key(&hil_dev.dev, key, down); | ||
121 | break; | ||
122 | } | ||
123 | hil_dev.curdev = 0; | ||
124 | } | ||
125 | |||
126 | static inline void handle_status(unsigned char s, unsigned char c) | ||
127 | { | ||
128 | if (c & 0x8) { | ||
129 | /* End of block */ | ||
130 | if (c & 0x10) | ||
131 | poll_finished(); | ||
132 | } else { | ||
133 | if (c & 0x10) { | ||
134 | if (hil_dev.curdev) | ||
135 | poll_finished(); /* just in case */ | ||
136 | hil_dev.curdev = c & 7; | ||
137 | hil_dev.ptr = 0; | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static inline void handle_data(unsigned char s, unsigned char c) | ||
143 | { | ||
144 | if (hil_dev.curdev) { | ||
145 | hil_dev.data[hil_dev.ptr++] = c; | ||
146 | hil_dev.ptr &= 15; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | |||
151 | /* | ||
152 | * Handle HIL interrupts. | ||
153 | */ | ||
154 | static irqreturn_t hil_interrupt(int irq, void *handle, struct pt_regs *regs) | ||
155 | { | ||
156 | unsigned char s, c; | ||
157 | |||
158 | s = hil_status(); | ||
159 | c = hil_read_data(); | ||
160 | |||
161 | switch (s >> 4) { | ||
162 | case 0x5: | ||
163 | handle_status(s, c); | ||
164 | break; | ||
165 | case 0x6: | ||
166 | handle_data(s, c); | ||
167 | break; | ||
168 | case 0x4: | ||
169 | hil_dev.s = s; | ||
170 | hil_dev.c = c; | ||
171 | mb(); | ||
172 | hil_dev.valid = 1; | ||
173 | break; | ||
174 | } | ||
175 | return IRQ_HANDLED; | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * Send a command to the HIL | ||
180 | */ | ||
181 | |||
182 | static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) | ||
183 | { | ||
184 | unsigned long flags; | ||
185 | |||
186 | spin_lock_irqsave(&hil_dev.lock, flags); | ||
187 | while (hil_busy()) | ||
188 | /* wait */; | ||
189 | hil_command(cmd); | ||
190 | while (len--) { | ||
191 | while (hil_busy()) | ||
192 | /* wait */; | ||
193 | hil_write_data(*(data++)); | ||
194 | } | ||
195 | spin_unlock_irqrestore(&hil_dev.lock, flags); | ||
196 | } | ||
197 | |||
198 | |||
199 | /* | ||
200 | * Initialise HIL. | ||
201 | */ | ||
202 | |||
203 | static int __init | ||
204 | hil_keyb_init(void) | ||
205 | { | ||
206 | unsigned char c; | ||
207 | unsigned int i, kbid; | ||
208 | wait_queue_head_t hil_wait; | ||
209 | |||
210 | if (hil_dev.dev.id.bustype) { | ||
211 | return -ENODEV; /* already initialized */ | ||
212 | } | ||
213 | |||
214 | #if defined(CONFIG_HP300) | ||
215 | if (!hwreg_present((void *)(HILBASE + HIL_DATA))) | ||
216 | return -ENODEV; | ||
217 | |||
218 | request_region(HILBASE+HIL_DATA, 2, "hil"); | ||
219 | #endif | ||
220 | |||
221 | request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id); | ||
222 | |||
223 | /* Turn on interrupts */ | ||
224 | hil_do(HIL_INTON, NULL, 0); | ||
225 | |||
226 | /* Look for keyboards */ | ||
227 | hil_dev.valid = 0; /* clear any pending data */ | ||
228 | hil_do(HIL_READKBDSADR, NULL, 0); | ||
229 | |||
230 | init_waitqueue_head(&hil_wait); | ||
231 | wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ); | ||
232 | if (!hil_dev.valid) { | ||
233 | printk(KERN_WARNING "HIL: timed out, assuming no keyboard present.\n"); | ||
234 | } | ||
235 | |||
236 | c = hil_dev.c; | ||
237 | hil_dev.valid = 0; | ||
238 | if (c == 0) { | ||
239 | kbid = -1; | ||
240 | printk(KERN_WARNING "HIL: no keyboard present.\n"); | ||
241 | } else { | ||
242 | kbid = ffz(~c); | ||
243 | /* printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); */ | ||
244 | } | ||
245 | |||
246 | /* set it to raw mode */ | ||
247 | c = 0; | ||
248 | hil_do(HIL_WRITEKBDSADR, &c, 1); | ||
249 | |||
250 | init_input_dev(&hil_dev.dev); | ||
251 | |||
252 | for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++) | ||
253 | if (hphilkeyb_keycode[i] != KEY_RESERVED) | ||
254 | set_bit(hphilkeyb_keycode[i], hil_dev.dev.keybit); | ||
255 | |||
256 | hil_dev.dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
257 | hil_dev.dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); | ||
258 | hil_dev.dev.keycodemax = HIL_KEYCODES_SET1_TBLSIZE; | ||
259 | hil_dev.dev.keycodesize = sizeof(hphilkeyb_keycode[0]); | ||
260 | hil_dev.dev.keycode = hphilkeyb_keycode; | ||
261 | hil_dev.dev.name = "HIL keyboard"; | ||
262 | hil_dev.dev.phys = "hpkbd/input0"; | ||
263 | |||
264 | hil_dev.dev.id.bustype = BUS_HIL; | ||
265 | hil_dev.dev.id.vendor = PCI_VENDOR_ID_HP; | ||
266 | hil_dev.dev.id.product = 0x0001; | ||
267 | hil_dev.dev.id.version = 0x0010; | ||
268 | |||
269 | input_register_device(&hil_dev.dev); | ||
270 | printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n", | ||
271 | hil_dev.dev.name, kbid, HILBASE, HIL_IRQ); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | #if defined(CONFIG_PARISC) | ||
277 | static int __init | ||
278 | hil_init_chip(struct parisc_device *dev) | ||
279 | { | ||
280 | if (!dev->irq) { | ||
281 | printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa); | ||
282 | return -ENODEV; | ||
283 | } | ||
284 | |||
285 | hil_base = dev->hpa; | ||
286 | hil_irq = dev->irq; | ||
287 | hil_dev.dev_id = dev; | ||
288 | |||
289 | printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq); | ||
290 | |||
291 | return hil_keyb_init(); | ||
292 | } | ||
293 | |||
294 | static struct parisc_device_id hil_tbl[] = { | ||
295 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 }, | ||
296 | { 0, } | ||
297 | }; | ||
298 | |||
299 | MODULE_DEVICE_TABLE(parisc, hil_tbl); | ||
300 | |||
301 | static struct parisc_driver hil_driver = { | ||
302 | .name = "HIL", | ||
303 | .id_table = hil_tbl, | ||
304 | .probe = hil_init_chip, | ||
305 | }; | ||
306 | #endif /* CONFIG_PARISC */ | ||
307 | |||
308 | |||
309 | |||
310 | |||
311 | |||
312 | static int __init hil_init(void) | ||
313 | { | ||
314 | #if defined(CONFIG_PARISC) | ||
315 | return register_parisc_driver(&hil_driver); | ||
316 | #else | ||
317 | return hil_keyb_init(); | ||
318 | #endif | ||
319 | } | ||
320 | |||
321 | |||
322 | static void __exit hil_exit(void) | ||
323 | { | ||
324 | if (HIL_IRQ) { | ||
325 | disable_irq(HIL_IRQ); | ||
326 | free_irq(HIL_IRQ, hil_dev.dev_id); | ||
327 | } | ||
328 | |||
329 | /* Turn off interrupts */ | ||
330 | hil_do(HIL_INTOFF, NULL, 0); | ||
331 | |||
332 | input_unregister_device(&hil_dev.dev); | ||
333 | |||
334 | #if defined(CONFIG_PARISC) | ||
335 | unregister_parisc_driver(&hil_driver); | ||
336 | #else | ||
337 | release_region(HILBASE+HIL_DATA, 2); | ||
338 | #endif | ||
339 | } | ||
340 | |||
341 | module_init(hil_init); | ||
342 | module_exit(hil_exit); | ||
343 | |||
diff --git a/drivers/input/keyboard/hpps2atkbd.h b/drivers/input/keyboard/hpps2atkbd.h new file mode 100644 index 000000000000..dc33f6945222 --- /dev/null +++ b/drivers/input/keyboard/hpps2atkbd.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * drivers/input/keyboard/hpps2atkbd.h | ||
3 | * | ||
4 | * Copyright (c) 2004 Helge Deller <deller@gmx.de> | ||
5 | * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr> | ||
6 | * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org> | ||
7 | * Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr> | ||
8 | * | ||
9 | * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | |||
16 | |||
17 | /* Is the keyboard an RDI PrecisionBook? */ | ||
18 | #ifndef CONFIG_KEYBOARD_ATKBD_RDI_KEYCODES | ||
19 | # define CONFLICT(x,y) x | ||
20 | #else | ||
21 | # define CONFLICT(x,y) y | ||
22 | #endif | ||
23 | |||
24 | /* sadly RDI (Tadpole) decided to ship a different keyboard layout | ||
25 | than HP for their PS/2 laptop keyboard which leads to conflicting | ||
26 | keycodes between a normal HP PS/2 keyboard and a RDI Precisionbook. | ||
27 | HP: RDI: */ | ||
28 | #define C_07 CONFLICT( KEY_F12, KEY_F1 ) | ||
29 | #define C_11 CONFLICT( KEY_LEFTALT, KEY_LEFTCTRL ) | ||
30 | #define C_14 CONFLICT( KEY_LEFTCTRL, KEY_CAPSLOCK ) | ||
31 | #define C_58 CONFLICT( KEY_CAPSLOCK, KEY_RIGHTCTRL ) | ||
32 | #define C_61 CONFLICT( KEY_102ND, KEY_LEFT ) | ||
33 | |||
34 | /* Raw SET 2 scancode table */ | ||
35 | |||
36 | /* 00 */ KEY_RESERVED, KEY_F9, KEY_RESERVED, KEY_F5, KEY_F3, KEY_F1, KEY_F2, C_07, | ||
37 | /* 08 */ KEY_ESC, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KEY_F2, | ||
38 | /* 10 */ KEY_RESERVED, C_11, KEY_LEFTSHIFT, KEY_RESERVED, C_14, KEY_Q, KEY_1, KEY_F3, | ||
39 | /* 18 */ KEY_RESERVED, KEY_LEFTALT, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_F4, | ||
40 | /* 20 */ KEY_RESERVED, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_F5, | ||
41 | /* 28 */ KEY_RESERVED, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_F6, | ||
42 | /* 30 */ KEY_RESERVED, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_F7, | ||
43 | /* 38 */ KEY_RESERVED, KEY_RIGHTALT, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_F8, | ||
44 | /* 40 */ KEY_RESERVED, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_F9, | ||
45 | /* 48 */ KEY_RESERVED, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_F10, | ||
46 | /* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_APOSTROPHE,KEY_RESERVED, KEY_LEFTBRACE, KEY_EQUAL, KEY_F11, KEY_SYSRQ, | ||
47 | /* 58 */ C_58, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12, KEY_SCROLLLOCK, | ||
48 | /* 60 */ KEY_DOWN, C_61, KEY_PAUSE, KEY_UP, KEY_DELETE, KEY_END, KEY_BACKSPACE, KEY_INSERT, | ||
49 | /* 68 */ KEY_RESERVED, KEY_KP1, KEY_RIGHT, KEY_KP4, KEY_KP7, KEY_PAGEDOWN, KEY_HOME, KEY_PAGEUP, | ||
50 | /* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, | ||
51 | /* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_102ND, | ||
52 | /* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
53 | /* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
54 | /* 90 */ KEY_RESERVED, KEY_RIGHTALT, 255, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
55 | /* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_CAPSLOCK, KEY_RESERVED, KEY_LEFTMETA, | ||
56 | /* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTMETA, | ||
57 | /* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_COMPOSE, | ||
58 | /* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
59 | /* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
60 | /* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
61 | /* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPSLASH, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
62 | /* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
63 | /* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPENTER, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
64 | /* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
65 | /* e8 */ KEY_RESERVED, KEY_END, KEY_RESERVED, KEY_LEFT, KEY_HOME, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
66 | /* f0 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_RESERVED, KEY_RIGHT, KEY_UP, KEY_RESERVED, KEY_PAUSE, | ||
67 | /* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_PAGEDOWN, KEY_RESERVED, KEY_SYSRQ, KEY_PAGEUP, KEY_RESERVED, KEY_RESERVED, | ||
68 | |||
69 | /* These are offset for escaped keycodes: */ | ||
70 | |||
71 | /* 00 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_F7, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
72 | /* 08 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
73 | /* 10 */ KEY_RESERVED, KEY_RIGHTALT, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
74 | /* 18 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
75 | /* 20 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
76 | /* 28 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
77 | /* 30 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
78 | /* 38 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
79 | /* 40 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
80 | /* 48 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
81 | /* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
82 | /* 58 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
83 | /* 60 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
84 | /* 68 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
85 | /* 70 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
86 | /* 78 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
87 | /* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
88 | /* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
89 | /* 90 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
90 | /* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
91 | /* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
92 | /* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
93 | /* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
94 | /* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
95 | /* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
96 | /* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
97 | /* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
98 | /* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
99 | /* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
100 | /* e8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
101 | /* f0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
102 | /* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED | ||
103 | |||
104 | #undef CONFLICT | ||
105 | #undef C_07 | ||
106 | #undef C_11 | ||
107 | #undef C_14 | ||
108 | #undef C_58 | ||
109 | #undef C_61 | ||
110 | |||
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c new file mode 100644 index 000000000000..2694ff2b5beb --- /dev/null +++ b/drivers/input/keyboard/lkkbd.c | |||
@@ -0,0 +1,752 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de> | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * LK keyboard driver for Linux, based on sunkbd.c (C) by Vojtech Pavlik | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * DEC LK201 and LK401 keyboard driver for Linux (primary for DECstations | ||
11 | * and VAXstations, but can also be used on any standard RS232 with an | ||
12 | * adaptor). | ||
13 | * | ||
14 | * DISCLAIMER: This works for _me_. If you break anything by using the | ||
15 | * information given below, I will _not_ be liable! | ||
16 | * | ||
17 | * RJ10 pinout: To DE9: Or DB25: | ||
18 | * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD) | ||
19 | * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND) | ||
20 | * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD) | ||
21 | * 3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!! | ||
22 | * | ||
23 | * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For | ||
24 | * RJ10, it's like this: | ||
25 | * | ||
26 | * __=__ Hold the plug in front of you, cable downwards, | ||
27 | * /___/| nose is hidden behind the plug. Now, pin 1 is at | ||
28 | * |1234|| the left side, pin 4 at the right and 2 and 3 are | ||
29 | * |IIII|| in between, of course:) | ||
30 | * | || | ||
31 | * |____|/ | ||
32 | * || So the adaptor consists of three connected cables | ||
33 | * || for data transmission (RxD and TxD) and signal ground. | ||
34 | * Additionally, you have to get +12V from somewhere. | ||
35 | * Most easily, you'll get that from a floppy or HDD power connector. | ||
36 | * It's the yellow cable there (black is ground and red is +5V). | ||
37 | * | ||
38 | * The keyboard and all the commands it understands are documented in | ||
39 | * "VCB02 Video Subsystem - Technical Manual", EK-104AA-TM-001. This | ||
40 | * document is LK201 specific, but LK401 is mostly compatible. It comes | ||
41 | * up in LK201 mode and doesn't report any of the additional keys it | ||
42 | * has. These need to be switched on with the LK_CMD_ENABLE_LK401 | ||
43 | * command. You'll find this document (scanned .pdf file) on MANX, | ||
44 | * a search engine specific to DEC documentation. Try | ||
45 | * http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1 | ||
46 | */ | ||
47 | |||
48 | /* | ||
49 | * This program is free software; you can redistribute it and/or modify | ||
50 | * it under the terms of the GNU General Public License as published by | ||
51 | * the Free Software Foundation; either version 2 of the License, or | ||
52 | * (at your option) any later version. | ||
53 | * | ||
54 | * This program is distributed in the hope that it will be useful, | ||
55 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
56 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
57 | * GNU General Public License for more details. | ||
58 | * | ||
59 | * You should have received a copy of the GNU General Public License | ||
60 | * along with this program; if not, write to the Free Software | ||
61 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
62 | * | ||
63 | * Should you need to contact me, the author, you can do so either by | ||
64 | * email or by paper mail: | ||
65 | * Jan-Benedict Glaw, Lilienstraße 16, 33790 Hörste (near Halle/Westf.), | ||
66 | * Germany. | ||
67 | */ | ||
68 | |||
69 | #include <linux/delay.h> | ||
70 | #include <linux/slab.h> | ||
71 | #include <linux/module.h> | ||
72 | #include <linux/moduleparam.h> | ||
73 | #include <linux/interrupt.h> | ||
74 | #include <linux/init.h> | ||
75 | #include <linux/input.h> | ||
76 | #include <linux/serio.h> | ||
77 | #include <linux/workqueue.h> | ||
78 | |||
79 | #define DRIVER_DESC "LK keyboard driver" | ||
80 | |||
81 | MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); | ||
82 | MODULE_DESCRIPTION (DRIVER_DESC); | ||
83 | MODULE_LICENSE ("GPL"); | ||
84 | |||
85 | /* | ||
86 | * Known parameters: | ||
87 | * bell_volume | ||
88 | * keyclick_volume | ||
89 | * ctrlclick_volume | ||
90 | * | ||
91 | * Please notice that there's not yet an API to set these at runtime. | ||
92 | */ | ||
93 | static int bell_volume = 100; /* % */ | ||
94 | module_param (bell_volume, int, 0); | ||
95 | MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%"); | ||
96 | |||
97 | static int keyclick_volume = 100; /* % */ | ||
98 | module_param (keyclick_volume, int, 0); | ||
99 | MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%"); | ||
100 | |||
101 | static int ctrlclick_volume = 100; /* % */ | ||
102 | module_param (ctrlclick_volume, int, 0); | ||
103 | MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); | ||
104 | |||
105 | static int lk201_compose_is_alt = 0; | ||
106 | module_param (lk201_compose_is_alt, int, 0); | ||
107 | MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " | ||
108 | "will act as an Alt key"); | ||
109 | |||
110 | |||
111 | |||
112 | #undef LKKBD_DEBUG | ||
113 | #ifdef LKKBD_DEBUG | ||
114 | #define DBG(x...) printk (x) | ||
115 | #else | ||
116 | #define DBG(x...) do {} while (0) | ||
117 | #endif | ||
118 | |||
119 | /* LED control */ | ||
120 | #define LK_LED_WAIT 0x81 | ||
121 | #define LK_LED_COMPOSE 0x82 | ||
122 | #define LK_LED_SHIFTLOCK 0x84 | ||
123 | #define LK_LED_SCROLLLOCK 0x88 | ||
124 | #define LK_CMD_LED_ON 0x13 | ||
125 | #define LK_CMD_LED_OFF 0x11 | ||
126 | |||
127 | /* Mode control */ | ||
128 | #define LK_MODE_DOWN 0x80 | ||
129 | #define LK_MODE_AUTODOWN 0x82 | ||
130 | #define LK_MODE_UPDOWN 0x86 | ||
131 | #define LK_CMD_SET_MODE(mode,div) ((mode) | ((div) << 3)) | ||
132 | |||
133 | /* Misc commands */ | ||
134 | #define LK_CMD_ENABLE_KEYCLICK 0x1b | ||
135 | #define LK_CMD_DISABLE_KEYCLICK 0x99 | ||
136 | #define LK_CMD_DISABLE_BELL 0xa1 | ||
137 | #define LK_CMD_SOUND_BELL 0xa7 | ||
138 | #define LK_CMD_ENABLE_BELL 0x23 | ||
139 | #define LK_CMD_DISABLE_CTRCLICK 0xb9 | ||
140 | #define LK_CMD_ENABLE_CTRCLICK 0xbb | ||
141 | #define LK_CMD_SET_DEFAULTS 0xd3 | ||
142 | #define LK_CMD_POWERCYCLE_RESET 0xfd | ||
143 | #define LK_CMD_ENABLE_LK401 0xe9 | ||
144 | #define LK_CMD_REQUEST_ID 0xab | ||
145 | |||
146 | /* Misc responses from keyboard */ | ||
147 | #define LK_STUCK_KEY 0x3d | ||
148 | #define LK_SELFTEST_FAILED 0x3e | ||
149 | #define LK_ALL_KEYS_UP 0xb3 | ||
150 | #define LK_METRONOME 0xb4 | ||
151 | #define LK_OUTPUT_ERROR 0xb5 | ||
152 | #define LK_INPUT_ERROR 0xb6 | ||
153 | #define LK_KBD_LOCKED 0xb7 | ||
154 | #define LK_KBD_TEST_MODE_ACK 0xb8 | ||
155 | #define LK_PREFIX_KEY_DOWN 0xb9 | ||
156 | #define LK_MODE_CHANGE_ACK 0xba | ||
157 | #define LK_RESPONSE_RESERVED 0xbb | ||
158 | |||
159 | #define LK_NUM_KEYCODES 256 | ||
160 | #define LK_NUM_IGNORE_BYTES 6 | ||
161 | typedef u_int16_t lk_keycode_t; | ||
162 | |||
163 | |||
164 | |||
165 | static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { | ||
166 | [0x56] = KEY_F1, | ||
167 | [0x57] = KEY_F2, | ||
168 | [0x58] = KEY_F3, | ||
169 | [0x59] = KEY_F4, | ||
170 | [0x5a] = KEY_F5, | ||
171 | [0x64] = KEY_F6, | ||
172 | [0x65] = KEY_F7, | ||
173 | [0x66] = KEY_F8, | ||
174 | [0x67] = KEY_F9, | ||
175 | [0x68] = KEY_F10, | ||
176 | [0x71] = KEY_F11, | ||
177 | [0x72] = KEY_F12, | ||
178 | [0x73] = KEY_F13, | ||
179 | [0x74] = KEY_F14, | ||
180 | [0x7c] = KEY_F15, | ||
181 | [0x7d] = KEY_F16, | ||
182 | [0x80] = KEY_F17, | ||
183 | [0x81] = KEY_F18, | ||
184 | [0x82] = KEY_F19, | ||
185 | [0x83] = KEY_F20, | ||
186 | [0x8a] = KEY_FIND, | ||
187 | [0x8b] = KEY_INSERT, | ||
188 | [0x8c] = KEY_DELETE, | ||
189 | [0x8d] = KEY_SELECT, | ||
190 | [0x8e] = KEY_PAGEUP, | ||
191 | [0x8f] = KEY_PAGEDOWN, | ||
192 | [0x92] = KEY_KP0, | ||
193 | [0x94] = KEY_KPDOT, | ||
194 | [0x95] = KEY_KPENTER, | ||
195 | [0x96] = KEY_KP1, | ||
196 | [0x97] = KEY_KP2, | ||
197 | [0x98] = KEY_KP3, | ||
198 | [0x99] = KEY_KP4, | ||
199 | [0x9a] = KEY_KP5, | ||
200 | [0x9b] = KEY_KP6, | ||
201 | [0x9c] = KEY_KPCOMMA, | ||
202 | [0x9d] = KEY_KP7, | ||
203 | [0x9e] = KEY_KP8, | ||
204 | [0x9f] = KEY_KP9, | ||
205 | [0xa0] = KEY_KPMINUS, | ||
206 | [0xa1] = KEY_PROG1, | ||
207 | [0xa2] = KEY_PROG2, | ||
208 | [0xa3] = KEY_PROG3, | ||
209 | [0xa4] = KEY_PROG4, | ||
210 | [0xa7] = KEY_LEFT, | ||
211 | [0xa8] = KEY_RIGHT, | ||
212 | [0xa9] = KEY_DOWN, | ||
213 | [0xaa] = KEY_UP, | ||
214 | [0xab] = KEY_RIGHTSHIFT, | ||
215 | [0xac] = KEY_LEFTALT, | ||
216 | [0xad] = KEY_COMPOSE, /* Right Compose, that is. */ | ||
217 | [0xae] = KEY_LEFTSHIFT, /* Same as KEY_RIGHTSHIFT on LK201 */ | ||
218 | [0xaf] = KEY_LEFTCTRL, | ||
219 | [0xb0] = KEY_CAPSLOCK, | ||
220 | [0xb1] = KEY_COMPOSE, /* Left Compose, that is. */ | ||
221 | [0xb2] = KEY_RIGHTALT, | ||
222 | [0xbc] = KEY_BACKSPACE, | ||
223 | [0xbd] = KEY_ENTER, | ||
224 | [0xbe] = KEY_TAB, | ||
225 | [0xbf] = KEY_ESC, | ||
226 | [0xc0] = KEY_1, | ||
227 | [0xc1] = KEY_Q, | ||
228 | [0xc2] = KEY_A, | ||
229 | [0xc3] = KEY_Z, | ||
230 | [0xc5] = KEY_2, | ||
231 | [0xc6] = KEY_W, | ||
232 | [0xc7] = KEY_S, | ||
233 | [0xc8] = KEY_X, | ||
234 | [0xc9] = KEY_102ND, | ||
235 | [0xcb] = KEY_3, | ||
236 | [0xcc] = KEY_E, | ||
237 | [0xcd] = KEY_D, | ||
238 | [0xce] = KEY_C, | ||
239 | [0xd0] = KEY_4, | ||
240 | [0xd1] = KEY_R, | ||
241 | [0xd2] = KEY_F, | ||
242 | [0xd3] = KEY_V, | ||
243 | [0xd4] = KEY_SPACE, | ||
244 | [0xd6] = KEY_5, | ||
245 | [0xd7] = KEY_T, | ||
246 | [0xd8] = KEY_G, | ||
247 | [0xd9] = KEY_B, | ||
248 | [0xdb] = KEY_6, | ||
249 | [0xdc] = KEY_Y, | ||
250 | [0xdd] = KEY_H, | ||
251 | [0xde] = KEY_N, | ||
252 | [0xe0] = KEY_7, | ||
253 | [0xe1] = KEY_U, | ||
254 | [0xe2] = KEY_J, | ||
255 | [0xe3] = KEY_M, | ||
256 | [0xe5] = KEY_8, | ||
257 | [0xe6] = KEY_I, | ||
258 | [0xe7] = KEY_K, | ||
259 | [0xe8] = KEY_COMMA, | ||
260 | [0xea] = KEY_9, | ||
261 | [0xeb] = KEY_O, | ||
262 | [0xec] = KEY_L, | ||
263 | [0xed] = KEY_DOT, | ||
264 | [0xef] = KEY_0, | ||
265 | [0xf0] = KEY_P, | ||
266 | [0xf2] = KEY_SEMICOLON, | ||
267 | [0xf3] = KEY_SLASH, | ||
268 | [0xf5] = KEY_EQUAL, | ||
269 | [0xf6] = KEY_RIGHTBRACE, | ||
270 | [0xf7] = KEY_BACKSLASH, | ||
271 | [0xf9] = KEY_MINUS, | ||
272 | [0xfa] = KEY_LEFTBRACE, | ||
273 | [0xfb] = KEY_APOSTROPHE, | ||
274 | }; | ||
275 | |||
276 | #define CHECK_LED(LED, BITS) do { \ | ||
277 | if (test_bit (LED, lk->dev.led)) \ | ||
278 | leds_on |= BITS; \ | ||
279 | else \ | ||
280 | leds_off |= BITS; \ | ||
281 | } while (0) | ||
282 | |||
283 | /* | ||
284 | * Per-keyboard data | ||
285 | */ | ||
286 | struct lkkbd { | ||
287 | lk_keycode_t keycode[LK_NUM_KEYCODES]; | ||
288 | int ignore_bytes; | ||
289 | unsigned char id[LK_NUM_IGNORE_BYTES]; | ||
290 | struct input_dev dev; | ||
291 | struct serio *serio; | ||
292 | struct work_struct tq; | ||
293 | char name[64]; | ||
294 | char phys[32]; | ||
295 | char type; | ||
296 | int bell_volume; | ||
297 | int keyclick_volume; | ||
298 | int ctrlclick_volume; | ||
299 | }; | ||
300 | |||
301 | /* | ||
302 | * Calculate volume parameter byte for a given volume. | ||
303 | */ | ||
304 | static unsigned char | ||
305 | volume_to_hw (int volume_percent) | ||
306 | { | ||
307 | unsigned char ret = 0; | ||
308 | |||
309 | if (volume_percent < 0) | ||
310 | volume_percent = 0; | ||
311 | if (volume_percent > 100) | ||
312 | volume_percent = 100; | ||
313 | |||
314 | if (volume_percent >= 0) | ||
315 | ret = 7; | ||
316 | if (volume_percent >= 13) /* 12.5 */ | ||
317 | ret = 6; | ||
318 | if (volume_percent >= 25) | ||
319 | ret = 5; | ||
320 | if (volume_percent >= 38) /* 37.5 */ | ||
321 | ret = 4; | ||
322 | if (volume_percent >= 50) | ||
323 | ret = 3; | ||
324 | if (volume_percent >= 63) /* 62.5 */ | ||
325 | ret = 2; /* This is the default volume */ | ||
326 | if (volume_percent >= 75) | ||
327 | ret = 1; | ||
328 | if (volume_percent >= 88) /* 87.5 */ | ||
329 | ret = 0; | ||
330 | |||
331 | ret |= 0x80; | ||
332 | |||
333 | return ret; | ||
334 | } | ||
335 | |||
336 | static void | ||
337 | lkkbd_detection_done (struct lkkbd *lk) | ||
338 | { | ||
339 | int i; | ||
340 | |||
341 | /* | ||
342 | * Reset setting for Compose key. Let Compose be KEY_COMPOSE. | ||
343 | */ | ||
344 | lk->keycode[0xb1] = KEY_COMPOSE; | ||
345 | |||
346 | /* | ||
347 | * Print keyboard name and modify Compose=Alt on user's request. | ||
348 | */ | ||
349 | switch (lk->id[4]) { | ||
350 | case 1: | ||
351 | sprintf (lk->name, "DEC LK201 keyboard"); | ||
352 | |||
353 | if (lk201_compose_is_alt) | ||
354 | lk->keycode[0xb1] = KEY_LEFTALT; | ||
355 | break; | ||
356 | |||
357 | case 2: | ||
358 | sprintf (lk->name, "DEC LK401 keyboard"); | ||
359 | break; | ||
360 | |||
361 | default: | ||
362 | sprintf (lk->name, "Unknown DEC keyboard"); | ||
363 | printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " | ||
364 | "please report to Jan-Benedict Glaw " | ||
365 | "<jbglaw@lug-owl.de>\n", lk->phys); | ||
366 | printk (KERN_ERR "lkkbd: keyboard ID'ed as:"); | ||
367 | for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) | ||
368 | printk (" 0x%02x", lk->id[i]); | ||
369 | printk ("\n"); | ||
370 | break; | ||
371 | } | ||
372 | printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n", | ||
373 | lk->phys, lk->name); | ||
374 | |||
375 | /* | ||
376 | * Report errors during keyboard boot-up. | ||
377 | */ | ||
378 | switch (lk->id[2]) { | ||
379 | case 0x00: | ||
380 | /* All okay */ | ||
381 | break; | ||
382 | |||
383 | case LK_STUCK_KEY: | ||
384 | printk (KERN_ERR "lkkbd: Stuck key on keyboard at " | ||
385 | "%s\n", lk->phys); | ||
386 | break; | ||
387 | |||
388 | case LK_SELFTEST_FAILED: | ||
389 | printk (KERN_ERR "lkkbd: Selftest failed on keyboard " | ||
390 | "at %s, keyboard may not work " | ||
391 | "properly\n", lk->phys); | ||
392 | break; | ||
393 | |||
394 | default: | ||
395 | printk (KERN_ERR "lkkbd: Unknown error %02x on " | ||
396 | "keyboard at %s\n", lk->id[2], | ||
397 | lk->phys); | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Try to hint user if there's a stuck key. | ||
403 | */ | ||
404 | if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0) | ||
405 | printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode " | ||
406 | "is 0x%04x\n", lk->id[3], | ||
407 | lk->keycode[lk->id[3]]); | ||
408 | |||
409 | return; | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * lkkbd_interrupt() is called by the low level driver when a character | ||
414 | * is received. | ||
415 | */ | ||
416 | static irqreturn_t | ||
417 | lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, | ||
418 | struct pt_regs *regs) | ||
419 | { | ||
420 | struct lkkbd *lk = serio_get_drvdata (serio); | ||
421 | int i; | ||
422 | |||
423 | DBG (KERN_INFO "Got byte 0x%02x\n", data); | ||
424 | |||
425 | if (lk->ignore_bytes > 0) { | ||
426 | DBG (KERN_INFO "Ignoring a byte on %s\n", | ||
427 | lk->name); | ||
428 | lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; | ||
429 | |||
430 | if (lk->ignore_bytes == 0) | ||
431 | lkkbd_detection_done (lk); | ||
432 | |||
433 | return IRQ_HANDLED; | ||
434 | } | ||
435 | |||
436 | switch (data) { | ||
437 | case LK_ALL_KEYS_UP: | ||
438 | input_regs (&lk->dev, regs); | ||
439 | for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) | ||
440 | if (lk->keycode[i] != KEY_RESERVED) | ||
441 | input_report_key (&lk->dev, lk->keycode[i], 0); | ||
442 | input_sync (&lk->dev); | ||
443 | break; | ||
444 | case LK_METRONOME: | ||
445 | DBG (KERN_INFO "Got LK_METRONOME and don't " | ||
446 | "know how to handle...\n"); | ||
447 | break; | ||
448 | case LK_OUTPUT_ERROR: | ||
449 | DBG (KERN_INFO "Got LK_OUTPUT_ERROR and don't " | ||
450 | "know how to handle...\n"); | ||
451 | break; | ||
452 | case LK_INPUT_ERROR: | ||
453 | DBG (KERN_INFO "Got LK_INPUT_ERROR and don't " | ||
454 | "know how to handle...\n"); | ||
455 | break; | ||
456 | case LK_KBD_LOCKED: | ||
457 | DBG (KERN_INFO "Got LK_KBD_LOCKED and don't " | ||
458 | "know how to handle...\n"); | ||
459 | break; | ||
460 | case LK_KBD_TEST_MODE_ACK: | ||
461 | DBG (KERN_INFO "Got LK_KBD_TEST_MODE_ACK and don't " | ||
462 | "know how to handle...\n"); | ||
463 | break; | ||
464 | case LK_PREFIX_KEY_DOWN: | ||
465 | DBG (KERN_INFO "Got LK_PREFIX_KEY_DOWN and don't " | ||
466 | "know how to handle...\n"); | ||
467 | break; | ||
468 | case LK_MODE_CHANGE_ACK: | ||
469 | DBG (KERN_INFO "Got LK_MODE_CHANGE_ACK and ignored " | ||
470 | "it properly...\n"); | ||
471 | break; | ||
472 | case LK_RESPONSE_RESERVED: | ||
473 | DBG (KERN_INFO "Got LK_RESPONSE_RESERVED and don't " | ||
474 | "know how to handle...\n"); | ||
475 | break; | ||
476 | case 0x01: | ||
477 | DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); | ||
478 | lk->ignore_bytes = LK_NUM_IGNORE_BYTES; | ||
479 | lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; | ||
480 | schedule_work (&lk->tq); | ||
481 | break; | ||
482 | |||
483 | default: | ||
484 | if (lk->keycode[data] != KEY_RESERVED) { | ||
485 | input_regs (&lk->dev, regs); | ||
486 | if (!test_bit (lk->keycode[data], lk->dev.key)) | ||
487 | input_report_key (&lk->dev, lk->keycode[data], 1); | ||
488 | else | ||
489 | input_report_key (&lk->dev, lk->keycode[data], 0); | ||
490 | input_sync (&lk->dev); | ||
491 | } else | ||
492 | printk (KERN_WARNING "%s: Unknown key with " | ||
493 | "scancode 0x%02x on %s.\n", | ||
494 | __FILE__, data, lk->name); | ||
495 | } | ||
496 | |||
497 | return IRQ_HANDLED; | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * lkkbd_event() handles events from the input module. | ||
502 | */ | ||
503 | static int | ||
504 | lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, | ||
505 | int value) | ||
506 | { | ||
507 | struct lkkbd *lk = dev->private; | ||
508 | unsigned char leds_on = 0; | ||
509 | unsigned char leds_off = 0; | ||
510 | |||
511 | switch (type) { | ||
512 | case EV_LED: | ||
513 | CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); | ||
514 | CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); | ||
515 | CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); | ||
516 | CHECK_LED (LED_SLEEP, LK_LED_WAIT); | ||
517 | if (leds_on != 0) { | ||
518 | lk->serio->write (lk->serio, LK_CMD_LED_ON); | ||
519 | lk->serio->write (lk->serio, leds_on); | ||
520 | } | ||
521 | if (leds_off != 0) { | ||
522 | lk->serio->write (lk->serio, LK_CMD_LED_OFF); | ||
523 | lk->serio->write (lk->serio, leds_off); | ||
524 | } | ||
525 | return 0; | ||
526 | |||
527 | case EV_SND: | ||
528 | switch (code) { | ||
529 | case SND_CLICK: | ||
530 | if (value == 0) { | ||
531 | DBG ("%s: Deactivating key clicks\n", __FUNCTION__); | ||
532 | lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); | ||
533 | lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); | ||
534 | } else { | ||
535 | DBG ("%s: Activating key clicks\n", __FUNCTION__); | ||
536 | lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); | ||
537 | lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); | ||
538 | lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); | ||
539 | lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); | ||
540 | } | ||
541 | return 0; | ||
542 | |||
543 | case SND_BELL: | ||
544 | if (value != 0) | ||
545 | lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | break; | ||
550 | |||
551 | default: | ||
552 | printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n", | ||
553 | __FUNCTION__, type, code, value); | ||
554 | } | ||
555 | |||
556 | return -1; | ||
557 | } | ||
558 | |||
559 | /* | ||
560 | * lkkbd_reinit() sets leds and beeps to a state the computer remembers they | ||
561 | * were in. | ||
562 | */ | ||
563 | static void | ||
564 | lkkbd_reinit (void *data) | ||
565 | { | ||
566 | struct lkkbd *lk = data; | ||
567 | int division; | ||
568 | unsigned char leds_on = 0; | ||
569 | unsigned char leds_off = 0; | ||
570 | |||
571 | /* Ask for ID */ | ||
572 | lk->serio->write (lk->serio, LK_CMD_REQUEST_ID); | ||
573 | |||
574 | /* Reset parameters */ | ||
575 | lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); | ||
576 | |||
577 | /* Set LEDs */ | ||
578 | CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); | ||
579 | CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); | ||
580 | CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); | ||
581 | CHECK_LED (LED_SLEEP, LK_LED_WAIT); | ||
582 | if (leds_on != 0) { | ||
583 | lk->serio->write (lk->serio, LK_CMD_LED_ON); | ||
584 | lk->serio->write (lk->serio, leds_on); | ||
585 | } | ||
586 | if (leds_off != 0) { | ||
587 | lk->serio->write (lk->serio, LK_CMD_LED_OFF); | ||
588 | lk->serio->write (lk->serio, leds_off); | ||
589 | } | ||
590 | |||
591 | /* | ||
592 | * Try to activate extended LK401 mode. This command will | ||
593 | * only work with a LK401 keyboard and grants access to | ||
594 | * LAlt, RAlt, RCompose and RShift. | ||
595 | */ | ||
596 | lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401); | ||
597 | |||
598 | /* Set all keys to UPDOWN mode */ | ||
599 | for (division = 1; division <= 14; division++) | ||
600 | lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, | ||
601 | division)); | ||
602 | |||
603 | /* Enable bell and set volume */ | ||
604 | lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL); | ||
605 | lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume)); | ||
606 | |||
607 | /* Enable/disable keyclick (and possibly set volume) */ | ||
608 | if (test_bit (SND_CLICK, lk->dev.snd)) { | ||
609 | lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); | ||
610 | lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); | ||
611 | lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); | ||
612 | lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); | ||
613 | } else { | ||
614 | lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); | ||
615 | lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); | ||
616 | } | ||
617 | |||
618 | /* Sound the bell if needed */ | ||
619 | if (test_bit (SND_BELL, lk->dev.snd)) | ||
620 | lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); | ||
621 | } | ||
622 | |||
623 | /* | ||
624 | * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. | ||
625 | */ | ||
626 | static int | ||
627 | lkkbd_connect (struct serio *serio, struct serio_driver *drv) | ||
628 | { | ||
629 | struct lkkbd *lk; | ||
630 | int i; | ||
631 | int err; | ||
632 | |||
633 | if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL))) | ||
634 | return -ENOMEM; | ||
635 | |||
636 | memset (lk, 0, sizeof (struct lkkbd)); | ||
637 | |||
638 | init_input_dev (&lk->dev); | ||
639 | set_bit (EV_KEY, lk->dev.evbit); | ||
640 | set_bit (EV_LED, lk->dev.evbit); | ||
641 | set_bit (EV_SND, lk->dev.evbit); | ||
642 | set_bit (EV_REP, lk->dev.evbit); | ||
643 | set_bit (LED_CAPSL, lk->dev.ledbit); | ||
644 | set_bit (LED_SLEEP, lk->dev.ledbit); | ||
645 | set_bit (LED_COMPOSE, lk->dev.ledbit); | ||
646 | set_bit (LED_SCROLLL, lk->dev.ledbit); | ||
647 | set_bit (SND_BELL, lk->dev.sndbit); | ||
648 | set_bit (SND_CLICK, lk->dev.sndbit); | ||
649 | |||
650 | lk->serio = serio; | ||
651 | |||
652 | INIT_WORK (&lk->tq, lkkbd_reinit, lk); | ||
653 | |||
654 | lk->bell_volume = bell_volume; | ||
655 | lk->keyclick_volume = keyclick_volume; | ||
656 | lk->ctrlclick_volume = ctrlclick_volume; | ||
657 | |||
658 | lk->dev.keycode = lk->keycode; | ||
659 | lk->dev.keycodesize = sizeof (lk_keycode_t); | ||
660 | lk->dev.keycodemax = LK_NUM_KEYCODES; | ||
661 | |||
662 | lk->dev.event = lkkbd_event; | ||
663 | lk->dev.private = lk; | ||
664 | |||
665 | serio_set_drvdata (serio, lk); | ||
666 | |||
667 | err = serio_open (serio, drv); | ||
668 | if (err) { | ||
669 | serio_set_drvdata (serio, NULL); | ||
670 | kfree (lk); | ||
671 | return err; | ||
672 | } | ||
673 | |||
674 | sprintf (lk->name, "DEC LK keyboard"); | ||
675 | sprintf (lk->phys, "%s/input0", serio->phys); | ||
676 | |||
677 | memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); | ||
678 | for (i = 0; i < LK_NUM_KEYCODES; i++) | ||
679 | set_bit (lk->keycode[i], lk->dev.keybit); | ||
680 | |||
681 | lk->dev.name = lk->name; | ||
682 | lk->dev.phys = lk->phys; | ||
683 | lk->dev.id.bustype = BUS_RS232; | ||
684 | lk->dev.id.vendor = SERIO_LKKBD; | ||
685 | lk->dev.id.product = 0; | ||
686 | lk->dev.id.version = 0x0100; | ||
687 | lk->dev.dev = &serio->dev; | ||
688 | |||
689 | input_register_device (&lk->dev); | ||
690 | |||
691 | printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys); | ||
692 | lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET); | ||
693 | |||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /* | ||
698 | * lkkbd_disconnect() unregisters and closes behind us. | ||
699 | */ | ||
700 | static void | ||
701 | lkkbd_disconnect (struct serio *serio) | ||
702 | { | ||
703 | struct lkkbd *lk = serio_get_drvdata (serio); | ||
704 | |||
705 | input_unregister_device (&lk->dev); | ||
706 | serio_close (serio); | ||
707 | serio_set_drvdata (serio, NULL); | ||
708 | kfree (lk); | ||
709 | } | ||
710 | |||
711 | static struct serio_device_id lkkbd_serio_ids[] = { | ||
712 | { | ||
713 | .type = SERIO_RS232, | ||
714 | .proto = SERIO_LKKBD, | ||
715 | .id = SERIO_ANY, | ||
716 | .extra = SERIO_ANY, | ||
717 | }, | ||
718 | { 0 } | ||
719 | }; | ||
720 | |||
721 | MODULE_DEVICE_TABLE(serio, lkkbd_serio_ids); | ||
722 | |||
723 | static struct serio_driver lkkbd_drv = { | ||
724 | .driver = { | ||
725 | .name = "lkkbd", | ||
726 | }, | ||
727 | .description = DRIVER_DESC, | ||
728 | .id_table = lkkbd_serio_ids, | ||
729 | .connect = lkkbd_connect, | ||
730 | .disconnect = lkkbd_disconnect, | ||
731 | .interrupt = lkkbd_interrupt, | ||
732 | }; | ||
733 | |||
734 | /* | ||
735 | * The functions for insering/removing us as a module. | ||
736 | */ | ||
737 | static int __init | ||
738 | lkkbd_init (void) | ||
739 | { | ||
740 | serio_register_driver(&lkkbd_drv); | ||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | static void __exit | ||
745 | lkkbd_exit (void) | ||
746 | { | ||
747 | serio_unregister_driver(&lkkbd_drv); | ||
748 | } | ||
749 | |||
750 | module_init (lkkbd_init); | ||
751 | module_exit (lkkbd_exit); | ||
752 | |||
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c new file mode 100644 index 000000000000..d3e9dd6a13cd --- /dev/null +++ b/drivers/input/keyboard/locomokbd.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 John Lenz | ||
3 | * | ||
4 | * Based on from xtkbd.c | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * LoCoMo keyboard driver for Linux/ARM | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/config.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/input.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include <linux/device.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/ioport.h> | ||
37 | |||
38 | #include <asm/hardware/locomo.h> | ||
39 | #include <asm/irq.h> | ||
40 | |||
41 | MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); | ||
42 | MODULE_DESCRIPTION("LoCoMo keyboard driver"); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | #define LOCOMOKBD_NUMKEYS 128 | ||
46 | |||
47 | #define KEY_ACTIVITY KEY_F16 | ||
48 | #define KEY_CONTACT KEY_F18 | ||
49 | #define KEY_CENTER KEY_F15 | ||
50 | |||
51 | static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { | ||
52 | 0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0, /* 0 - 9 */ | ||
53 | 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT, /* 10 - 19 */ | ||
54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 29 */ | ||
55 | 0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0, /* 30 - 39 */ | ||
56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT, /* 40 - 49 */ | ||
57 | KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T, /* 50 - 59 */ | ||
58 | KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0, /* 60 - 69 */ | ||
59 | KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0, /* 70 - 79 */ | ||
60 | 0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J, /* 80 - 89 */ | ||
61 | KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0, /* 90 - 99 */ | ||
62 | 0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A, /* 100 - 109 */ | ||
63 | KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0, /* 110 - 119 */ | ||
64 | KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */ | ||
65 | }; | ||
66 | |||
67 | #define KB_ROWS 16 | ||
68 | #define KB_COLS 8 | ||
69 | #define KB_ROWMASK(r) (1 << (r)) | ||
70 | #define SCANCODE(c,r) ( ((c)<<4) + (r) + 1 ) | ||
71 | #define NR_SCANCODES 128 | ||
72 | |||
73 | #define KB_DELAY 8 | ||
74 | #define SCAN_INTERVAL (HZ/10) | ||
75 | #define LOCOMOKBD_PRESSED 1 | ||
76 | |||
77 | struct locomokbd { | ||
78 | unsigned char keycode[LOCOMOKBD_NUMKEYS]; | ||
79 | struct input_dev input; | ||
80 | char phys[32]; | ||
81 | |||
82 | struct locomo_dev *ldev; | ||
83 | unsigned long base; | ||
84 | spinlock_t lock; | ||
85 | |||
86 | struct timer_list timer; | ||
87 | }; | ||
88 | |||
89 | /* helper functions for reading the keyboard matrix */ | ||
90 | static inline void locomokbd_charge_all(unsigned long membase) | ||
91 | { | ||
92 | locomo_writel(0x00FF, membase + LOCOMO_KSC); | ||
93 | } | ||
94 | |||
95 | static inline void locomokbd_activate_all(unsigned long membase) | ||
96 | { | ||
97 | unsigned long r; | ||
98 | |||
99 | locomo_writel(0, membase + LOCOMO_KSC); | ||
100 | r = locomo_readl(membase + LOCOMO_KIC); | ||
101 | r &= 0xFEFF; | ||
102 | locomo_writel(r, membase + LOCOMO_KIC); | ||
103 | } | ||
104 | |||
105 | static inline void locomokbd_activate_col(unsigned long membase, int col) | ||
106 | { | ||
107 | unsigned short nset; | ||
108 | unsigned short nbset; | ||
109 | |||
110 | nset = 0xFF & ~(1 << col); | ||
111 | nbset = (nset << 8) + nset; | ||
112 | locomo_writel(nbset, membase + LOCOMO_KSC); | ||
113 | } | ||
114 | |||
115 | static inline void locomokbd_reset_col(unsigned long membase, int col) | ||
116 | { | ||
117 | unsigned short nbset; | ||
118 | |||
119 | nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF; | ||
120 | locomo_writel(nbset, membase + LOCOMO_KSC); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * The LoCoMo keyboard only generates interrupts when a key is pressed. | ||
125 | * So when a key is pressed, we enable a timer. This timer scans the | ||
126 | * keyboard, and this is how we detect when the key is released. | ||
127 | */ | ||
128 | |||
129 | /* Scan the hardware keyboard and push any changes up through the input layer */ | ||
130 | static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs) | ||
131 | { | ||
132 | unsigned int row, col, rowd, scancode; | ||
133 | unsigned long flags; | ||
134 | unsigned int num_pressed; | ||
135 | unsigned long membase = locomokbd->base; | ||
136 | |||
137 | spin_lock_irqsave(&locomokbd->lock, flags); | ||
138 | |||
139 | if (regs) | ||
140 | input_regs(&locomokbd->input, regs); | ||
141 | |||
142 | locomokbd_charge_all(membase); | ||
143 | |||
144 | num_pressed = 0; | ||
145 | for (col = 0; col < KB_COLS; col++) { | ||
146 | |||
147 | locomokbd_activate_col(membase, col); | ||
148 | udelay(KB_DELAY); | ||
149 | |||
150 | rowd = ~locomo_readl(membase + LOCOMO_KIB); | ||
151 | for (row = 0; row < KB_ROWS; row++ ) { | ||
152 | scancode = SCANCODE(col, row); | ||
153 | if (rowd & KB_ROWMASK(row)) { | ||
154 | num_pressed += 1; | ||
155 | input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 1); | ||
156 | } else { | ||
157 | input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 0); | ||
158 | } | ||
159 | } | ||
160 | locomokbd_reset_col(membase, col); | ||
161 | } | ||
162 | locomokbd_activate_all(membase); | ||
163 | |||
164 | input_sync(&locomokbd->input); | ||
165 | |||
166 | /* if any keys are pressed, enable the timer */ | ||
167 | if (num_pressed) | ||
168 | mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL); | ||
169 | |||
170 | spin_unlock_irqrestore(&locomokbd->lock, flags); | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * LoCoMo keyboard interrupt handler. | ||
175 | */ | ||
176 | static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
177 | { | ||
178 | struct locomokbd *locomokbd = dev_id; | ||
179 | /** wait chattering delay **/ | ||
180 | udelay(100); | ||
181 | |||
182 | locomokbd_scankeyboard(locomokbd, regs); | ||
183 | |||
184 | return IRQ_HANDLED; | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * LoCoMo timer checking for released keys | ||
189 | */ | ||
190 | static void locomokbd_timer_callback(unsigned long data) | ||
191 | { | ||
192 | struct locomokbd *locomokbd = (struct locomokbd *) data; | ||
193 | locomokbd_scankeyboard(locomokbd, NULL); | ||
194 | } | ||
195 | |||
196 | static int locomokbd_probe(struct locomo_dev *dev) | ||
197 | { | ||
198 | struct locomokbd *locomokbd; | ||
199 | int i, ret; | ||
200 | |||
201 | locomokbd = kmalloc(sizeof(struct locomokbd), GFP_KERNEL); | ||
202 | if (!locomokbd) | ||
203 | return -ENOMEM; | ||
204 | |||
205 | memset(locomokbd, 0, sizeof(struct locomokbd)); | ||
206 | |||
207 | /* try and claim memory region */ | ||
208 | if (!request_mem_region((unsigned long) dev->mapbase, | ||
209 | dev->length, | ||
210 | LOCOMO_DRIVER_NAME(dev))) { | ||
211 | ret = -EBUSY; | ||
212 | printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n"); | ||
213 | goto free; | ||
214 | } | ||
215 | |||
216 | locomokbd->ldev = dev; | ||
217 | locomo_set_drvdata(dev, locomokbd); | ||
218 | |||
219 | locomokbd->base = (unsigned long) dev->mapbase; | ||
220 | |||
221 | spin_lock_init(&locomokbd->lock); | ||
222 | |||
223 | init_timer(&locomokbd->timer); | ||
224 | locomokbd->timer.function = locomokbd_timer_callback; | ||
225 | locomokbd->timer.data = (unsigned long) locomokbd; | ||
226 | |||
227 | locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
228 | |||
229 | init_input_dev(&locomokbd->input); | ||
230 | locomokbd->input.keycode = locomokbd->keycode; | ||
231 | locomokbd->input.keycodesize = sizeof(unsigned char); | ||
232 | locomokbd->input.keycodemax = ARRAY_SIZE(locomokbd_keycode); | ||
233 | locomokbd->input.private = locomokbd; | ||
234 | |||
235 | memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode)); | ||
236 | for (i = 0; i < LOCOMOKBD_NUMKEYS; i++) | ||
237 | set_bit(locomokbd->keycode[i], locomokbd->input.keybit); | ||
238 | clear_bit(0, locomokbd->input.keybit); | ||
239 | |||
240 | strcpy(locomokbd->phys, "locomokbd/input0"); | ||
241 | |||
242 | locomokbd->input.name = "LoCoMo keyboard"; | ||
243 | locomokbd->input.phys = locomokbd->phys; | ||
244 | locomokbd->input.id.bustype = BUS_XTKBD; | ||
245 | locomokbd->input.id.vendor = 0x0001; | ||
246 | locomokbd->input.id.product = 0x0001; | ||
247 | locomokbd->input.id.version = 0x0100; | ||
248 | |||
249 | /* attempt to get the interrupt */ | ||
250 | ret = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd); | ||
251 | if (ret) { | ||
252 | printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n"); | ||
253 | goto out; | ||
254 | } | ||
255 | |||
256 | input_register_device(&locomokbd->input); | ||
257 | |||
258 | printk(KERN_INFO "input: LoCoMo keyboard on locomokbd\n"); | ||
259 | |||
260 | return 0; | ||
261 | |||
262 | out: | ||
263 | release_mem_region((unsigned long) dev->mapbase, dev->length); | ||
264 | locomo_set_drvdata(dev, NULL); | ||
265 | free: | ||
266 | kfree(locomokbd); | ||
267 | |||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | static int locomokbd_remove(struct locomo_dev *dev) | ||
272 | { | ||
273 | struct locomokbd *locomokbd = locomo_get_drvdata(dev); | ||
274 | |||
275 | free_irq(dev->irq[0], locomokbd); | ||
276 | |||
277 | del_timer_sync(&locomokbd->timer); | ||
278 | |||
279 | input_unregister_device(&locomokbd->input); | ||
280 | locomo_set_drvdata(dev, NULL); | ||
281 | |||
282 | release_mem_region((unsigned long) dev->mapbase, dev->length); | ||
283 | |||
284 | kfree(locomokbd); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static struct locomo_driver keyboard_driver = { | ||
290 | .drv = { | ||
291 | .name = "locomokbd" | ||
292 | }, | ||
293 | .devid = LOCOMO_DEVID_KEYBOARD, | ||
294 | .probe = locomokbd_probe, | ||
295 | .remove = locomokbd_remove, | ||
296 | }; | ||
297 | |||
298 | static int __init locomokbd_init(void) | ||
299 | { | ||
300 | return locomo_driver_register(&keyboard_driver); | ||
301 | } | ||
302 | |||
303 | static void __exit locomokbd_exit(void) | ||
304 | { | ||
305 | locomo_driver_unregister(&keyboard_driver); | ||
306 | } | ||
307 | |||
308 | module_init(locomokbd_init); | ||
309 | module_exit(locomokbd_exit); | ||
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c new file mode 100644 index 000000000000..859ed771ee0a --- /dev/null +++ b/drivers/input/keyboard/maple_keyb.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $ | ||
3 | * SEGA Dreamcast keyboard driver | ||
4 | * Based on drivers/usb/usbkbd.c | ||
5 | */ | ||
6 | |||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/slab.h> | ||
9 | #include <linux/input.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/timer.h> | ||
13 | #include <linux/maple.h> | ||
14 | |||
15 | MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>"); | ||
16 | MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); | ||
17 | MODULE_LICENSE("GPL"); | ||
18 | |||
19 | static unsigned char dc_kbd_keycode[256] = { | ||
20 | 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, | ||
21 | 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, | ||
22 | 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, | ||
23 | 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, | ||
24 | 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, | ||
25 | 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, | ||
26 | 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, | ||
27 | 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, | ||
28 | 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, | ||
29 | 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
31 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
32 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
33 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
34 | 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, | ||
35 | 150,158,159,128,136,177,178,176,142,152,173,140 | ||
36 | }; | ||
37 | |||
38 | |||
39 | struct dc_kbd { | ||
40 | struct input_dev dev; | ||
41 | unsigned char new[8]; | ||
42 | unsigned char old[8]; | ||
43 | int open; | ||
44 | }; | ||
45 | |||
46 | |||
47 | static void dc_scan_kbd(struct dc_kbd *kbd) | ||
48 | { | ||
49 | int i; | ||
50 | struct input_dev *dev = &kbd->dev; | ||
51 | |||
52 | for(i=0; i<8; i++) | ||
53 | input_report_key(dev, | ||
54 | dc_kbd_keycode[i+224], | ||
55 | (kbd->new[0]>>i)&1); | ||
56 | |||
57 | for(i=2; i<8; i++) { | ||
58 | |||
59 | if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) { | ||
60 | if(dc_kbd_keycode[kbd->old[i]]) | ||
61 | input_report_key(dev, | ||
62 | dc_kbd_keycode[kbd->old[i]], | ||
63 | 0); | ||
64 | else | ||
65 | printk("Unknown key (scancode %#x) released.", | ||
66 | kbd->old[i]); | ||
67 | } | ||
68 | |||
69 | if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) { | ||
70 | if(dc_kbd_keycode[kbd->new[i]]) | ||
71 | input_report_key(dev, | ||
72 | dc_kbd_keycode[kbd->new[i]], | ||
73 | 1); | ||
74 | else | ||
75 | printk("Unknown key (scancode %#x) pressed.", | ||
76 | kbd->new[i]); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | input_sync(dev); | ||
81 | |||
82 | memcpy(kbd->old, kbd->new, 8); | ||
83 | } | ||
84 | |||
85 | |||
86 | static void dc_kbd_callback(struct mapleq *mq) | ||
87 | { | ||
88 | struct maple_device *mapledev = mq->dev; | ||
89 | struct dc_kbd *kbd = mapledev->private_data; | ||
90 | unsigned long *buf = mq->recvbuf; | ||
91 | |||
92 | if (buf[1] == mapledev->function) { | ||
93 | memcpy(kbd->new, buf+2, 8); | ||
94 | dc_scan_kbd(kbd); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | |||
99 | static int dc_kbd_open(struct input_dev *dev) | ||
100 | { | ||
101 | struct dc_kbd *kbd = dev->private; | ||
102 | kbd->open++; | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | |||
107 | static void dc_kbd_close(struct input_dev *dev) | ||
108 | { | ||
109 | struct dc_kbd *kbd = dev->private; | ||
110 | kbd->open--; | ||
111 | } | ||
112 | |||
113 | |||
114 | static int dc_kbd_connect(struct maple_device *dev) | ||
115 | { | ||
116 | int i; | ||
117 | unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); | ||
118 | struct dc_kbd *kbd; | ||
119 | |||
120 | if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL))) | ||
121 | return -1; | ||
122 | memset(kbd, 0, sizeof(struct dc_kbd)); | ||
123 | |||
124 | dev->private_data = kbd; | ||
125 | |||
126 | kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
127 | |||
128 | init_input_dev(&kbd->dev); | ||
129 | |||
130 | for (i=0; i<255; i++) | ||
131 | set_bit(dc_kbd_keycode[i], kbd->dev.keybit); | ||
132 | |||
133 | clear_bit(0, kbd->dev.keybit); | ||
134 | |||
135 | kbd->dev.private = kbd; | ||
136 | kbd->dev.open = dc_kbd_open; | ||
137 | kbd->dev.close = dc_kbd_close; | ||
138 | kbd->dev.event = NULL; | ||
139 | |||
140 | kbd->dev.name = dev->product_name; | ||
141 | kbd->dev.id.bustype = BUS_MAPLE; | ||
142 | |||
143 | input_register_device(&kbd->dev); | ||
144 | |||
145 | maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); | ||
146 | |||
147 | printk(KERN_INFO "input: keyboard(0x%lx): %s\n", data, kbd->dev.name); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | |||
153 | static void dc_kbd_disconnect(struct maple_device *dev) | ||
154 | { | ||
155 | struct dc_kbd *kbd = dev->private_data; | ||
156 | |||
157 | input_unregister_device(&kbd->dev); | ||
158 | kfree(kbd); | ||
159 | } | ||
160 | |||
161 | |||
162 | static struct maple_driver dc_kbd_driver = { | ||
163 | .function = MAPLE_FUNC_KEYBOARD, | ||
164 | .name = "Dreamcast keyboard", | ||
165 | .connect = dc_kbd_connect, | ||
166 | .disconnect = dc_kbd_disconnect, | ||
167 | }; | ||
168 | |||
169 | |||
170 | static int __init dc_kbd_init(void) | ||
171 | { | ||
172 | maple_register_driver(&dc_kbd_driver); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | |||
177 | static void __exit dc_kbd_exit(void) | ||
178 | { | ||
179 | maple_unregister_driver(&dc_kbd_driver); | ||
180 | } | ||
181 | |||
182 | |||
183 | module_init(dc_kbd_init); | ||
184 | module_exit(dc_kbd_exit); | ||
185 | |||
186 | /* | ||
187 | * Local variables: | ||
188 | * c-basic-offset: 8 | ||
189 | * End: | ||
190 | */ | ||
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c new file mode 100644 index 000000000000..2e8ce1613eec --- /dev/null +++ b/drivers/input/keyboard/newtonkbd.c | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000 Justin Cormack | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * Newton keyboard driver for Linux | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * Should you need to contact me, the author, you can do so either by | ||
25 | * e-mail - mail your message to <j.cormack@doc.ic.ac.uk>, or by paper mail: | ||
26 | * Justin Cormack, 68 Dartmouth Park Road, London NW5 1SN, UK. | ||
27 | */ | ||
28 | |||
29 | #include <linux/slab.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/input.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/serio.h> | ||
34 | |||
35 | #define DRIVER_DESC "Newton keyboard driver" | ||
36 | |||
37 | MODULE_AUTHOR("Justin Cormack <j.cormack@doc.ic.ac.uk>"); | ||
38 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
41 | #define NKBD_KEY 0x7f | ||
42 | #define NKBD_PRESS 0x80 | ||
43 | |||
44 | static unsigned char nkbd_keycode[128] = { | ||
45 | KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X, | ||
46 | KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R, | ||
47 | KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5, | ||
48 | KEY_EQUAL, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_RIGHTBRACE, KEY_O, | ||
49 | KEY_U, KEY_LEFTBRACE, KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_APOSTROPHE, | ||
50 | KEY_K, KEY_SEMICOLON, KEY_BACKSLASH, KEY_COMMA, KEY_SLASH, KEY_N, KEY_M, KEY_DOT, | ||
51 | KEY_TAB, KEY_SPACE, KEY_GRAVE, KEY_DELETE, 0, 0, 0, KEY_LEFTMETA, | ||
52 | KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_LEFTALT, KEY_LEFTCTRL, KEY_RIGHTSHIFT, 0, 0, 0, | ||
53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
57 | KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0 | ||
58 | }; | ||
59 | |||
60 | static char *nkbd_name = "Newton Keyboard"; | ||
61 | |||
62 | struct nkbd { | ||
63 | unsigned char keycode[128]; | ||
64 | struct input_dev dev; | ||
65 | struct serio *serio; | ||
66 | char phys[32]; | ||
67 | }; | ||
68 | |||
69 | static irqreturn_t nkbd_interrupt(struct serio *serio, | ||
70 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
71 | { | ||
72 | struct nkbd *nkbd = serio_get_drvdata(serio); | ||
73 | |||
74 | /* invalid scan codes are probably the init sequence, so we ignore them */ | ||
75 | if (nkbd->keycode[data & NKBD_KEY]) { | ||
76 | input_regs(&nkbd->dev, regs); | ||
77 | input_report_key(&nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS); | ||
78 | input_sync(&nkbd->dev); | ||
79 | } | ||
80 | |||
81 | else if (data == 0xe7) /* end of init sequence */ | ||
82 | printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys); | ||
83 | return IRQ_HANDLED; | ||
84 | |||
85 | } | ||
86 | |||
87 | static int nkbd_connect(struct serio *serio, struct serio_driver *drv) | ||
88 | { | ||
89 | struct nkbd *nkbd; | ||
90 | int i; | ||
91 | int err; | ||
92 | |||
93 | if (!(nkbd = kmalloc(sizeof(struct nkbd), GFP_KERNEL))) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | memset(nkbd, 0, sizeof(struct nkbd)); | ||
97 | |||
98 | nkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
99 | |||
100 | nkbd->serio = serio; | ||
101 | |||
102 | init_input_dev(&nkbd->dev); | ||
103 | nkbd->dev.keycode = nkbd->keycode; | ||
104 | nkbd->dev.keycodesize = sizeof(unsigned char); | ||
105 | nkbd->dev.keycodemax = ARRAY_SIZE(nkbd_keycode); | ||
106 | nkbd->dev.private = nkbd; | ||
107 | |||
108 | serio_set_drvdata(serio, nkbd); | ||
109 | |||
110 | err = serio_open(serio, drv); | ||
111 | if (err) { | ||
112 | serio_set_drvdata(serio, NULL); | ||
113 | kfree(nkbd); | ||
114 | return err; | ||
115 | } | ||
116 | |||
117 | memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode)); | ||
118 | for (i = 0; i < 128; i++) | ||
119 | set_bit(nkbd->keycode[i], nkbd->dev.keybit); | ||
120 | clear_bit(0, nkbd->dev.keybit); | ||
121 | |||
122 | sprintf(nkbd->phys, "%s/input0", serio->phys); | ||
123 | |||
124 | nkbd->dev.name = nkbd_name; | ||
125 | nkbd->dev.phys = nkbd->phys; | ||
126 | nkbd->dev.id.bustype = BUS_RS232; | ||
127 | nkbd->dev.id.vendor = SERIO_NEWTON; | ||
128 | nkbd->dev.id.product = 0x0001; | ||
129 | nkbd->dev.id.version = 0x0100; | ||
130 | nkbd->dev.dev = &serio->dev; | ||
131 | |||
132 | input_register_device(&nkbd->dev); | ||
133 | |||
134 | printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static void nkbd_disconnect(struct serio *serio) | ||
140 | { | ||
141 | struct nkbd *nkbd = serio_get_drvdata(serio); | ||
142 | |||
143 | input_unregister_device(&nkbd->dev); | ||
144 | serio_close(serio); | ||
145 | serio_set_drvdata(serio, NULL); | ||
146 | kfree(nkbd); | ||
147 | } | ||
148 | |||
149 | static struct serio_device_id nkbd_serio_ids[] = { | ||
150 | { | ||
151 | .type = SERIO_RS232, | ||
152 | .proto = SERIO_NEWTON, | ||
153 | .id = SERIO_ANY, | ||
154 | .extra = SERIO_ANY, | ||
155 | }, | ||
156 | { 0 } | ||
157 | }; | ||
158 | |||
159 | MODULE_DEVICE_TABLE(serio, nkbd_serio_ids); | ||
160 | |||
161 | static struct serio_driver nkbd_drv = { | ||
162 | .driver = { | ||
163 | .name = "newtonkbd", | ||
164 | }, | ||
165 | .description = DRIVER_DESC, | ||
166 | .id_table = nkbd_serio_ids, | ||
167 | .interrupt = nkbd_interrupt, | ||
168 | .connect = nkbd_connect, | ||
169 | .disconnect = nkbd_disconnect, | ||
170 | }; | ||
171 | |||
172 | static int __init nkbd_init(void) | ||
173 | { | ||
174 | serio_register_driver(&nkbd_drv); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static void __exit nkbd_exit(void) | ||
179 | { | ||
180 | serio_unregister_driver(&nkbd_drv); | ||
181 | } | ||
182 | |||
183 | module_init(nkbd_init); | ||
184 | module_exit(nkbd_exit); | ||
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c new file mode 100644 index 000000000000..596964ceb96d --- /dev/null +++ b/drivers/input/keyboard/sunkbd.c | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * $Id: sunkbd.c,v 1.14 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Sun keyboard driver for Linux | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | * Should you need to contact me, the author, you can do so either by | ||
27 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
28 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
29 | */ | ||
30 | |||
31 | #include <linux/delay.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/input.h> | ||
37 | #include <linux/serio.h> | ||
38 | #include <linux/workqueue.h> | ||
39 | |||
40 | #define DRIVER_DESC "Sun keyboard driver" | ||
41 | |||
42 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
43 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | static unsigned char sunkbd_keycode[128] = { | ||
47 | 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0, | ||
48 | 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3, | ||
49 | 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55, | ||
50 | 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, | ||
51 | 26, 27,111,127, 71, 72, 73, 74,134,135,107, 0, 29, 30, 31, 32, | ||
52 | 33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136, | ||
53 | 104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101, | ||
54 | 79, 80, 81, 0, 0, 0,138, 58,125, 57,126,109, 86, 78 | ||
55 | }; | ||
56 | |||
57 | #define SUNKBD_CMD_RESET 0x1 | ||
58 | #define SUNKBD_CMD_BELLON 0x2 | ||
59 | #define SUNKBD_CMD_BELLOFF 0x3 | ||
60 | #define SUNKBD_CMD_CLICK 0xa | ||
61 | #define SUNKBD_CMD_NOCLICK 0xb | ||
62 | #define SUNKBD_CMD_SETLED 0xe | ||
63 | #define SUNKBD_CMD_LAYOUT 0xf | ||
64 | |||
65 | #define SUNKBD_RET_RESET 0xff | ||
66 | #define SUNKBD_RET_ALLUP 0x7f | ||
67 | #define SUNKBD_RET_LAYOUT 0xfe | ||
68 | |||
69 | #define SUNKBD_LAYOUT_5_MASK 0x20 | ||
70 | #define SUNKBD_RELEASE 0x80 | ||
71 | #define SUNKBD_KEY 0x7f | ||
72 | |||
73 | /* | ||
74 | * Per-keyboard data. | ||
75 | */ | ||
76 | |||
77 | struct sunkbd { | ||
78 | unsigned char keycode[128]; | ||
79 | struct input_dev dev; | ||
80 | struct serio *serio; | ||
81 | struct work_struct tq; | ||
82 | wait_queue_head_t wait; | ||
83 | char name[64]; | ||
84 | char phys[32]; | ||
85 | char type; | ||
86 | volatile s8 reset; | ||
87 | volatile s8 layout; | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * sunkbd_interrupt() is called by the low level driver when a character | ||
92 | * is received. | ||
93 | */ | ||
94 | |||
95 | static irqreturn_t sunkbd_interrupt(struct serio *serio, | ||
96 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
97 | { | ||
98 | struct sunkbd* sunkbd = serio_get_drvdata(serio); | ||
99 | |||
100 | if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ | ||
101 | sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */ | ||
102 | wake_up_interruptible(&sunkbd->wait); | ||
103 | goto out; | ||
104 | } | ||
105 | |||
106 | if (sunkbd->layout == -1) { | ||
107 | sunkbd->layout = data; | ||
108 | wake_up_interruptible(&sunkbd->wait); | ||
109 | goto out; | ||
110 | } | ||
111 | |||
112 | switch (data) { | ||
113 | |||
114 | case SUNKBD_RET_RESET: | ||
115 | schedule_work(&sunkbd->tq); | ||
116 | sunkbd->reset = -1; | ||
117 | break; | ||
118 | |||
119 | case SUNKBD_RET_LAYOUT: | ||
120 | sunkbd->layout = -1; | ||
121 | break; | ||
122 | |||
123 | case SUNKBD_RET_ALLUP: /* All keys released */ | ||
124 | break; | ||
125 | |||
126 | default: | ||
127 | if (sunkbd->keycode[data & SUNKBD_KEY]) { | ||
128 | input_regs(&sunkbd->dev, regs); | ||
129 | input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); | ||
130 | input_sync(&sunkbd->dev); | ||
131 | } else { | ||
132 | printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", | ||
133 | data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); | ||
134 | } | ||
135 | } | ||
136 | out: | ||
137 | return IRQ_HANDLED; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * sunkbd_event() handles events from the input module. | ||
142 | */ | ||
143 | |||
144 | static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
145 | { | ||
146 | struct sunkbd *sunkbd = dev->private; | ||
147 | |||
148 | switch (type) { | ||
149 | |||
150 | case EV_LED: | ||
151 | |||
152 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); | ||
153 | sunkbd->serio->write(sunkbd->serio, | ||
154 | (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | | ||
155 | (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); | ||
156 | return 0; | ||
157 | |||
158 | case EV_SND: | ||
159 | |||
160 | switch (code) { | ||
161 | |||
162 | case SND_CLICK: | ||
163 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); | ||
164 | return 0; | ||
165 | |||
166 | case SND_BELL: | ||
167 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | break; | ||
172 | } | ||
173 | |||
174 | return -1; | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * sunkbd_initialize() checks for a Sun keyboard attached, and determines | ||
179 | * its type. | ||
180 | */ | ||
181 | |||
182 | static int sunkbd_initialize(struct sunkbd *sunkbd) | ||
183 | { | ||
184 | sunkbd->reset = -2; | ||
185 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); | ||
186 | wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); | ||
187 | if (sunkbd->reset <0) | ||
188 | return -1; | ||
189 | |||
190 | sunkbd->type = sunkbd->reset; | ||
191 | |||
192 | if (sunkbd->type == 4) { /* Type 4 keyboard */ | ||
193 | sunkbd->layout = -2; | ||
194 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); | ||
195 | wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4); | ||
196 | if (sunkbd->layout < 0) return -1; | ||
197 | if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * sunkbd_reinit() sets leds and beeps to a state the computer remembers they | ||
205 | * were in. | ||
206 | */ | ||
207 | |||
208 | static void sunkbd_reinit(void *data) | ||
209 | { | ||
210 | struct sunkbd *sunkbd = data; | ||
211 | |||
212 | wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); | ||
213 | |||
214 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); | ||
215 | sunkbd->serio->write(sunkbd->serio, | ||
216 | (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) | | ||
217 | (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led)); | ||
218 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd)); | ||
219 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd)); | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. | ||
224 | */ | ||
225 | |||
226 | static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) | ||
227 | { | ||
228 | struct sunkbd *sunkbd; | ||
229 | int i; | ||
230 | int err; | ||
231 | |||
232 | if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL))) | ||
233 | return -ENOMEM; | ||
234 | |||
235 | memset(sunkbd, 0, sizeof(struct sunkbd)); | ||
236 | |||
237 | init_input_dev(&sunkbd->dev); | ||
238 | init_waitqueue_head(&sunkbd->wait); | ||
239 | |||
240 | sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); | ||
241 | sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); | ||
242 | sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); | ||
243 | |||
244 | sunkbd->serio = serio; | ||
245 | |||
246 | INIT_WORK(&sunkbd->tq, sunkbd_reinit, sunkbd); | ||
247 | |||
248 | sunkbd->dev.keycode = sunkbd->keycode; | ||
249 | sunkbd->dev.keycodesize = sizeof(unsigned char); | ||
250 | sunkbd->dev.keycodemax = ARRAY_SIZE(sunkbd_keycode); | ||
251 | |||
252 | sunkbd->dev.event = sunkbd_event; | ||
253 | sunkbd->dev.private = sunkbd; | ||
254 | |||
255 | serio_set_drvdata(serio, sunkbd); | ||
256 | |||
257 | err = serio_open(serio, drv); | ||
258 | if (err) { | ||
259 | serio_set_drvdata(serio, NULL); | ||
260 | kfree(sunkbd); | ||
261 | return err; | ||
262 | } | ||
263 | |||
264 | if (sunkbd_initialize(sunkbd) < 0) { | ||
265 | serio_close(serio); | ||
266 | serio_set_drvdata(serio, NULL); | ||
267 | kfree(sunkbd); | ||
268 | return -ENODEV; | ||
269 | } | ||
270 | |||
271 | sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); | ||
272 | |||
273 | memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); | ||
274 | for (i = 0; i < 128; i++) | ||
275 | set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); | ||
276 | clear_bit(0, sunkbd->dev.keybit); | ||
277 | |||
278 | sprintf(sunkbd->phys, "%s/input0", serio->phys); | ||
279 | |||
280 | sunkbd->dev.name = sunkbd->name; | ||
281 | sunkbd->dev.phys = sunkbd->phys; | ||
282 | sunkbd->dev.id.bustype = BUS_RS232; | ||
283 | sunkbd->dev.id.vendor = SERIO_SUNKBD; | ||
284 | sunkbd->dev.id.product = sunkbd->type; | ||
285 | sunkbd->dev.id.version = 0x0100; | ||
286 | sunkbd->dev.dev = &serio->dev; | ||
287 | |||
288 | input_register_device(&sunkbd->dev); | ||
289 | |||
290 | printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * sunkbd_disconnect() unregisters and closes behind us. | ||
297 | */ | ||
298 | |||
299 | static void sunkbd_disconnect(struct serio *serio) | ||
300 | { | ||
301 | struct sunkbd *sunkbd = serio_get_drvdata(serio); | ||
302 | input_unregister_device(&sunkbd->dev); | ||
303 | serio_close(serio); | ||
304 | serio_set_drvdata(serio, NULL); | ||
305 | kfree(sunkbd); | ||
306 | } | ||
307 | |||
308 | static struct serio_device_id sunkbd_serio_ids[] = { | ||
309 | { | ||
310 | .type = SERIO_RS232, | ||
311 | .proto = SERIO_SUNKBD, | ||
312 | .id = SERIO_ANY, | ||
313 | .extra = SERIO_ANY, | ||
314 | }, | ||
315 | { | ||
316 | .type = SERIO_RS232, | ||
317 | .proto = SERIO_UNKNOWN, /* sunkbd does probe */ | ||
318 | .id = SERIO_ANY, | ||
319 | .extra = SERIO_ANY, | ||
320 | }, | ||
321 | { 0 } | ||
322 | }; | ||
323 | |||
324 | MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids); | ||
325 | |||
326 | static struct serio_driver sunkbd_drv = { | ||
327 | .driver = { | ||
328 | .name = "sunkbd", | ||
329 | }, | ||
330 | .description = DRIVER_DESC, | ||
331 | .id_table = sunkbd_serio_ids, | ||
332 | .interrupt = sunkbd_interrupt, | ||
333 | .connect = sunkbd_connect, | ||
334 | .disconnect = sunkbd_disconnect, | ||
335 | }; | ||
336 | |||
337 | /* | ||
338 | * The functions for insering/removing us as a module. | ||
339 | */ | ||
340 | |||
341 | static int __init sunkbd_init(void) | ||
342 | { | ||
343 | serio_register_driver(&sunkbd_drv); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static void __exit sunkbd_exit(void) | ||
348 | { | ||
349 | serio_unregister_driver(&sunkbd_drv); | ||
350 | } | ||
351 | |||
352 | module_init(sunkbd_init); | ||
353 | module_exit(sunkbd_exit); | ||
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c new file mode 100644 index 000000000000..19eaec7789d1 --- /dev/null +++ b/drivers/input/keyboard/xtkbd.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * $Id: xtkbd.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * XT keyboard driver for Linux | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | * Should you need to contact me, the author, you can do so either by | ||
27 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
28 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
29 | */ | ||
30 | |||
31 | #include <linux/slab.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/input.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/serio.h> | ||
36 | |||
37 | #define DRIVER_DESC "XT keyboard driver" | ||
38 | |||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
40 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | #define XTKBD_EMUL0 0xe0 | ||
44 | #define XTKBD_EMUL1 0xe1 | ||
45 | #define XTKBD_KEY 0x7f | ||
46 | #define XTKBD_RELEASE 0x80 | ||
47 | |||
48 | static unsigned char xtkbd_keycode[256] = { | ||
49 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
50 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | ||
51 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, | ||
52 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, | ||
53 | 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, | ||
54 | 80, 81, 82, 83, 0, 0, 0, 87, 88, 0, 0, 0, 0, 0, 0, 0, | ||
55 | 0, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0,110,111,103,108,105, | ||
56 | 106 | ||
57 | }; | ||
58 | |||
59 | static char *xtkbd_name = "XT Keyboard"; | ||
60 | |||
61 | struct xtkbd { | ||
62 | unsigned char keycode[256]; | ||
63 | struct input_dev dev; | ||
64 | struct serio *serio; | ||
65 | char phys[32]; | ||
66 | }; | ||
67 | |||
68 | static irqreturn_t xtkbd_interrupt(struct serio *serio, | ||
69 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
70 | { | ||
71 | struct xtkbd *xtkbd = serio_get_drvdata(serio); | ||
72 | |||
73 | switch (data) { | ||
74 | case XTKBD_EMUL0: | ||
75 | case XTKBD_EMUL1: | ||
76 | break; | ||
77 | default: | ||
78 | |||
79 | if (xtkbd->keycode[data & XTKBD_KEY]) { | ||
80 | input_regs(&xtkbd->dev, regs); | ||
81 | input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); | ||
82 | input_sync(&xtkbd->dev); | ||
83 | } else { | ||
84 | printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n", | ||
85 | data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed"); | ||
86 | } | ||
87 | } | ||
88 | return IRQ_HANDLED; | ||
89 | } | ||
90 | |||
91 | static int xtkbd_connect(struct serio *serio, struct serio_driver *drv) | ||
92 | { | ||
93 | struct xtkbd *xtkbd; | ||
94 | int i; | ||
95 | int err; | ||
96 | |||
97 | if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL))) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | memset(xtkbd, 0, sizeof(struct xtkbd)); | ||
101 | |||
102 | xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
103 | |||
104 | xtkbd->serio = serio; | ||
105 | |||
106 | init_input_dev(&xtkbd->dev); | ||
107 | xtkbd->dev.keycode = xtkbd->keycode; | ||
108 | xtkbd->dev.keycodesize = sizeof(unsigned char); | ||
109 | xtkbd->dev.keycodemax = ARRAY_SIZE(xtkbd_keycode); | ||
110 | xtkbd->dev.private = xtkbd; | ||
111 | |||
112 | serio_set_drvdata(serio, xtkbd); | ||
113 | |||
114 | err = serio_open(serio, drv); | ||
115 | if (err) { | ||
116 | serio_set_drvdata(serio, NULL); | ||
117 | kfree(xtkbd); | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); | ||
122 | for (i = 0; i < 255; i++) | ||
123 | set_bit(xtkbd->keycode[i], xtkbd->dev.keybit); | ||
124 | clear_bit(0, xtkbd->dev.keybit); | ||
125 | |||
126 | sprintf(xtkbd->phys, "%s/input0", serio->phys); | ||
127 | |||
128 | xtkbd->dev.name = xtkbd_name; | ||
129 | xtkbd->dev.phys = xtkbd->phys; | ||
130 | xtkbd->dev.id.bustype = BUS_XTKBD; | ||
131 | xtkbd->dev.id.vendor = 0x0001; | ||
132 | xtkbd->dev.id.product = 0x0001; | ||
133 | xtkbd->dev.id.version = 0x0100; | ||
134 | xtkbd->dev.dev = &serio->dev; | ||
135 | |||
136 | input_register_device(&xtkbd->dev); | ||
137 | |||
138 | printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static void xtkbd_disconnect(struct serio *serio) | ||
144 | { | ||
145 | struct xtkbd *xtkbd = serio_get_drvdata(serio); | ||
146 | |||
147 | input_unregister_device(&xtkbd->dev); | ||
148 | serio_close(serio); | ||
149 | serio_set_drvdata(serio, NULL); | ||
150 | kfree(xtkbd); | ||
151 | } | ||
152 | |||
153 | static struct serio_device_id xtkbd_serio_ids[] = { | ||
154 | { | ||
155 | .type = SERIO_XT, | ||
156 | .proto = SERIO_ANY, | ||
157 | .id = SERIO_ANY, | ||
158 | .extra = SERIO_ANY, | ||
159 | }, | ||
160 | { 0 } | ||
161 | }; | ||
162 | |||
163 | MODULE_DEVICE_TABLE(serio, xtkbd_serio_ids); | ||
164 | |||
165 | static struct serio_driver xtkbd_drv = { | ||
166 | .driver = { | ||
167 | .name = "xtkbd", | ||
168 | }, | ||
169 | .description = DRIVER_DESC, | ||
170 | .id_table = xtkbd_serio_ids, | ||
171 | .interrupt = xtkbd_interrupt, | ||
172 | .connect = xtkbd_connect, | ||
173 | .disconnect = xtkbd_disconnect, | ||
174 | }; | ||
175 | |||
176 | static int __init xtkbd_init(void) | ||
177 | { | ||
178 | serio_register_driver(&xtkbd_drv); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static void __exit xtkbd_exit(void) | ||
183 | { | ||
184 | serio_unregister_driver(&xtkbd_drv); | ||
185 | } | ||
186 | |||
187 | module_init(xtkbd_init); | ||
188 | module_exit(xtkbd_exit); | ||