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/hilkbd.c |
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/hilkbd.c')
-rw-r--r-- | drivers/input/keyboard/hilkbd.c | 343 |
1 files changed, 343 insertions, 0 deletions
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 | |||