]>
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> | |
102c8c76 | 6 | * Copyright (C) 1999-2006 Helge Deller <deller@gmx.de> |
1da177e4 LT |
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> | |
1da177e4 LT |
21 | #include <linux/errno.h> |
22 | #include <linux/input.h> | |
23 | #include <linux/init.h> | |
6ab0f5cd | 24 | #include <linux/interrupt.h> |
1da177e4 LT |
25 | #include <linux/hil.h> |
26 | #include <linux/spinlock.h> | |
27 | ||
28 | ||
29 | MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller"); | |
30 | MODULE_DESCRIPTION("HIL keyboard driver (basic functionality)"); | |
31 | MODULE_LICENSE("GPL v2"); | |
32 | ||
33 | ||
34 | #if defined(CONFIG_PARISC) | |
35 | ||
36 | #include <asm/io.h> | |
37 | #include <asm/hardware.h> | |
38 | #include <asm/parisc-device.h> | |
39 | static unsigned long hil_base; /* HPA for the HIL device */ | |
40 | static unsigned int hil_irq; | |
41 | #define HILBASE hil_base /* HPPA (parisc) port address */ | |
42 | #define HIL_DATA 0x800 | |
43 | #define HIL_CMD 0x801 | |
44 | #define HIL_IRQ hil_irq | |
45 | #define hil_readb(p) gsc_readb(p) | |
46 | #define hil_writeb(v,p) gsc_writeb((v),(p)) | |
47 | ||
48 | #elif defined(CONFIG_HP300) | |
49 | ||
50 | #define HILBASE 0xf0428000 /* HP300 (m86k) port address */ | |
51 | #define HIL_DATA 0x1 | |
52 | #define HIL_CMD 0x3 | |
53 | #define HIL_IRQ 2 | |
54 | #define hil_readb(p) readb(p) | |
55 | #define hil_writeb(v,p) writeb((v),(p)) | |
56 | ||
57 | #else | |
58 | #error "HIL is not supported on this platform" | |
59 | #endif | |
60 | ||
61 | ||
62 | ||
63 | /* HIL helper functions */ | |
64 | ||
65 | #define hil_busy() (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY) | |
66 | #define hil_data_available() (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY) | |
67 | #define hil_status() (hil_readb(HILBASE + HIL_CMD)) | |
68 | #define hil_command(x) do { hil_writeb((x), HILBASE + HIL_CMD); } while (0) | |
69 | #define hil_read_data() (hil_readb(HILBASE + HIL_DATA)) | |
70 | #define hil_write_data(x) do { hil_writeb((x), HILBASE + HIL_DATA); } while (0) | |
71 | ||
72 | /* HIL constants */ | |
73 | ||
74 | #define HIL_BUSY 0x02 | |
75 | #define HIL_DATA_RDY 0x01 | |
76 | ||
77 | #define HIL_SETARD 0xA0 /* set auto-repeat delay */ | |
78 | #define HIL_SETARR 0xA2 /* set auto-repeat rate */ | |
79 | #define HIL_SETTONE 0xA3 /* set tone generator */ | |
80 | #define HIL_CNMT 0xB2 /* clear nmi */ | |
81 | #define HIL_INTON 0x5C /* Turn on interrupts. */ | |
82 | #define HIL_INTOFF 0x5D /* Turn off interrupts. */ | |
83 | ||
84 | #define HIL_READKBDSADR 0xF9 | |
85 | #define HIL_WRITEKBDSADR 0xE9 | |
86 | ||
87 | static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = | |
88 | { HIL_KEYCODES_SET1 }; | |
89 | ||
90 | /* HIL structure */ | |
91 | static struct { | |
102c8c76 | 92 | struct input_dev *dev; |
1da177e4 LT |
93 | |
94 | unsigned int curdev; | |
95 | ||
96 | unsigned char s; | |
97 | unsigned char c; | |
98 | int valid; | |
99 | ||
100 | unsigned char data[16]; | |
101 | unsigned int ptr; | |
102 | spinlock_t lock; | |
103 | ||
104 | void *dev_id; /* native bus device */ | |
105 | } hil_dev; | |
106 | ||
107 | ||
108 | static void poll_finished(void) | |
109 | { | |
110 | int down; | |
111 | int key; | |
112 | unsigned char scode; | |
113 | ||
114 | switch (hil_dev.data[0]) { | |
115 | case 0x40: | |
116 | down = (hil_dev.data[1] & 1) == 0; | |
117 | scode = hil_dev.data[1] >> 1; | |
118 | key = hphilkeyb_keycode[scode]; | |
102c8c76 | 119 | input_report_key(hil_dev.dev, key, down); |
1da177e4 LT |
120 | break; |
121 | } | |
122 | hil_dev.curdev = 0; | |
123 | } | |
124 | ||
125 | static inline void handle_status(unsigned char s, unsigned char c) | |
126 | { | |
127 | if (c & 0x8) { | |
128 | /* End of block */ | |
129 | if (c & 0x10) | |
130 | poll_finished(); | |
131 | } else { | |
132 | if (c & 0x10) { | |
133 | if (hil_dev.curdev) | |
134 | poll_finished(); /* just in case */ | |
135 | hil_dev.curdev = c & 7; | |
136 | hil_dev.ptr = 0; | |
137 | } | |
138 | } | |
139 | } | |
140 | ||
141 | static inline void handle_data(unsigned char s, unsigned char c) | |
142 | { | |
143 | if (hil_dev.curdev) { | |
144 | hil_dev.data[hil_dev.ptr++] = c; | |
145 | hil_dev.ptr &= 15; | |
146 | } | |
147 | } | |
148 | ||
149 | ||
150 | /* | |
151 | * Handle HIL interrupts. | |
152 | */ | |
7d12e780 | 153 | static irqreturn_t hil_interrupt(int irq, void *handle) |
1da177e4 LT |
154 | { |
155 | unsigned char s, c; | |
156 | ||
157 | s = hil_status(); | |
158 | c = hil_read_data(); | |
159 | ||
160 | switch (s >> 4) { | |
161 | case 0x5: | |
162 | handle_status(s, c); | |
163 | break; | |
164 | case 0x6: | |
165 | handle_data(s, c); | |
166 | break; | |
167 | case 0x4: | |
168 | hil_dev.s = s; | |
169 | hil_dev.c = c; | |
170 | mb(); | |
171 | hil_dev.valid = 1; | |
172 | break; | |
173 | } | |
174 | return IRQ_HANDLED; | |
175 | } | |
176 | ||
177 | /* | |
178 | * Send a command to the HIL | |
179 | */ | |
180 | ||
181 | static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) | |
182 | { | |
183 | unsigned long flags; | |
184 | ||
185 | spin_lock_irqsave(&hil_dev.lock, flags); | |
186 | while (hil_busy()) | |
187 | /* wait */; | |
188 | hil_command(cmd); | |
189 | while (len--) { | |
190 | while (hil_busy()) | |
191 | /* wait */; | |
192 | hil_write_data(*(data++)); | |
193 | } | |
194 | spin_unlock_irqrestore(&hil_dev.lock, flags); | |
195 | } | |
196 | ||
197 | ||
198 | /* | |
199 | * Initialise HIL. | |
200 | */ | |
201 | ||
202 | static int __init | |
203 | hil_keyb_init(void) | |
204 | { | |
205 | unsigned char c; | |
206 | unsigned int i, kbid; | |
207 | wait_queue_head_t hil_wait; | |
208 | ||
102c8c76 | 209 | if (hil_dev.dev) { |
1da177e4 LT |
210 | return -ENODEV; /* already initialized */ |
211 | } | |
102c8c76 HD |
212 | |
213 | hil_dev.dev = input_allocate_device(); | |
214 | if (!hil_dev.dev) | |
215 | return -ENOMEM; | |
216 | hil_dev.dev->private = &hil_dev; | |
1da177e4 LT |
217 | |
218 | #if defined(CONFIG_HP300) | |
219 | if (!hwreg_present((void *)(HILBASE + HIL_DATA))) | |
220 | return -ENODEV; | |
221 | ||
222 | request_region(HILBASE+HIL_DATA, 2, "hil"); | |
223 | #endif | |
224 | ||
225 | request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id); | |
226 | ||
227 | /* Turn on interrupts */ | |
228 | hil_do(HIL_INTON, NULL, 0); | |
229 | ||
230 | /* Look for keyboards */ | |
231 | hil_dev.valid = 0; /* clear any pending data */ | |
232 | hil_do(HIL_READKBDSADR, NULL, 0); | |
233 | ||
234 | init_waitqueue_head(&hil_wait); | |
235 | wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ); | |
236 | if (!hil_dev.valid) { | |
237 | printk(KERN_WARNING "HIL: timed out, assuming no keyboard present.\n"); | |
238 | } | |
239 | ||
240 | c = hil_dev.c; | |
241 | hil_dev.valid = 0; | |
242 | if (c == 0) { | |
243 | kbid = -1; | |
244 | printk(KERN_WARNING "HIL: no keyboard present.\n"); | |
245 | } else { | |
246 | kbid = ffz(~c); | |
247 | /* printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); */ | |
248 | } | |
249 | ||
250 | /* set it to raw mode */ | |
251 | c = 0; | |
252 | hil_do(HIL_WRITEKBDSADR, &c, 1); | |
253 | ||
1da177e4 LT |
254 | for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++) |
255 | if (hphilkeyb_keycode[i] != KEY_RESERVED) | |
102c8c76 HD |
256 | set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit); |
257 | ||
258 | hil_dev.dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | |
259 | hil_dev.dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); | |
260 | hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; | |
261 | hil_dev.dev->keycodesize = sizeof(hphilkeyb_keycode[0]); | |
262 | hil_dev.dev->keycode = hphilkeyb_keycode; | |
263 | hil_dev.dev->name = "HIL keyboard"; | |
264 | hil_dev.dev->phys = "hpkbd/input0"; | |
265 | ||
266 | hil_dev.dev->id.bustype = BUS_HIL; | |
267 | hil_dev.dev->id.vendor = PCI_VENDOR_ID_HP; | |
268 | hil_dev.dev->id.product = 0x0001; | |
269 | hil_dev.dev->id.version = 0x0010; | |
270 | ||
271 | input_register_device(hil_dev.dev); | |
1da177e4 | 272 | printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n", |
102c8c76 | 273 | hil_dev.dev->name, kbid, HILBASE, HIL_IRQ); |
1da177e4 LT |
274 | |
275 | return 0; | |
276 | } | |
277 | ||
278 | #if defined(CONFIG_PARISC) | |
279 | static int __init | |
280 | hil_init_chip(struct parisc_device *dev) | |
281 | { | |
282 | if (!dev->irq) { | |
53f01bba | 283 | printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa.start); |
1da177e4 LT |
284 | return -ENODEV; |
285 | } | |
286 | ||
53f01bba | 287 | hil_base = dev->hpa.start; |
1da177e4 LT |
288 | hil_irq = dev->irq; |
289 | hil_dev.dev_id = dev; | |
290 | ||
291 | printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq); | |
292 | ||
293 | return hil_keyb_init(); | |
294 | } | |
295 | ||
296 | static struct parisc_device_id hil_tbl[] = { | |
297 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 }, | |
298 | { 0, } | |
299 | }; | |
300 | ||
301 | MODULE_DEVICE_TABLE(parisc, hil_tbl); | |
302 | ||
303 | static struct parisc_driver hil_driver = { | |
bdad1f83 | 304 | .name = "hil", |
1da177e4 LT |
305 | .id_table = hil_tbl, |
306 | .probe = hil_init_chip, | |
307 | }; | |
308 | #endif /* CONFIG_PARISC */ | |
309 | ||
310 | ||
311 | ||
312 | ||
313 | ||
314 | static int __init hil_init(void) | |
315 | { | |
316 | #if defined(CONFIG_PARISC) | |
317 | return register_parisc_driver(&hil_driver); | |
318 | #else | |
319 | return hil_keyb_init(); | |
320 | #endif | |
321 | } | |
322 | ||
323 | ||
324 | static void __exit hil_exit(void) | |
325 | { | |
326 | if (HIL_IRQ) { | |
327 | disable_irq(HIL_IRQ); | |
328 | free_irq(HIL_IRQ, hil_dev.dev_id); | |
329 | } | |
330 | ||
331 | /* Turn off interrupts */ | |
332 | hil_do(HIL_INTOFF, NULL, 0); | |
333 | ||
102c8c76 HD |
334 | input_unregister_device(hil_dev.dev); |
335 | ||
102c8c76 | 336 | hil_dev.dev = NULL; |
1da177e4 LT |
337 | |
338 | #if defined(CONFIG_PARISC) | |
339 | unregister_parisc_driver(&hil_driver); | |
340 | #else | |
341 | release_region(HILBASE+HIL_DATA, 2); | |
342 | #endif | |
343 | } | |
344 | ||
345 | module_init(hil_init); | |
346 | module_exit(hil_exit); | |
347 |