blob: fe57044e9e544ee2a566c15ddb0042496fbffa2d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Generic linux-input device driver for keyboard devices
3 *
4 * Copyright (c) 2001 Brian S. Julin
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer,
12 * without modification.
13 * 2. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * Alternatively, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL").
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 *
29 * References:
30 * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A
31 *
32 */
33
34#include <linux/hil.h>
35#include <linux/input.h>
36#include <linux/serio.h>
37#include <linux/kernel.h>
38#include <linux/module.h>
39#include <linux/init.h>
Dmitry Torokhov6777f012009-08-07 23:17:46 -070040#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/slab.h>
42#include <linux/pci_ids.h>
43
44#define PREFIX "HIL KEYB: "
45#define HIL_GENERIC_NAME "HIL keyboard"
46
47MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
48MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
49MODULE_LICENSE("Dual BSD/GPL");
Helge Dellerc10a93a2008-12-29 04:44:44 -080050MODULE_ALIAS("serio:ty03pr25id00ex*");
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#define HIL_KBD_MAX_LENGTH 16
53
54#define HIL_KBD_SET1_UPBIT 0x01
55#define HIL_KBD_SET1_SHIFT 1
Helge Deller3acaf542007-02-28 23:51:19 -050056static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 { HIL_KEYCODES_SET1 };
58
59#define HIL_KBD_SET2_UPBIT 0x01
60#define HIL_KBD_SET2_SHIFT 1
61/* Set2 is user defined */
62
63#define HIL_KBD_SET3_UPBIT 0x80
64#define HIL_KBD_SET3_SHIFT 0
Helge Deller3acaf542007-02-28 23:51:19 -050065static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly =
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 { HIL_KEYCODES_SET3 };
67
Helge Deller3acaf542007-02-28 23:51:19 -050068static const char hil_language[][16] = { HIL_LOCALE_MAP };
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70struct hil_kbd {
Helge Deller102c8c72006-03-26 07:41:55 -070071 struct input_dev *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 struct serio *serio;
73
74 /* Input buffer and index for packets from HIL bus. */
75 hil_packet data[HIL_KBD_MAX_LENGTH];
76 int idx4; /* four counts per packet */
77
78 /* Raw device info records from HIL bus, see hil.h for fields. */
79 char idd[HIL_KBD_MAX_LENGTH]; /* DID byte and IDD record */
80 char rsc[HIL_KBD_MAX_LENGTH]; /* RSC record */
81 char exd[HIL_KBD_MAX_LENGTH]; /* EXD record */
82 char rnm[HIL_KBD_MAX_LENGTH + 1]; /* RNM record + NULL term. */
83
Dmitry Torokhov6777f012009-08-07 23:17:46 -070084 struct completion cmd_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085};
86
Dmitry Torokhov6777f012009-08-07 23:17:46 -070087static bool hil_kbd_is_command_response(hil_packet p)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
Dmitry Torokhov6777f012009-08-07 23:17:46 -070089 if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
90 return false;
91
92 if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
93 return false;
94
95 return true;
96}
97
98static void hil_kbd_handle_command_response(struct hil_kbd *kbd)
99{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 hil_packet p;
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700101 char *buf;
102 int i, idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700104 idx = kbd->idx4 / 4;
105 p = kbd->data[idx - 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 switch (p & HIL_PKT_DATA_MASK) {
108 case HIL_CMD_IDD:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700109 buf = kbd->idd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 break;
Helge Dellerffd51f42007-02-28 23:51:29 -0500111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 case HIL_CMD_RSC:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700113 buf = kbd->rsc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 break;
Helge Dellerffd51f42007-02-28 23:51:29 -0500115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 case HIL_CMD_EXD:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700117 buf = kbd->exd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 break;
Helge Dellerffd51f42007-02-28 23:51:29 -0500119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 case HIL_CMD_RNM:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700121 kbd->rnm[HIL_KBD_MAX_LENGTH] = 0;
122 buf = kbd->rnm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 break;
Helge Dellerffd51f42007-02-28 23:51:29 -0500124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 default:
126 /* These occur when device isn't present */
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700127 if (p != (HIL_ERR_INT | HIL_PKT_CMD)) {
128 /* Anything else we'd like to know about. */
129 printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
130 }
131 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700134 for (i = 0; i < idx; i++)
135 buf[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
136 for (; i < HIL_KBD_MAX_LENGTH; i++)
137 buf[i] = 0;
138 out:
139 complete(&kbd->cmd_done);
140}
141
142static void hil_kbd_handle_key_events(struct hil_kbd *kbd)
143{
144 struct input_dev *dev = kbd->dev;
145 int idx = kbd->idx4 / 4;
146 int i;
147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
149 case HIL_POL_CHARTYPE_NONE:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700150 return;
Helge Dellerffd51f42007-02-28 23:51:29 -0500151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 case HIL_POL_CHARTYPE_ASCII:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700153 for (i = 1; i < idx - 1; i++)
154 input_report_key(dev, kbd->data[i] & 0x7f, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 break;
Helge Dellerffd51f42007-02-28 23:51:29 -0500156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 case HIL_POL_CHARTYPE_RSVD1:
158 case HIL_POL_CHARTYPE_RSVD2:
159 case HIL_POL_CHARTYPE_BINARY:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700160 for (i = 1; i < idx - 1; i++)
161 input_report_key(dev, kbd->data[i], 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 break;
Helge Dellerffd51f42007-02-28 23:51:29 -0500163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 case HIL_POL_CHARTYPE_SET1:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700165 for (i = 1; i < idx - 1; i++) {
166 unsigned int key = kbd->data[i];
167 int up = key & HIL_KBD_SET1_UPBIT;
168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 key &= (~HIL_KBD_SET1_UPBIT & 0xff);
170 key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT];
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700171 input_report_key(dev, key, !up);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 }
173 break;
Helge Dellerffd51f42007-02-28 23:51:29 -0500174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 case HIL_POL_CHARTYPE_SET2:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700176 for (i = 1; i < idx - 1; i++) {
177 unsigned int key = kbd->data[i];
178 int up = key & HIL_KBD_SET2_UPBIT;
179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 key &= (~HIL_KBD_SET1_UPBIT & 0xff);
181 key = key >> HIL_KBD_SET2_SHIFT;
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700182 input_report_key(dev, key, !up);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 }
184 break;
Helge Dellerffd51f42007-02-28 23:51:29 -0500185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 case HIL_POL_CHARTYPE_SET3:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700187 for (i = 1; i < idx - 1; i++) {
188 unsigned int key = kbd->data[i];
189 int up = key & HIL_KBD_SET3_UPBIT;
190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 key &= (~HIL_KBD_SET1_UPBIT & 0xff);
192 key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT];
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700193 input_report_key(dev, key, !up);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 }
195 break;
196 }
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700197
198 input_sync(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
Helge Dellerffd51f42007-02-28 23:51:29 -0500201static void hil_kbd_process_err(struct hil_kbd *kbd)
202{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 printk(KERN_WARNING PREFIX "errored HIL packet\n");
204 kbd->idx4 = 0;
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700205 complete(&kbd->cmd_done); /* just in case somebody is waiting */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206}
207
Helge Dellerffd51f42007-02-28 23:51:29 -0500208static irqreturn_t hil_kbd_interrupt(struct serio *serio,
209 unsigned char data, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
211 struct hil_kbd *kbd;
212 hil_packet packet;
213 int idx;
214
Matthew Wilcox6ab0f5c2005-10-21 22:58:51 -0400215 kbd = serio_get_drvdata(serio);
Helge Dellerffd51f42007-02-28 23:51:29 -0500216 BUG_ON(kbd == NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700218 if (kbd->idx4 >= HIL_KBD_MAX_LENGTH * sizeof(hil_packet)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 hil_kbd_process_err(kbd);
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700220 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 }
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700222
223 idx = kbd->idx4 / 4;
Helge Dellerffd51f42007-02-28 23:51:29 -0500224 if (!(kbd->idx4 % 4))
225 kbd->data[idx] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 packet = kbd->data[idx];
227 packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
228 kbd->data[idx] = packet;
229
230 /* Records of N 4-byte hil_packets must terminate with a command. */
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700231 if ((++kbd->idx4 % 4) == 0) {
232 if ((packet & 0xffff0000) != HIL_ERR_INT) {
233 hil_kbd_process_err(kbd);
234 } else if (packet & HIL_PKT_CMD) {
235 if (hil_kbd_is_command_response(packet))
236 hil_kbd_handle_command_response(kbd);
237 else
238 hil_kbd_handle_key_events(kbd);
239 kbd->idx4 = 0;
240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 }
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700242 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 return IRQ_HANDLED;
244}
245
246static void hil_kbd_disconnect(struct serio *serio)
247{
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700248 struct hil_kbd *kbd = serio_get_drvdata(serio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Helge Dellerffd51f42007-02-28 23:51:29 -0500250 BUG_ON(kbd == NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 serio_close(serio);
Kyle McMartincd7a9202006-03-30 11:47:32 -0500253 input_unregister_device(kbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 kfree(kbd);
255}
256
Matthew Wilcox6ab0f5c2005-10-21 22:58:51 -0400257static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258{
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700259 struct hil_kbd *kbd;
260 struct input_dev *input_dev;
261 uint8_t did, *idd;
262 int i;
263 int error;
Dmitry Torokhov95d465f2006-04-02 00:08:05 -0500264
Eric Sesterhennb39787a2006-03-14 00:09:16 -0500265 kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700266 input_dev = input_allocate_device();
267 if (!kbd || !input_dev) {
268 error = -ENOMEM;
269 goto bail0;
270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700272 kbd->serio = serio;
273 kbd->dev = input_dev;
274
275 error = serio_open(serio, drv);
276 if (error)
Dmitry Torokhov95d465f2006-04-02 00:08:05 -0500277 goto bail0;
278
Matthew Wilcox6ab0f5c2005-10-21 22:58:51 -0400279 serio_set_drvdata(serio, kbd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281 /* Get device info. MLC driver supplies devid/status/etc. */
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700282 init_completion(&kbd->cmd_done);
Dmitry Torokhovdd0d5442009-08-05 00:30:26 -0700283 serio_write(serio, 0);
284 serio_write(serio, 0);
285 serio_write(serio, HIL_PKT_CMD >> 8);
286 serio_write(serio, HIL_CMD_IDD);
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700287 error = wait_for_completion_killable(&kbd->cmd_done);
288 if (error)
289 goto bail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700291 init_completion(&kbd->cmd_done);
Dmitry Torokhovdd0d5442009-08-05 00:30:26 -0700292 serio_write(serio, 0);
293 serio_write(serio, 0);
294 serio_write(serio, HIL_PKT_CMD >> 8);
295 serio_write(serio, HIL_CMD_RSC);
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700296 error = wait_for_completion_killable(&kbd->cmd_done);
297 if (error)
298 goto bail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700300 init_completion(&kbd->cmd_done);
Dmitry Torokhovdd0d5442009-08-05 00:30:26 -0700301 serio_write(serio, 0);
302 serio_write(serio, 0);
303 serio_write(serio, HIL_PKT_CMD >> 8);
304 serio_write(serio, HIL_CMD_RNM);
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700305 error = wait_for_completion_killable(&kbd->cmd_done);
306 if (error)
307 goto bail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700309 init_completion(&kbd->cmd_done);
Dmitry Torokhovdd0d5442009-08-05 00:30:26 -0700310 serio_write(serio, 0);
311 serio_write(serio, 0);
312 serio_write(serio, HIL_PKT_CMD >> 8);
313 serio_write(serio, HIL_CMD_EXD);
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700314 error = wait_for_completion_killable(&kbd->cmd_done);
315 if (error)
316 goto bail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 did = kbd->idd[0];
319 idd = kbd->idd + 1;
320 switch (did & HIL_IDD_DID_TYPE_MASK) {
321 case HIL_IDD_DID_TYPE_KB_INTEGRAL:
322 case HIL_IDD_DID_TYPE_KB_ITF:
323 case HIL_IDD_DID_TYPE_KB_RSVD:
324 case HIL_IDD_DID_TYPE_CHAR:
325 printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n",
326 did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
327 break;
328 default:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700329 goto bail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 }
331
Helge Dellerffd51f42007-02-28 23:51:29 -0500332 if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700334 goto bail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
336
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700337 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
338 input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
339 BIT_MASK(LED_SCROLLL);
340 input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
341 input_dev->keycodesize = sizeof(hil_kbd_set1[0]);
342 input_dev->keycode = hil_kbd_set1;
343 input_dev->name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
344 input_dev->phys = "hpkbd/input0"; /* XXX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700346 input_dev->id.bustype = BUS_HIL;
347 input_dev->id.vendor = PCI_VENDOR_ID_HP;
348 input_dev->id.product = 0x0001; /* TODO: get from kbd->rsc */
349 input_dev->id.version = 0x0100; /* TODO: get from kbd->rsc */
350 input_dev->dev.parent = &serio->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
352 for (i = 0; i < 128; i++) {
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700353 __set_bit(hil_kbd_set1[i], input_dev->keybit);
354 __set_bit(hil_kbd_set3[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 }
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700356 __clear_bit(KEY_RESERVED, input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Dmitry Torokhovdd0d5442009-08-05 00:30:26 -0700358 serio_write(serio, 0);
359 serio_write(serio, 0);
360 serio_write(serio, HIL_PKT_CMD >> 8);
361 serio_write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700362 /* No need to wait for completion */
363
364 error = input_register_device(kbd->dev);
365 if (error)
366 goto bail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Matthew Wilcox6ab0f5c2005-10-21 22:58:51 -0400368 return 0;
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700369
370 bail1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 serio_close(serio);
Matthew Wilcoxd668da82006-04-03 13:44:17 +0000372 serio_set_drvdata(serio, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 bail0:
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700374 input_free_device(input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 kfree(kbd);
Dmitry Torokhov6777f012009-08-07 23:17:46 -0700376 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
378
Matthew Wilcox6ab0f5c2005-10-21 22:58:51 -0400379static struct serio_device_id hil_kbd_ids[] = {
380 {
381 .type = SERIO_HIL_MLC,
382 .proto = SERIO_HIL,
383 .id = SERIO_ANY,
384 .extra = SERIO_ANY,
385 },
386 { 0 }
387};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Helge Deller3acaf542007-02-28 23:51:19 -0500389static struct serio_driver hil_kbd_serio_drv = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 .driver = {
391 .name = "hil_kbd",
392 },
393 .description = "HP HIL keyboard driver",
Matthew Wilcox6ab0f5c2005-10-21 22:58:51 -0400394 .id_table = hil_kbd_ids,
Helge Dellerffd51f42007-02-28 23:51:29 -0500395 .connect = hil_kbd_connect,
396 .disconnect = hil_kbd_disconnect,
397 .interrupt = hil_kbd_interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398};
399
400static int __init hil_kbd_init(void)
401{
Akinobu Mita153a9df02006-11-23 23:35:10 -0500402 return serio_register_driver(&hil_kbd_serio_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
Helge Dellerffd51f42007-02-28 23:51:29 -0500404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405static void __exit hil_kbd_exit(void)
406{
407 serio_unregister_driver(&hil_kbd_serio_drv);
408}
Helge Dellerffd51f42007-02-28 23:51:29 -0500409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410module_init(hil_kbd_init);
411module_exit(hil_kbd_exit);