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