1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/drivers/hil/hilkbd.c |
4 | * |
5 | * Copyright (C) 1998 Philip Blundell <philb@gnu.org> |
6 | * Copyright (C) 1999 Matthew Wilcox <willy@infradead.org> |
7 | * Copyright (C) 1999-2007 Helge Deller <deller@gmx.de> |
8 | * |
9 | * Very basic HP Human Interface Loop (HIL) driver. |
10 | * This driver handles the keyboard on HP300 (m68k) and on some |
11 | * HP700 (parisc) series machines. |
12 | */ |
13 | |
14 | #include <linux/pci_ids.h> |
15 | #include <linux/ioport.h> |
16 | #include <linux/module.h> |
17 | #include <linux/errno.h> |
18 | #include <linux/input.h> |
19 | #include <linux/init.h> |
20 | #include <linux/interrupt.h> |
21 | #include <linux/hil.h> |
22 | #include <linux/io.h> |
23 | #include <linux/sched.h> |
24 | #include <linux/spinlock.h> |
25 | #include <asm/irq.h> |
26 | #ifdef CONFIG_HP300 |
27 | #include <asm/hwtest.h> |
28 | #endif |
29 | |
30 | |
31 | MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller" ); |
32 | MODULE_DESCRIPTION("HIL keyboard driver (basic functionality)" ); |
33 | MODULE_LICENSE("GPL v2" ); |
34 | |
35 | |
36 | #if defined(CONFIG_PARISC) |
37 | |
38 | #include <asm/io.h> |
39 | #include <asm/hardware.h> |
40 | #include <asm/parisc-device.h> |
41 | static unsigned long hil_base; /* HPA for the HIL device */ |
42 | static unsigned int hil_irq; |
43 | #define HILBASE hil_base /* HPPA (parisc) port address */ |
44 | #define HIL_DATA 0x800 |
45 | #define HIL_CMD 0x801 |
46 | #define HIL_IRQ hil_irq |
47 | #define hil_readb(p) gsc_readb(p) |
48 | #define hil_writeb(v,p) gsc_writeb((v),(p)) |
49 | |
50 | #elif defined(CONFIG_HP300) |
51 | |
52 | #define HILBASE 0xf0428000UL /* HP300 (m68k) port address */ |
53 | #define HIL_DATA 0x1 |
54 | #define HIL_CMD 0x3 |
55 | #define HIL_IRQ 2 |
56 | #define hil_readb(p) readb((const volatile void __iomem *)(p)) |
57 | #define hil_writeb(v, p) writeb((v), (volatile void __iomem *)(p)) |
58 | |
59 | #else |
60 | #error "HIL is not supported on this platform" |
61 | #endif |
62 | |
63 | |
64 | |
65 | /* HIL helper functions */ |
66 | |
67 | #define hil_busy() (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY) |
68 | #define hil_data_available() (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY) |
69 | #define hil_status() (hil_readb(HILBASE + HIL_CMD)) |
70 | #define hil_command(x) do { hil_writeb((x), HILBASE + HIL_CMD); } while (0) |
71 | #define hil_read_data() (hil_readb(HILBASE + HIL_DATA)) |
72 | #define hil_write_data(x) do { hil_writeb((x), HILBASE + HIL_DATA); } while (0) |
73 | |
74 | /* HIL constants */ |
75 | |
76 | #define HIL_BUSY 0x02 |
77 | #define HIL_DATA_RDY 0x01 |
78 | |
79 | #define HIL_SETARD 0xA0 /* set auto-repeat delay */ |
80 | #define HIL_SETARR 0xA2 /* set auto-repeat rate */ |
81 | #define HIL_SETTONE 0xA3 /* set tone generator */ |
82 | #define HIL_CNMT 0xB2 /* clear nmi */ |
83 | #define HIL_INTON 0x5C /* Turn on interrupts. */ |
84 | #define HIL_INTOFF 0x5D /* Turn off interrupts. */ |
85 | |
86 | #define HIL_READKBDSADR 0xF9 |
87 | #define HIL_WRITEKBDSADR 0xE9 |
88 | |
89 | static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly = |
90 | { HIL_KEYCODES_SET1 }; |
91 | |
92 | /* HIL structure */ |
93 | static struct { |
94 | struct input_dev *dev; |
95 | |
96 | unsigned int curdev; |
97 | |
98 | unsigned char s; |
99 | unsigned char c; |
100 | int valid; |
101 | |
102 | unsigned char data[16]; |
103 | unsigned int ptr; |
104 | spinlock_t lock; |
105 | |
106 | void *dev_id; /* native bus device */ |
107 | } hil_dev; |
108 | |
109 | |
110 | static void poll_finished(void) |
111 | { |
112 | int down; |
113 | int key; |
114 | unsigned char scode; |
115 | |
116 | switch (hil_dev.data[0]) { |
117 | case 0x40: |
118 | down = (hil_dev.data[1] & 1) == 0; |
119 | scode = hil_dev.data[1] >> 1; |
120 | key = hphilkeyb_keycode[scode]; |
121 | input_report_key(dev: hil_dev.dev, code: key, value: down); |
122 | break; |
123 | } |
124 | hil_dev.curdev = 0; |
125 | } |
126 | |
127 | |
128 | static inline void handle_status(unsigned char s, unsigned char c) |
129 | { |
130 | if (c & 0x8) { |
131 | /* End of block */ |
132 | if (c & 0x10) |
133 | poll_finished(); |
134 | } else { |
135 | if (c & 0x10) { |
136 | if (hil_dev.curdev) |
137 | poll_finished(); /* just in case */ |
138 | hil_dev.curdev = c & 7; |
139 | hil_dev.ptr = 0; |
140 | } |
141 | } |
142 | } |
143 | |
144 | |
145 | static inline void handle_data(unsigned char s, unsigned char c) |
146 | { |
147 | if (hil_dev.curdev) { |
148 | hil_dev.data[hil_dev.ptr++] = c; |
149 | hil_dev.ptr &= 15; |
150 | } |
151 | } |
152 | |
153 | |
154 | /* handle HIL interrupts */ |
155 | static irqreturn_t hil_interrupt(int irq, void *handle) |
156 | { |
157 | unsigned char s, c; |
158 | |
159 | s = hil_status(); |
160 | c = hil_read_data(); |
161 | |
162 | switch (s >> 4) { |
163 | case 0x5: |
164 | handle_status(s, c); |
165 | break; |
166 | case 0x6: |
167 | handle_data(s, c); |
168 | break; |
169 | case 0x4: |
170 | hil_dev.s = s; |
171 | hil_dev.c = c; |
172 | mb(); |
173 | hil_dev.valid = 1; |
174 | break; |
175 | } |
176 | return IRQ_HANDLED; |
177 | } |
178 | |
179 | |
180 | /* send a command to the HIL */ |
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(lock: &hil_dev.lock, flags); |
195 | } |
196 | |
197 | |
198 | /* initialize HIL */ |
199 | static int hil_keyb_init(void) |
200 | { |
201 | unsigned char c; |
202 | unsigned int i, kbid; |
203 | wait_queue_head_t hil_wait; |
204 | int err; |
205 | |
206 | if (hil_dev.dev) |
207 | return -ENODEV; /* already initialized */ |
208 | |
209 | init_waitqueue_head(&hil_wait); |
210 | spin_lock_init(&hil_dev.lock); |
211 | |
212 | hil_dev.dev = input_allocate_device(); |
213 | if (!hil_dev.dev) |
214 | return -ENOMEM; |
215 | |
216 | err = request_irq(irq: HIL_IRQ, handler: hil_interrupt, flags: 0, name: "hil" , dev: hil_dev.dev_id); |
217 | if (err) { |
218 | printk(KERN_ERR "HIL: Can't get IRQ\n" ); |
219 | goto err1; |
220 | } |
221 | |
222 | /* Turn on interrupts */ |
223 | hil_do(HIL_INTON, NULL, len: 0); |
224 | |
225 | /* Look for keyboards */ |
226 | hil_dev.valid = 0; /* clear any pending data */ |
227 | hil_do(HIL_READKBDSADR, NULL, len: 0); |
228 | |
229 | wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3 * HZ); |
230 | if (!hil_dev.valid) |
231 | printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n" ); |
232 | |
233 | c = hil_dev.c; |
234 | hil_dev.valid = 0; |
235 | if (c == 0) { |
236 | kbid = -1; |
237 | printk(KERN_WARNING "HIL: no keyboard present\n" ); |
238 | } else { |
239 | kbid = ffz(~c); |
240 | printk(KERN_INFO "HIL: keyboard found at id %d\n" , kbid); |
241 | } |
242 | |
243 | /* set it to raw mode */ |
244 | c = 0; |
245 | hil_do(HIL_WRITEKBDSADR, data: &c, len: 1); |
246 | |
247 | for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++) |
248 | if (hphilkeyb_keycode[i] != KEY_RESERVED) |
249 | __set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit); |
250 | |
251 | hil_dev.dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); |
252 | hil_dev.dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | |
253 | BIT_MASK(LED_SCROLLL); |
254 | hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; |
255 | hil_dev.dev->keycodesize= sizeof(hphilkeyb_keycode[0]); |
256 | hil_dev.dev->keycode = hphilkeyb_keycode; |
257 | hil_dev.dev->name = "HIL keyboard" ; |
258 | hil_dev.dev->phys = "hpkbd/input0" ; |
259 | |
260 | hil_dev.dev->id.bustype = BUS_HIL; |
261 | hil_dev.dev->id.vendor = PCI_VENDOR_ID_HP; |
262 | hil_dev.dev->id.product = 0x0001; |
263 | hil_dev.dev->id.version = 0x0010; |
264 | |
265 | err = input_register_device(hil_dev.dev); |
266 | if (err) { |
267 | printk(KERN_ERR "HIL: Can't register device\n" ); |
268 | goto err2; |
269 | } |
270 | |
271 | printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n" , |
272 | hil_dev.dev->name, kbid, HILBASE, HIL_IRQ); |
273 | |
274 | return 0; |
275 | |
276 | err2: |
277 | hil_do(HIL_INTOFF, NULL, len: 0); |
278 | free_irq(HIL_IRQ, hil_dev.dev_id); |
279 | err1: |
280 | input_free_device(dev: hil_dev.dev); |
281 | hil_dev.dev = NULL; |
282 | return err; |
283 | } |
284 | |
285 | static void hil_keyb_exit(void) |
286 | { |
287 | if (HIL_IRQ) |
288 | free_irq(HIL_IRQ, hil_dev.dev_id); |
289 | |
290 | /* Turn off interrupts */ |
291 | hil_do(HIL_INTOFF, NULL, len: 0); |
292 | |
293 | input_unregister_device(hil_dev.dev); |
294 | hil_dev.dev = NULL; |
295 | } |
296 | |
297 | #if defined(CONFIG_PARISC) |
298 | static int __init hil_probe_chip(struct parisc_device *dev) |
299 | { |
300 | /* Only allow one HIL keyboard */ |
301 | if (hil_dev.dev) |
302 | return -ENODEV; |
303 | |
304 | if (!dev->irq) { |
305 | printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%p\n" , |
306 | (void *)dev->hpa.start); |
307 | return -ENODEV; |
308 | } |
309 | |
310 | hil_base = dev->hpa.start; |
311 | hil_irq = dev->irq; |
312 | hil_dev.dev_id = dev; |
313 | |
314 | printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n" , hil_base, hil_irq); |
315 | |
316 | return hil_keyb_init(); |
317 | } |
318 | |
319 | static void __exit hil_remove_chip(struct parisc_device *dev) |
320 | { |
321 | hil_keyb_exit(); |
322 | } |
323 | |
324 | static const struct parisc_device_id hil_tbl[] __initconst = { |
325 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 }, |
326 | { 0, } |
327 | }; |
328 | |
329 | #if 0 |
330 | /* Disabled to avoid conflicts with the HP SDC HIL drivers */ |
331 | MODULE_DEVICE_TABLE(parisc, hil_tbl); |
332 | #endif |
333 | |
334 | static struct parisc_driver hil_driver __refdata = { |
335 | .name = "hil" , |
336 | .id_table = hil_tbl, |
337 | .probe = hil_probe_chip, |
338 | .remove = __exit_p(hil_remove_chip), |
339 | }; |
340 | |
341 | static int __init hil_init(void) |
342 | { |
343 | return register_parisc_driver(&hil_driver); |
344 | } |
345 | |
346 | static void __exit hil_exit(void) |
347 | { |
348 | unregister_parisc_driver(&hil_driver); |
349 | } |
350 | |
351 | #else /* !CONFIG_PARISC */ |
352 | |
353 | static int __init hil_init(void) |
354 | { |
355 | int error; |
356 | |
357 | /* Only allow one HIL keyboard */ |
358 | if (hil_dev.dev) |
359 | return -EBUSY; |
360 | |
361 | if (!MACH_IS_HP300) |
362 | return -ENODEV; |
363 | |
364 | if (!hwreg_present((void *)(HILBASE + HIL_DATA))) { |
365 | printk(KERN_ERR "HIL: hardware register was not found\n" ); |
366 | return -ENODEV; |
367 | } |
368 | |
369 | if (!request_region(HILBASE + HIL_DATA, 2, "hil" )) { |
370 | printk(KERN_ERR "HIL: IOPORT region already used\n" ); |
371 | return -EIO; |
372 | } |
373 | |
374 | error = hil_keyb_init(); |
375 | if (error) { |
376 | release_region(HILBASE + HIL_DATA, 2); |
377 | return error; |
378 | } |
379 | |
380 | return 0; |
381 | } |
382 | |
383 | static void __exit hil_exit(void) |
384 | { |
385 | hil_keyb_exit(); |
386 | release_region(HILBASE + HIL_DATA, 2); |
387 | } |
388 | |
389 | #endif /* CONFIG_PARISC */ |
390 | |
391 | module_init(hil_init); |
392 | module_exit(hil_exit); |
393 | |