blob: 54bc569db4b014e999068a57c5ae11b1f41f6a69 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Helge Deller102c8c72006-03-26 07:41:55 -07006 * Copyright (C) 1999-2006 Helge Deller <deller@gmx.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/errno.h>
22#include <linux/input.h>
23#include <linux/init.h>
Matthew Wilcox6ab0f5c2005-10-21 22:58:51 -040024#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/hil.h>
26#include <linux/spinlock.h>
27
28
29MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller");
30MODULE_DESCRIPTION("HIL keyboard driver (basic functionality)");
31MODULE_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
87static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
88 { HIL_KEYCODES_SET1 };
89
90/* HIL structure */
91static struct {
Helge Deller102c8c72006-03-26 07:41:55 -070092 struct input_dev *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
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
108static 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];
Helge Deller102c8c72006-03-26 07:41:55 -0700119 input_report_key(hil_dev.dev, key, down);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 break;
121 }
122 hil_dev.curdev = 0;
123}
124
125static 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
141static 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 */
David Howells7d12e782006-10-05 14:55:46 +0100153static irqreturn_t hil_interrupt(int irq, void *handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
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
181static 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
202static int __init
203hil_keyb_init(void)
204{
205 unsigned char c;
206 unsigned int i, kbid;
207 wait_queue_head_t hil_wait;
208
Helge Deller102c8c72006-03-26 07:41:55 -0700209 if (hil_dev.dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 return -ENODEV; /* already initialized */
211 }
Helge Deller102c8c72006-03-26 07:41:55 -0700212
213 hil_dev.dev = input_allocate_device();
214 if (!hil_dev.dev)
215 return -ENOMEM;
216 hil_dev.dev->private = &hil_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
255 if (hphilkeyb_keycode[i] != KEY_RESERVED)
Helge Deller102c8c72006-03-26 07:41:55 -0700256 set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Helge Deller102c8c72006-03-26 07:41:55 -0700258 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";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Helge Deller102c8c72006-03-26 07:41:55 -0700266 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Helge Deller102c8c72006-03-26 07:41:55 -0700271 input_register_device(hil_dev.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
Helge Deller102c8c72006-03-26 07:41:55 -0700273 hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 return 0;
276}
277
278#if defined(CONFIG_PARISC)
279static int __init
280hil_init_chip(struct parisc_device *dev)
281{
282 if (!dev->irq) {
Matthew Wilcox53f01bb2005-10-21 22:36:40 -0400283 printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa.start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 return -ENODEV;
285 }
286
Matthew Wilcox53f01bb2005-10-21 22:36:40 -0400287 hil_base = dev->hpa.start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 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
296static struct parisc_device_id hil_tbl[] = {
297 { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 },
298 { 0, }
299};
300
301MODULE_DEVICE_TABLE(parisc, hil_tbl);
302
303static struct parisc_driver hil_driver = {
Matthew Wilcoxbdad1f82005-10-21 22:36:23 -0400304 .name = "hil",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 .id_table = hil_tbl,
306 .probe = hil_init_chip,
307};
308#endif /* CONFIG_PARISC */
309
310
311
312
313
314static 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
324static 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
Helge Deller102c8c72006-03-26 07:41:55 -0700334 input_unregister_device(hil_dev.dev);
335
Helge Deller102c8c72006-03-26 07:41:55 -0700336 hil_dev.dev = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338#if defined(CONFIG_PARISC)
339 unregister_parisc_driver(&hil_driver);
340#else
341 release_region(HILBASE+HIL_DATA, 2);
342#endif
343}
344
345module_init(hil_init);
346module_exit(hil_exit);
347