Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/keyboard/hil_kbd.c
15109 views
1
/*
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>
40
#include <linux/completion.h>
41
#include <linux/slab.h>
42
#include <linux/pci_ids.h>
43
44
#define PREFIX "HIL: "
45
46
MODULE_AUTHOR("Brian S. Julin <[email protected]>");
47
MODULE_DESCRIPTION("HIL keyboard/mouse driver");
48
MODULE_LICENSE("Dual BSD/GPL");
49
MODULE_ALIAS("serio:ty03pr25id00ex*"); /* HIL keyboard */
50
MODULE_ALIAS("serio:ty03pr25id0Fex*"); /* HIL mouse */
51
52
#define HIL_PACKET_MAX_LENGTH 16
53
54
#define HIL_KBD_SET1_UPBIT 0x01
55
#define HIL_KBD_SET1_SHIFT 1
56
static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
57
{ 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
65
static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly =
66
{ HIL_KEYCODES_SET3 };
67
68
static const char hil_language[][16] = { HIL_LOCALE_MAP };
69
70
struct hil_dev {
71
struct input_dev *dev;
72
struct serio *serio;
73
74
/* Input buffer and index for packets from HIL bus. */
75
hil_packet data[HIL_PACKET_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_PACKET_MAX_LENGTH]; /* DID byte and IDD record */
80
char rsc[HIL_PACKET_MAX_LENGTH]; /* RSC record */
81
char exd[HIL_PACKET_MAX_LENGTH]; /* EXD record */
82
char rnm[HIL_PACKET_MAX_LENGTH + 1]; /* RNM record + NULL term. */
83
84
struct completion cmd_done;
85
86
bool is_pointer;
87
/* Extra device details needed for pointing devices. */
88
unsigned int nbtn, naxes;
89
unsigned int btnmap[7];
90
};
91
92
static bool hil_dev_is_command_response(hil_packet p)
93
{
94
if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
95
return false;
96
97
if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
98
return false;
99
100
return true;
101
}
102
103
static void hil_dev_handle_command_response(struct hil_dev *dev)
104
{
105
hil_packet p;
106
char *buf;
107
int i, idx;
108
109
idx = dev->idx4 / 4;
110
p = dev->data[idx - 1];
111
112
switch (p & HIL_PKT_DATA_MASK) {
113
case HIL_CMD_IDD:
114
buf = dev->idd;
115
break;
116
117
case HIL_CMD_RSC:
118
buf = dev->rsc;
119
break;
120
121
case HIL_CMD_EXD:
122
buf = dev->exd;
123
break;
124
125
case HIL_CMD_RNM:
126
dev->rnm[HIL_PACKET_MAX_LENGTH] = 0;
127
buf = dev->rnm;
128
break;
129
130
default:
131
/* These occur when device isn't present */
132
if (p != (HIL_ERR_INT | HIL_PKT_CMD)) {
133
/* Anything else we'd like to know about. */
134
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
135
}
136
goto out;
137
}
138
139
for (i = 0; i < idx; i++)
140
buf[i] = dev->data[i] & HIL_PKT_DATA_MASK;
141
for (; i < HIL_PACKET_MAX_LENGTH; i++)
142
buf[i] = 0;
143
out:
144
complete(&dev->cmd_done);
145
}
146
147
static void hil_dev_handle_kbd_events(struct hil_dev *kbd)
148
{
149
struct input_dev *dev = kbd->dev;
150
int idx = kbd->idx4 / 4;
151
int i;
152
153
switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
154
case HIL_POL_CHARTYPE_NONE:
155
return;
156
157
case HIL_POL_CHARTYPE_ASCII:
158
for (i = 1; i < idx - 1; i++)
159
input_report_key(dev, kbd->data[i] & 0x7f, 1);
160
break;
161
162
case HIL_POL_CHARTYPE_RSVD1:
163
case HIL_POL_CHARTYPE_RSVD2:
164
case HIL_POL_CHARTYPE_BINARY:
165
for (i = 1; i < idx - 1; i++)
166
input_report_key(dev, kbd->data[i], 1);
167
break;
168
169
case HIL_POL_CHARTYPE_SET1:
170
for (i = 1; i < idx - 1; i++) {
171
unsigned int key = kbd->data[i];
172
int up = key & HIL_KBD_SET1_UPBIT;
173
174
key &= (~HIL_KBD_SET1_UPBIT & 0xff);
175
key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT];
176
input_report_key(dev, key, !up);
177
}
178
break;
179
180
case HIL_POL_CHARTYPE_SET2:
181
for (i = 1; i < idx - 1; i++) {
182
unsigned int key = kbd->data[i];
183
int up = key & HIL_KBD_SET2_UPBIT;
184
185
key &= (~HIL_KBD_SET1_UPBIT & 0xff);
186
key = key >> HIL_KBD_SET2_SHIFT;
187
input_report_key(dev, key, !up);
188
}
189
break;
190
191
case HIL_POL_CHARTYPE_SET3:
192
for (i = 1; i < idx - 1; i++) {
193
unsigned int key = kbd->data[i];
194
int up = key & HIL_KBD_SET3_UPBIT;
195
196
key &= (~HIL_KBD_SET1_UPBIT & 0xff);
197
key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT];
198
input_report_key(dev, key, !up);
199
}
200
break;
201
}
202
203
input_sync(dev);
204
}
205
206
static void hil_dev_handle_ptr_events(struct hil_dev *ptr)
207
{
208
struct input_dev *dev = ptr->dev;
209
int idx = ptr->idx4 / 4;
210
hil_packet p = ptr->data[idx - 1];
211
int i, cnt, laxis;
212
bool absdev, ax16;
213
214
if ((p & HIL_CMDCT_POL) != idx - 1) {
215
printk(KERN_WARNING PREFIX
216
"Malformed poll packet %x (idx = %i)\n", p, idx);
217
return;
218
}
219
220
i = (p & HIL_POL_AXIS_ALT) ? 3 : 0;
221
laxis = (p & HIL_POL_NUM_AXES_MASK) + i;
222
223
ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
224
absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
225
226
for (cnt = 1; i < laxis; i++) {
227
unsigned int lo, hi, val;
228
229
lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK;
230
hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0;
231
232
if (absdev) {
233
val = lo + (hi << 8);
234
#ifdef TABLET_AUTOADJUST
235
if (val < input_abs_get_min(dev, ABS_X + i))
236
input_abs_set_min(dev, ABS_X + i, val);
237
if (val > input_abs_get_max(dev, ABS_X + i))
238
input_abs_set_max(dev, ABS_X + i, val);
239
#endif
240
if (i % 3)
241
val = input_abs_get_max(dev, ABS_X + i) - val;
242
input_report_abs(dev, ABS_X + i, val);
243
} else {
244
val = (int) (((int8_t) lo) | ((int8_t) hi << 8));
245
if (i % 3)
246
val *= -1;
247
input_report_rel(dev, REL_X + i, val);
248
}
249
}
250
251
while (cnt < idx - 1) {
252
unsigned int btn = ptr->data[cnt++];
253
int up = btn & 1;
254
255
btn &= 0xfe;
256
if (btn == 0x8e)
257
continue; /* TODO: proximity == touch? */
258
if (btn > 0x8c || btn < 0x80)
259
continue;
260
btn = (btn - 0x80) >> 1;
261
btn = ptr->btnmap[btn];
262
input_report_key(dev, btn, !up);
263
}
264
265
input_sync(dev);
266
}
267
268
static void hil_dev_process_err(struct hil_dev *dev)
269
{
270
printk(KERN_WARNING PREFIX "errored HIL packet\n");
271
dev->idx4 = 0;
272
complete(&dev->cmd_done); /* just in case somebody is waiting */
273
}
274
275
static irqreturn_t hil_dev_interrupt(struct serio *serio,
276
unsigned char data, unsigned int flags)
277
{
278
struct hil_dev *dev;
279
hil_packet packet;
280
int idx;
281
282
dev = serio_get_drvdata(serio);
283
BUG_ON(dev == NULL);
284
285
if (dev->idx4 >= HIL_PACKET_MAX_LENGTH * sizeof(hil_packet)) {
286
hil_dev_process_err(dev);
287
goto out;
288
}
289
290
idx = dev->idx4 / 4;
291
if (!(dev->idx4 % 4))
292
dev->data[idx] = 0;
293
packet = dev->data[idx];
294
packet |= ((hil_packet)data) << ((3 - (dev->idx4 % 4)) * 8);
295
dev->data[idx] = packet;
296
297
/* Records of N 4-byte hil_packets must terminate with a command. */
298
if ((++dev->idx4 % 4) == 0) {
299
if ((packet & 0xffff0000) != HIL_ERR_INT) {
300
hil_dev_process_err(dev);
301
} else if (packet & HIL_PKT_CMD) {
302
if (hil_dev_is_command_response(packet))
303
hil_dev_handle_command_response(dev);
304
else if (dev->is_pointer)
305
hil_dev_handle_ptr_events(dev);
306
else
307
hil_dev_handle_kbd_events(dev);
308
dev->idx4 = 0;
309
}
310
}
311
out:
312
return IRQ_HANDLED;
313
}
314
315
static void hil_dev_disconnect(struct serio *serio)
316
{
317
struct hil_dev *dev = serio_get_drvdata(serio);
318
319
BUG_ON(dev == NULL);
320
321
serio_close(serio);
322
input_unregister_device(dev->dev);
323
serio_set_drvdata(serio, NULL);
324
kfree(dev);
325
}
326
327
static void hil_dev_keyboard_setup(struct hil_dev *kbd)
328
{
329
struct input_dev *input_dev = kbd->dev;
330
uint8_t did = kbd->idd[0];
331
int i;
332
333
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
334
input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
335
BIT_MASK(LED_SCROLLL);
336
337
for (i = 0; i < 128; i++) {
338
__set_bit(hil_kbd_set1[i], input_dev->keybit);
339
__set_bit(hil_kbd_set3[i], input_dev->keybit);
340
}
341
__clear_bit(KEY_RESERVED, input_dev->keybit);
342
343
input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
344
input_dev->keycodesize = sizeof(hil_kbd_set1[0]);
345
input_dev->keycode = hil_kbd_set1;
346
347
input_dev->name = strlen(kbd->rnm) ? kbd->rnm : "HIL keyboard";
348
input_dev->phys = "hpkbd/input0";
349
350
printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n",
351
did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
352
}
353
354
static void hil_dev_pointer_setup(struct hil_dev *ptr)
355
{
356
struct input_dev *input_dev = ptr->dev;
357
uint8_t did = ptr->idd[0];
358
uint8_t *idd = ptr->idd + 1;
359
unsigned int naxsets = HIL_IDD_NUM_AXSETS(*idd);
360
unsigned int i, btntype;
361
const char *txt;
362
363
ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
364
365
switch (did & HIL_IDD_DID_TYPE_MASK) {
366
case HIL_IDD_DID_TYPE_REL:
367
input_dev->evbit[0] = BIT_MASK(EV_REL);
368
369
for (i = 0; i < ptr->naxes; i++)
370
__set_bit(REL_X + i, input_dev->relbit);
371
372
for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++)
373
__set_bit(REL_X + i, input_dev->relbit);
374
375
txt = "relative";
376
break;
377
378
case HIL_IDD_DID_TYPE_ABS:
379
input_dev->evbit[0] = BIT_MASK(EV_ABS);
380
381
for (i = 0; i < ptr->naxes; i++)
382
input_set_abs_params(input_dev, ABS_X + i,
383
0, HIL_IDD_AXIS_MAX(idd, i), 0, 0);
384
385
for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++)
386
input_set_abs_params(input_dev, ABS_X + i,
387
0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0);
388
389
#ifdef TABLET_AUTOADJUST
390
for (i = 0; i < ABS_MAX; i++) {
391
int diff = input_abs_get_max(input_dev, ABS_X + i) / 10;
392
input_abs_set_min(input_dev, ABS_X + i,
393
input_abs_get_min(input_dev, ABS_X + i) + diff);
394
input_abs_set_max(input_dev, ABS_X + i,
395
input_abs_get_max(input_dev, ABS_X + i) - diff);
396
}
397
#endif
398
399
txt = "absolute";
400
break;
401
402
default:
403
BUG();
404
}
405
406
ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
407
if (ptr->nbtn)
408
input_dev->evbit[0] |= BIT_MASK(EV_KEY);
409
410
btntype = BTN_MISC;
411
if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
412
#ifdef TABLET_SIMULATES_MOUSE
413
btntype = BTN_TOUCH;
414
#else
415
btntype = BTN_DIGI;
416
#endif
417
if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
418
btntype = BTN_TOUCH;
419
420
if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
421
btntype = BTN_MOUSE;
422
423
for (i = 0; i < ptr->nbtn; i++) {
424
__set_bit(btntype | i, input_dev->keybit);
425
ptr->btnmap[i] = btntype | i;
426
}
427
428
if (btntype == BTN_MOUSE) {
429
/* Swap buttons 2 and 3 */
430
ptr->btnmap[1] = BTN_MIDDLE;
431
ptr->btnmap[2] = BTN_RIGHT;
432
}
433
434
input_dev->name = strlen(ptr->rnm) ? ptr->rnm : "HIL pointer device";
435
436
printk(KERN_INFO PREFIX
437
"HIL pointer device found (did: 0x%02x, axis: %s)\n",
438
did, txt);
439
printk(KERN_INFO PREFIX
440
"HIL pointer has %i buttons and %i sets of %i axes\n",
441
ptr->nbtn, naxsets, ptr->naxes);
442
}
443
444
static int hil_dev_connect(struct serio *serio, struct serio_driver *drv)
445
{
446
struct hil_dev *dev;
447
struct input_dev *input_dev;
448
uint8_t did, *idd;
449
int error;
450
451
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
452
input_dev = input_allocate_device();
453
if (!dev || !input_dev) {
454
error = -ENOMEM;
455
goto bail0;
456
}
457
458
dev->serio = serio;
459
dev->dev = input_dev;
460
461
error = serio_open(serio, drv);
462
if (error)
463
goto bail0;
464
465
serio_set_drvdata(serio, dev);
466
467
/* Get device info. MLC driver supplies devid/status/etc. */
468
init_completion(&dev->cmd_done);
469
serio_write(serio, 0);
470
serio_write(serio, 0);
471
serio_write(serio, HIL_PKT_CMD >> 8);
472
serio_write(serio, HIL_CMD_IDD);
473
error = wait_for_completion_killable(&dev->cmd_done);
474
if (error)
475
goto bail1;
476
477
init_completion(&dev->cmd_done);
478
serio_write(serio, 0);
479
serio_write(serio, 0);
480
serio_write(serio, HIL_PKT_CMD >> 8);
481
serio_write(serio, HIL_CMD_RSC);
482
error = wait_for_completion_killable(&dev->cmd_done);
483
if (error)
484
goto bail1;
485
486
init_completion(&dev->cmd_done);
487
serio_write(serio, 0);
488
serio_write(serio, 0);
489
serio_write(serio, HIL_PKT_CMD >> 8);
490
serio_write(serio, HIL_CMD_RNM);
491
error = wait_for_completion_killable(&dev->cmd_done);
492
if (error)
493
goto bail1;
494
495
init_completion(&dev->cmd_done);
496
serio_write(serio, 0);
497
serio_write(serio, 0);
498
serio_write(serio, HIL_PKT_CMD >> 8);
499
serio_write(serio, HIL_CMD_EXD);
500
error = wait_for_completion_killable(&dev->cmd_done);
501
if (error)
502
goto bail1;
503
504
did = dev->idd[0];
505
idd = dev->idd + 1;
506
507
switch (did & HIL_IDD_DID_TYPE_MASK) {
508
case HIL_IDD_DID_TYPE_KB_INTEGRAL:
509
case HIL_IDD_DID_TYPE_KB_ITF:
510
case HIL_IDD_DID_TYPE_KB_RSVD:
511
case HIL_IDD_DID_TYPE_CHAR:
512
if (HIL_IDD_NUM_BUTTONS(idd) ||
513
HIL_IDD_NUM_AXES_PER_SET(*idd)) {
514
printk(KERN_INFO PREFIX
515
"combo devices are not supported.\n");
516
goto bail1;
517
}
518
519
dev->is_pointer = false;
520
hil_dev_keyboard_setup(dev);
521
break;
522
523
case HIL_IDD_DID_TYPE_REL:
524
case HIL_IDD_DID_TYPE_ABS:
525
dev->is_pointer = true;
526
hil_dev_pointer_setup(dev);
527
break;
528
529
default:
530
goto bail1;
531
}
532
533
input_dev->id.bustype = BUS_HIL;
534
input_dev->id.vendor = PCI_VENDOR_ID_HP;
535
input_dev->id.product = 0x0001; /* TODO: get from kbd->rsc */
536
input_dev->id.version = 0x0100; /* TODO: get from kbd->rsc */
537
input_dev->dev.parent = &serio->dev;
538
539
if (!dev->is_pointer) {
540
serio_write(serio, 0);
541
serio_write(serio, 0);
542
serio_write(serio, HIL_PKT_CMD >> 8);
543
/* Enable Keyswitch Autorepeat 1 */
544
serio_write(serio, HIL_CMD_EK1);
545
/* No need to wait for completion */
546
}
547
548
error = input_register_device(input_dev);
549
if (error)
550
goto bail1;
551
552
return 0;
553
554
bail1:
555
serio_close(serio);
556
serio_set_drvdata(serio, NULL);
557
bail0:
558
input_free_device(input_dev);
559
kfree(dev);
560
return error;
561
}
562
563
static struct serio_device_id hil_dev_ids[] = {
564
{
565
.type = SERIO_HIL_MLC,
566
.proto = SERIO_HIL,
567
.id = SERIO_ANY,
568
.extra = SERIO_ANY,
569
},
570
{ 0 }
571
};
572
573
MODULE_DEVICE_TABLE(serio, hil_dev_ids);
574
575
static struct serio_driver hil_serio_drv = {
576
.driver = {
577
.name = "hil_dev",
578
},
579
.description = "HP HIL keyboard/mouse/tablet driver",
580
.id_table = hil_dev_ids,
581
.connect = hil_dev_connect,
582
.disconnect = hil_dev_disconnect,
583
.interrupt = hil_dev_interrupt
584
};
585
586
static int __init hil_dev_init(void)
587
{
588
return serio_register_driver(&hil_serio_drv);
589
}
590
591
static void __exit hil_dev_exit(void)
592
{
593
serio_unregister_driver(&hil_serio_drv);
594
}
595
596
module_init(hil_dev_init);
597
module_exit(hil_dev_exit);
598
599