]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 |