11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Generic linux-input device driver for keyboard devices 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2001 Brian S. Julin 51da177e4SLinus Torvalds * All rights reserved. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or without 81da177e4SLinus Torvalds * modification, are permitted provided that the following conditions 91da177e4SLinus Torvalds * are met: 101da177e4SLinus Torvalds * 1. Redistributions of source code must retain the above copyright 111da177e4SLinus Torvalds * notice, this list of conditions, and the following disclaimer, 121da177e4SLinus Torvalds * without modification. 131da177e4SLinus Torvalds * 2. The name of the author may not be used to endorse or promote products 141da177e4SLinus Torvalds * derived from this software without specific prior written permission. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * Alternatively, this software may be distributed under the terms of the 171da177e4SLinus Torvalds * GNU General Public License ("GPL"). 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 201da177e4SLinus Torvalds * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 211da177e4SLinus Torvalds * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 221da177e4SLinus Torvalds * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 231da177e4SLinus Torvalds * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 241da177e4SLinus Torvalds * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 251da177e4SLinus Torvalds * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 261da177e4SLinus Torvalds * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 271da177e4SLinus Torvalds * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 281da177e4SLinus Torvalds * 291da177e4SLinus Torvalds * References: 301da177e4SLinus Torvalds * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A 311da177e4SLinus Torvalds * 321da177e4SLinus Torvalds */ 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds #include <linux/hil.h> 351da177e4SLinus Torvalds #include <linux/input.h> 361da177e4SLinus Torvalds #include <linux/serio.h> 371da177e4SLinus Torvalds #include <linux/kernel.h> 381da177e4SLinus Torvalds #include <linux/module.h> 391da177e4SLinus Torvalds #include <linux/init.h> 406777f017SDmitry Torokhov #include <linux/completion.h> 411da177e4SLinus Torvalds #include <linux/slab.h> 421da177e4SLinus Torvalds #include <linux/pci_ids.h> 431da177e4SLinus Torvalds 44fa71c605SDmitry Torokhov #define PREFIX "HIL: " 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); 47fa71c605SDmitry Torokhov MODULE_DESCRIPTION("HIL keyboard/mouse driver"); 481da177e4SLinus Torvalds MODULE_LICENSE("Dual BSD/GPL"); 49fa71c605SDmitry Torokhov MODULE_ALIAS("serio:ty03pr25id00ex*"); /* HIL keyboard */ 50fa71c605SDmitry Torokhov MODULE_ALIAS("serio:ty03pr25id0Fex*"); /* HIL mouse */ 511da177e4SLinus Torvalds 521437dc30SDmitry Torokhov #define HIL_PACKET_MAX_LENGTH 16 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds #define HIL_KBD_SET1_UPBIT 0x01 551da177e4SLinus Torvalds #define HIL_KBD_SET1_SHIFT 1 563acaf540SHelge Deller static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly = 571da177e4SLinus Torvalds { HIL_KEYCODES_SET1 }; 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds #define HIL_KBD_SET2_UPBIT 0x01 601da177e4SLinus Torvalds #define HIL_KBD_SET2_SHIFT 1 611da177e4SLinus Torvalds /* Set2 is user defined */ 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds #define HIL_KBD_SET3_UPBIT 0x80 641da177e4SLinus Torvalds #define HIL_KBD_SET3_SHIFT 0 653acaf540SHelge Deller static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly = 661da177e4SLinus Torvalds { HIL_KEYCODES_SET3 }; 671da177e4SLinus Torvalds 683acaf540SHelge Deller static const char hil_language[][16] = { HIL_LOCALE_MAP }; 691da177e4SLinus Torvalds 701437dc30SDmitry Torokhov struct hil_dev { 71102c8c76SHelge Deller struct input_dev *dev; 721da177e4SLinus Torvalds struct serio *serio; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds /* Input buffer and index for packets from HIL bus. */ 751437dc30SDmitry Torokhov hil_packet data[HIL_PACKET_MAX_LENGTH]; 761da177e4SLinus Torvalds int idx4; /* four counts per packet */ 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /* Raw device info records from HIL bus, see hil.h for fields. */ 791437dc30SDmitry Torokhov char idd[HIL_PACKET_MAX_LENGTH]; /* DID byte and IDD record */ 801437dc30SDmitry Torokhov char rsc[HIL_PACKET_MAX_LENGTH]; /* RSC record */ 811437dc30SDmitry Torokhov char exd[HIL_PACKET_MAX_LENGTH]; /* EXD record */ 821437dc30SDmitry Torokhov char rnm[HIL_PACKET_MAX_LENGTH + 1]; /* RNM record + NULL term. */ 831da177e4SLinus Torvalds 846777f017SDmitry Torokhov struct completion cmd_done; 85fa71c605SDmitry Torokhov 86fa71c605SDmitry Torokhov bool is_pointer; 87fa71c605SDmitry Torokhov /* Extra device details needed for pointing devices. */ 88fa71c605SDmitry Torokhov unsigned int nbtn, naxes; 89fa71c605SDmitry Torokhov unsigned int btnmap[7]; 901da177e4SLinus Torvalds }; 911da177e4SLinus Torvalds 921437dc30SDmitry Torokhov static bool hil_dev_is_command_response(hil_packet p) 931da177e4SLinus Torvalds { 946777f017SDmitry Torokhov if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) 956777f017SDmitry Torokhov return false; 966777f017SDmitry Torokhov 976777f017SDmitry Torokhov if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) 986777f017SDmitry Torokhov return false; 996777f017SDmitry Torokhov 1006777f017SDmitry Torokhov return true; 1016777f017SDmitry Torokhov } 1026777f017SDmitry Torokhov 1031437dc30SDmitry Torokhov static void hil_dev_handle_command_response(struct hil_dev *dev) 1046777f017SDmitry Torokhov { 1051da177e4SLinus Torvalds hil_packet p; 1066777f017SDmitry Torokhov char *buf; 1076777f017SDmitry Torokhov int i, idx; 1081da177e4SLinus Torvalds 1091437dc30SDmitry Torokhov idx = dev->idx4 / 4; 1101437dc30SDmitry Torokhov p = dev->data[idx - 1]; 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds switch (p & HIL_PKT_DATA_MASK) { 1131da177e4SLinus Torvalds case HIL_CMD_IDD: 1141437dc30SDmitry Torokhov buf = dev->idd; 1151da177e4SLinus Torvalds break; 116ffd51f46SHelge Deller 1171da177e4SLinus Torvalds case HIL_CMD_RSC: 1181437dc30SDmitry Torokhov buf = dev->rsc; 1191da177e4SLinus Torvalds break; 120ffd51f46SHelge Deller 1211da177e4SLinus Torvalds case HIL_CMD_EXD: 1221437dc30SDmitry Torokhov buf = dev->exd; 1231da177e4SLinus Torvalds break; 124ffd51f46SHelge Deller 1251da177e4SLinus Torvalds case HIL_CMD_RNM: 1261437dc30SDmitry Torokhov dev->rnm[HIL_PACKET_MAX_LENGTH] = 0; 1271437dc30SDmitry Torokhov buf = dev->rnm; 1281da177e4SLinus Torvalds break; 129ffd51f46SHelge Deller 1301da177e4SLinus Torvalds default: 1311da177e4SLinus Torvalds /* These occur when device isn't present */ 1326777f017SDmitry Torokhov if (p != (HIL_ERR_INT | HIL_PKT_CMD)) { 1331da177e4SLinus Torvalds /* Anything else we'd like to know about. */ 1341da177e4SLinus Torvalds printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds goto out; 1376777f017SDmitry Torokhov } 1381da177e4SLinus Torvalds 1396777f017SDmitry Torokhov for (i = 0; i < idx; i++) 1401437dc30SDmitry Torokhov buf[i] = dev->data[i] & HIL_PKT_DATA_MASK; 1411437dc30SDmitry Torokhov for (; i < HIL_PACKET_MAX_LENGTH; i++) 1426777f017SDmitry Torokhov buf[i] = 0; 1436777f017SDmitry Torokhov out: 1441437dc30SDmitry Torokhov complete(&dev->cmd_done); 1456777f017SDmitry Torokhov } 1466777f017SDmitry Torokhov 147fa71c605SDmitry Torokhov static void hil_dev_handle_kbd_events(struct hil_dev *kbd) 1486777f017SDmitry Torokhov { 1496777f017SDmitry Torokhov struct input_dev *dev = kbd->dev; 1506777f017SDmitry Torokhov int idx = kbd->idx4 / 4; 1516777f017SDmitry Torokhov int i; 1526777f017SDmitry Torokhov 1531da177e4SLinus Torvalds switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) { 1541da177e4SLinus Torvalds case HIL_POL_CHARTYPE_NONE: 1556777f017SDmitry Torokhov return; 156ffd51f46SHelge Deller 1571da177e4SLinus Torvalds case HIL_POL_CHARTYPE_ASCII: 1586777f017SDmitry Torokhov for (i = 1; i < idx - 1; i++) 1596777f017SDmitry Torokhov input_report_key(dev, kbd->data[i] & 0x7f, 1); 1601da177e4SLinus Torvalds break; 161ffd51f46SHelge Deller 1621da177e4SLinus Torvalds case HIL_POL_CHARTYPE_RSVD1: 1631da177e4SLinus Torvalds case HIL_POL_CHARTYPE_RSVD2: 1641da177e4SLinus Torvalds case HIL_POL_CHARTYPE_BINARY: 1656777f017SDmitry Torokhov for (i = 1; i < idx - 1; i++) 1666777f017SDmitry Torokhov input_report_key(dev, kbd->data[i], 1); 1671da177e4SLinus Torvalds break; 168ffd51f46SHelge Deller 1691da177e4SLinus Torvalds case HIL_POL_CHARTYPE_SET1: 1706777f017SDmitry Torokhov for (i = 1; i < idx - 1; i++) { 1716777f017SDmitry Torokhov unsigned int key = kbd->data[i]; 1726777f017SDmitry Torokhov int up = key & HIL_KBD_SET1_UPBIT; 1736777f017SDmitry Torokhov 1741da177e4SLinus Torvalds key &= (~HIL_KBD_SET1_UPBIT & 0xff); 1751da177e4SLinus Torvalds key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT]; 1761da177e4SLinus Torvalds input_report_key(dev, key, !up); 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds break; 179ffd51f46SHelge Deller 1801da177e4SLinus Torvalds case HIL_POL_CHARTYPE_SET2: 1816777f017SDmitry Torokhov for (i = 1; i < idx - 1; i++) { 1826777f017SDmitry Torokhov unsigned int key = kbd->data[i]; 1836777f017SDmitry Torokhov int up = key & HIL_KBD_SET2_UPBIT; 1846777f017SDmitry Torokhov 1851da177e4SLinus Torvalds key &= (~HIL_KBD_SET1_UPBIT & 0xff); 1861da177e4SLinus Torvalds key = key >> HIL_KBD_SET2_SHIFT; 1871da177e4SLinus Torvalds input_report_key(dev, key, !up); 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds break; 190ffd51f46SHelge Deller 1911da177e4SLinus Torvalds case HIL_POL_CHARTYPE_SET3: 1926777f017SDmitry Torokhov for (i = 1; i < idx - 1; i++) { 1936777f017SDmitry Torokhov unsigned int key = kbd->data[i]; 1946777f017SDmitry Torokhov int up = key & HIL_KBD_SET3_UPBIT; 1956777f017SDmitry Torokhov 1961da177e4SLinus Torvalds key &= (~HIL_KBD_SET1_UPBIT & 0xff); 1971da177e4SLinus Torvalds key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT]; 1981da177e4SLinus Torvalds input_report_key(dev, key, !up); 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds break; 2011da177e4SLinus Torvalds } 2026777f017SDmitry Torokhov 2036777f017SDmitry Torokhov input_sync(dev); 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 206fa71c605SDmitry Torokhov static void hil_dev_handle_ptr_events(struct hil_dev *ptr) 207fa71c605SDmitry Torokhov { 208fa71c605SDmitry Torokhov struct input_dev *dev = ptr->dev; 209fa71c605SDmitry Torokhov int idx = ptr->idx4 / 4; 210fa71c605SDmitry Torokhov hil_packet p = ptr->data[idx - 1]; 211fa71c605SDmitry Torokhov int i, cnt, laxis; 212fa71c605SDmitry Torokhov bool absdev, ax16; 213fa71c605SDmitry Torokhov 214fa71c605SDmitry Torokhov if ((p & HIL_CMDCT_POL) != idx - 1) { 215fa71c605SDmitry Torokhov printk(KERN_WARNING PREFIX 216fa71c605SDmitry Torokhov "Malformed poll packet %x (idx = %i)\n", p, idx); 217fa71c605SDmitry Torokhov return; 218fa71c605SDmitry Torokhov } 219fa71c605SDmitry Torokhov 220fa71c605SDmitry Torokhov i = (p & HIL_POL_AXIS_ALT) ? 3 : 0; 221fa71c605SDmitry Torokhov laxis = (p & HIL_POL_NUM_AXES_MASK) + i; 222fa71c605SDmitry Torokhov 223fa71c605SDmitry Torokhov ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ 224fa71c605SDmitry Torokhov absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; 225fa71c605SDmitry Torokhov 226fa71c605SDmitry Torokhov for (cnt = 1; i < laxis; i++) { 227fa71c605SDmitry Torokhov unsigned int lo, hi, val; 228fa71c605SDmitry Torokhov 229fa71c605SDmitry Torokhov lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK; 230fa71c605SDmitry Torokhov hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0; 231fa71c605SDmitry Torokhov 232fa71c605SDmitry Torokhov if (absdev) { 233fa71c605SDmitry Torokhov val = lo + (hi << 8); 234fa71c605SDmitry Torokhov #ifdef TABLET_AUTOADJUST 235fa71c605SDmitry Torokhov if (val < dev->absmin[ABS_X + i]) 236fa71c605SDmitry Torokhov dev->absmin[ABS_X + i] = val; 237fa71c605SDmitry Torokhov if (val > dev->absmax[ABS_X + i]) 238fa71c605SDmitry Torokhov dev->absmax[ABS_X + i] = val; 239fa71c605SDmitry Torokhov #endif 240fa71c605SDmitry Torokhov if (i%3) val = dev->absmax[ABS_X + i] - val; 241fa71c605SDmitry Torokhov input_report_abs(dev, ABS_X + i, val); 242fa71c605SDmitry Torokhov } else { 243fa71c605SDmitry Torokhov val = (int) (((int8_t)lo) | ((int8_t)hi << 8)); 244fa71c605SDmitry Torokhov if (i % 3) 245fa71c605SDmitry Torokhov val *= -1; 246fa71c605SDmitry Torokhov input_report_rel(dev, REL_X + i, val); 247fa71c605SDmitry Torokhov } 248fa71c605SDmitry Torokhov } 249fa71c605SDmitry Torokhov 250fa71c605SDmitry Torokhov while (cnt < idx - 1) { 251fa71c605SDmitry Torokhov unsigned int btn = ptr->data[cnt++]; 252fa71c605SDmitry Torokhov int up = btn & 1; 253fa71c605SDmitry Torokhov 254fa71c605SDmitry Torokhov btn &= 0xfe; 255fa71c605SDmitry Torokhov if (btn == 0x8e) 256fa71c605SDmitry Torokhov continue; /* TODO: proximity == touch? */ 257fa71c605SDmitry Torokhov if (btn > 0x8c || btn < 0x80) 258fa71c605SDmitry Torokhov continue; 259fa71c605SDmitry Torokhov btn = (btn - 0x80) >> 1; 260fa71c605SDmitry Torokhov btn = ptr->btnmap[btn]; 261fa71c605SDmitry Torokhov input_report_key(dev, btn, !up); 262fa71c605SDmitry Torokhov } 263fa71c605SDmitry Torokhov 264fa71c605SDmitry Torokhov input_sync(dev); 265fa71c605SDmitry Torokhov } 266fa71c605SDmitry Torokhov 2671437dc30SDmitry Torokhov static void hil_dev_process_err(struct hil_dev *dev) 268ffd51f46SHelge Deller { 2691da177e4SLinus Torvalds printk(KERN_WARNING PREFIX "errored HIL packet\n"); 2701437dc30SDmitry Torokhov dev->idx4 = 0; 2711437dc30SDmitry Torokhov complete(&dev->cmd_done); /* just in case somebody is waiting */ 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds 2741437dc30SDmitry Torokhov static irqreturn_t hil_dev_interrupt(struct serio *serio, 2757d12e780SDavid Howells unsigned char data, unsigned int flags) 2761da177e4SLinus Torvalds { 2771437dc30SDmitry Torokhov struct hil_dev *dev; 2781da177e4SLinus Torvalds hil_packet packet; 2791da177e4SLinus Torvalds int idx; 2801da177e4SLinus Torvalds 2811437dc30SDmitry Torokhov dev = serio_get_drvdata(serio); 2821437dc30SDmitry Torokhov BUG_ON(dev == NULL); 2831da177e4SLinus Torvalds 2841437dc30SDmitry Torokhov if (dev->idx4 >= HIL_PACKET_MAX_LENGTH * sizeof(hil_packet)) { 2851437dc30SDmitry Torokhov hil_dev_process_err(dev); 2866777f017SDmitry Torokhov goto out; 2871da177e4SLinus Torvalds } 2886777f017SDmitry Torokhov 2891437dc30SDmitry Torokhov idx = dev->idx4 / 4; 2901437dc30SDmitry Torokhov if (!(dev->idx4 % 4)) 2911437dc30SDmitry Torokhov dev->data[idx] = 0; 2921437dc30SDmitry Torokhov packet = dev->data[idx]; 2931437dc30SDmitry Torokhov packet |= ((hil_packet)data) << ((3 - (dev->idx4 % 4)) * 8); 2941437dc30SDmitry Torokhov dev->data[idx] = packet; 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds /* Records of N 4-byte hil_packets must terminate with a command. */ 2971437dc30SDmitry Torokhov if ((++dev->idx4 % 4) == 0) { 2981da177e4SLinus Torvalds if ((packet & 0xffff0000) != HIL_ERR_INT) { 2991437dc30SDmitry Torokhov hil_dev_process_err(dev); 3006777f017SDmitry Torokhov } else if (packet & HIL_PKT_CMD) { 3011437dc30SDmitry Torokhov if (hil_dev_is_command_response(packet)) 3021437dc30SDmitry Torokhov hil_dev_handle_command_response(dev); 303fa71c605SDmitry Torokhov else if (dev->is_pointer) 304fa71c605SDmitry Torokhov hil_dev_handle_ptr_events(dev); 3056777f017SDmitry Torokhov else 306fa71c605SDmitry Torokhov hil_dev_handle_kbd_events(dev); 3071437dc30SDmitry Torokhov dev->idx4 = 0; 3081da177e4SLinus Torvalds } 3096777f017SDmitry Torokhov } 3106777f017SDmitry Torokhov out: 3111da177e4SLinus Torvalds return IRQ_HANDLED; 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 3141437dc30SDmitry Torokhov static void hil_dev_disconnect(struct serio *serio) 3151da177e4SLinus Torvalds { 3161437dc30SDmitry Torokhov struct hil_dev *dev = serio_get_drvdata(serio); 3171da177e4SLinus Torvalds 3181437dc30SDmitry Torokhov BUG_ON(dev == NULL); 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds serio_close(serio); 3211437dc30SDmitry Torokhov input_unregister_device(dev->dev); 322fa71c605SDmitry Torokhov serio_set_drvdata(serio, NULL); 3231437dc30SDmitry Torokhov kfree(dev); 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 326fa71c605SDmitry Torokhov static void hil_dev_keyboard_setup(struct hil_dev *kbd) 327fa71c605SDmitry Torokhov { 328fa71c605SDmitry Torokhov struct input_dev *input_dev = kbd->dev; 329fa71c605SDmitry Torokhov uint8_t did = kbd->idd[0]; 330fa71c605SDmitry Torokhov int i; 331fa71c605SDmitry Torokhov 332fa71c605SDmitry Torokhov input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 333fa71c605SDmitry Torokhov input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | 334fa71c605SDmitry Torokhov BIT_MASK(LED_SCROLLL); 335fa71c605SDmitry Torokhov 336fa71c605SDmitry Torokhov for (i = 0; i < 128; i++) { 337fa71c605SDmitry Torokhov __set_bit(hil_kbd_set1[i], input_dev->keybit); 338fa71c605SDmitry Torokhov __set_bit(hil_kbd_set3[i], input_dev->keybit); 339fa71c605SDmitry Torokhov } 340fa71c605SDmitry Torokhov __clear_bit(KEY_RESERVED, input_dev->keybit); 341fa71c605SDmitry Torokhov 342fa71c605SDmitry Torokhov input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; 343fa71c605SDmitry Torokhov input_dev->keycodesize = sizeof(hil_kbd_set1[0]); 344fa71c605SDmitry Torokhov input_dev->keycode = hil_kbd_set1; 345fa71c605SDmitry Torokhov 346fa71c605SDmitry Torokhov input_dev->name = strlen(kbd->rnm) ? kbd->rnm : "HIL keyboard"; 347fa71c605SDmitry Torokhov input_dev->phys = "hpkbd/input0"; 348fa71c605SDmitry Torokhov 349fa71c605SDmitry Torokhov printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", 350fa71c605SDmitry Torokhov did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); 351fa71c605SDmitry Torokhov } 352fa71c605SDmitry Torokhov 353fa71c605SDmitry Torokhov static void hil_dev_pointer_setup(struct hil_dev *ptr) 354fa71c605SDmitry Torokhov { 355fa71c605SDmitry Torokhov struct input_dev *input_dev = ptr->dev; 356fa71c605SDmitry Torokhov uint8_t did = ptr->idd[0]; 357fa71c605SDmitry Torokhov uint8_t *idd = ptr->idd + 1; 358fa71c605SDmitry Torokhov unsigned int naxsets = HIL_IDD_NUM_AXSETS(*idd); 359fa71c605SDmitry Torokhov unsigned int i, btntype; 360fa71c605SDmitry Torokhov const char *txt; 361fa71c605SDmitry Torokhov 362fa71c605SDmitry Torokhov ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); 363fa71c605SDmitry Torokhov 364fa71c605SDmitry Torokhov switch (did & HIL_IDD_DID_TYPE_MASK) { 365fa71c605SDmitry Torokhov case HIL_IDD_DID_TYPE_REL: 366fa71c605SDmitry Torokhov input_dev->evbit[0] = BIT_MASK(EV_REL); 367fa71c605SDmitry Torokhov 368fa71c605SDmitry Torokhov for (i = 0; i < ptr->naxes; i++) 369fa71c605SDmitry Torokhov __set_bit(REL_X + i, input_dev->relbit); 370fa71c605SDmitry Torokhov 371fa71c605SDmitry Torokhov for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) 372fa71c605SDmitry Torokhov __set_bit(REL_X + i, input_dev->relbit); 373fa71c605SDmitry Torokhov 374fa71c605SDmitry Torokhov txt = "relative"; 375fa71c605SDmitry Torokhov break; 376fa71c605SDmitry Torokhov 377fa71c605SDmitry Torokhov case HIL_IDD_DID_TYPE_ABS: 378fa71c605SDmitry Torokhov input_dev->evbit[0] = BIT_MASK(EV_ABS); 379fa71c605SDmitry Torokhov 380fa71c605SDmitry Torokhov for (i = 0; i < ptr->naxes; i++) 381fa71c605SDmitry Torokhov input_set_abs_params(input_dev, ABS_X + i, 382fa71c605SDmitry Torokhov 0, HIL_IDD_AXIS_MAX(idd, i), 0, 0); 383fa71c605SDmitry Torokhov 384fa71c605SDmitry Torokhov for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) 385fa71c605SDmitry Torokhov input_set_abs_params(input_dev, ABS_X + i, 386fa71c605SDmitry Torokhov 0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0); 387fa71c605SDmitry Torokhov 388fa71c605SDmitry Torokhov #ifdef TABLET_AUTOADJUST 389fa71c605SDmitry Torokhov for (i = 0; i < ABS_MAX; i++) { 390fa71c605SDmitry Torokhov int diff = input_dev->absmax[ABS_X + i] / 10; 391fa71c605SDmitry Torokhov input_dev->absmin[ABS_X + i] += diff; 392fa71c605SDmitry Torokhov input_dev->absmax[ABS_X + i] -= diff; 393fa71c605SDmitry Torokhov } 394fa71c605SDmitry Torokhov #endif 395fa71c605SDmitry Torokhov 396fa71c605SDmitry Torokhov txt = "absolute"; 397fa71c605SDmitry Torokhov break; 398fa71c605SDmitry Torokhov 399fa71c605SDmitry Torokhov default: 400fa71c605SDmitry Torokhov BUG(); 401fa71c605SDmitry Torokhov } 402fa71c605SDmitry Torokhov 403fa71c605SDmitry Torokhov ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); 404fa71c605SDmitry Torokhov if (ptr->nbtn) 405fa71c605SDmitry Torokhov input_dev->evbit[0] |= BIT_MASK(EV_KEY); 406fa71c605SDmitry Torokhov 407fa71c605SDmitry Torokhov btntype = BTN_MISC; 408fa71c605SDmitry Torokhov if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) 409fa71c605SDmitry Torokhov #ifdef TABLET_SIMULATES_MOUSE 410fa71c605SDmitry Torokhov btntype = BTN_TOUCH; 411fa71c605SDmitry Torokhov #else 412fa71c605SDmitry Torokhov btntype = BTN_DIGI; 413fa71c605SDmitry Torokhov #endif 414fa71c605SDmitry Torokhov if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) 415fa71c605SDmitry Torokhov btntype = BTN_TOUCH; 416fa71c605SDmitry Torokhov 417fa71c605SDmitry Torokhov if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) 418fa71c605SDmitry Torokhov btntype = BTN_MOUSE; 419fa71c605SDmitry Torokhov 420fa71c605SDmitry Torokhov for (i = 0; i < ptr->nbtn; i++) { 421fa71c605SDmitry Torokhov __set_bit(btntype | i, input_dev->keybit); 422fa71c605SDmitry Torokhov ptr->btnmap[i] = btntype | i; 423fa71c605SDmitry Torokhov } 424fa71c605SDmitry Torokhov 425fa71c605SDmitry Torokhov if (btntype == BTN_MOUSE) { 426fa71c605SDmitry Torokhov /* Swap buttons 2 and 3 */ 427fa71c605SDmitry Torokhov ptr->btnmap[1] = BTN_MIDDLE; 428fa71c605SDmitry Torokhov ptr->btnmap[2] = BTN_RIGHT; 429fa71c605SDmitry Torokhov } 430fa71c605SDmitry Torokhov 431fa71c605SDmitry Torokhov input_dev->name = strlen(ptr->rnm) ? ptr->rnm : "HIL pointer device"; 432fa71c605SDmitry Torokhov 433fa71c605SDmitry Torokhov printk(KERN_INFO PREFIX 434fa71c605SDmitry Torokhov "HIL pointer device found (did: 0x%02x, axis: %s)\n", 435fa71c605SDmitry Torokhov did, txt); 436fa71c605SDmitry Torokhov printk(KERN_INFO PREFIX 437fa71c605SDmitry Torokhov "HIL pointer has %i buttons and %i sets of %i axes\n", 438fa71c605SDmitry Torokhov ptr->nbtn, naxsets, ptr->naxes); 439fa71c605SDmitry Torokhov } 440fa71c605SDmitry Torokhov 4411437dc30SDmitry Torokhov static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) 4421da177e4SLinus Torvalds { 4431437dc30SDmitry Torokhov struct hil_dev *dev; 4446777f017SDmitry Torokhov struct input_dev *input_dev; 4451da177e4SLinus Torvalds uint8_t did, *idd; 4466777f017SDmitry Torokhov int error; 4471da177e4SLinus Torvalds 4481437dc30SDmitry Torokhov dev = kzalloc(sizeof(*dev), GFP_KERNEL); 4496777f017SDmitry Torokhov input_dev = input_allocate_device(); 4501437dc30SDmitry Torokhov if (!dev || !input_dev) { 4516777f017SDmitry Torokhov error = -ENOMEM; 4526777f017SDmitry Torokhov goto bail0; 4536777f017SDmitry Torokhov } 4541da177e4SLinus Torvalds 4551437dc30SDmitry Torokhov dev->serio = serio; 4561437dc30SDmitry Torokhov dev->dev = input_dev; 4576777f017SDmitry Torokhov 4586777f017SDmitry Torokhov error = serio_open(serio, drv); 4596777f017SDmitry Torokhov if (error) 46095d465fdSDmitry Torokhov goto bail0; 46195d465fdSDmitry Torokhov 4621437dc30SDmitry Torokhov serio_set_drvdata(serio, dev); 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds /* Get device info. MLC driver supplies devid/status/etc. */ 4651437dc30SDmitry Torokhov init_completion(&dev->cmd_done); 466dd0d5443SDmitry Torokhov serio_write(serio, 0); 467dd0d5443SDmitry Torokhov serio_write(serio, 0); 468dd0d5443SDmitry Torokhov serio_write(serio, HIL_PKT_CMD >> 8); 469dd0d5443SDmitry Torokhov serio_write(serio, HIL_CMD_IDD); 4701437dc30SDmitry Torokhov error = wait_for_completion_killable(&dev->cmd_done); 4716777f017SDmitry Torokhov if (error) 4726777f017SDmitry Torokhov goto bail1; 4731da177e4SLinus Torvalds 4741437dc30SDmitry Torokhov init_completion(&dev->cmd_done); 475dd0d5443SDmitry Torokhov serio_write(serio, 0); 476dd0d5443SDmitry Torokhov serio_write(serio, 0); 477dd0d5443SDmitry Torokhov serio_write(serio, HIL_PKT_CMD >> 8); 478dd0d5443SDmitry Torokhov serio_write(serio, HIL_CMD_RSC); 4791437dc30SDmitry Torokhov error = wait_for_completion_killable(&dev->cmd_done); 4806777f017SDmitry Torokhov if (error) 4816777f017SDmitry Torokhov goto bail1; 4821da177e4SLinus Torvalds 4831437dc30SDmitry Torokhov init_completion(&dev->cmd_done); 484dd0d5443SDmitry Torokhov serio_write(serio, 0); 485dd0d5443SDmitry Torokhov serio_write(serio, 0); 486dd0d5443SDmitry Torokhov serio_write(serio, HIL_PKT_CMD >> 8); 487dd0d5443SDmitry Torokhov serio_write(serio, HIL_CMD_RNM); 4881437dc30SDmitry Torokhov error = wait_for_completion_killable(&dev->cmd_done); 4896777f017SDmitry Torokhov if (error) 4906777f017SDmitry Torokhov goto bail1; 4911da177e4SLinus Torvalds 4921437dc30SDmitry Torokhov init_completion(&dev->cmd_done); 493dd0d5443SDmitry Torokhov serio_write(serio, 0); 494dd0d5443SDmitry Torokhov serio_write(serio, 0); 495dd0d5443SDmitry Torokhov serio_write(serio, HIL_PKT_CMD >> 8); 496dd0d5443SDmitry Torokhov serio_write(serio, HIL_CMD_EXD); 4971437dc30SDmitry Torokhov error = wait_for_completion_killable(&dev->cmd_done); 4986777f017SDmitry Torokhov if (error) 4996777f017SDmitry Torokhov goto bail1; 5001da177e4SLinus Torvalds 5011437dc30SDmitry Torokhov did = dev->idd[0]; 5021437dc30SDmitry Torokhov idd = dev->idd + 1; 503fa71c605SDmitry Torokhov 5041da177e4SLinus Torvalds switch (did & HIL_IDD_DID_TYPE_MASK) { 5051da177e4SLinus Torvalds case HIL_IDD_DID_TYPE_KB_INTEGRAL: 5061da177e4SLinus Torvalds case HIL_IDD_DID_TYPE_KB_ITF: 5071da177e4SLinus Torvalds case HIL_IDD_DID_TYPE_KB_RSVD: 5081da177e4SLinus Torvalds case HIL_IDD_DID_TYPE_CHAR: 509fa71c605SDmitry Torokhov if (HIL_IDD_NUM_BUTTONS(idd) || 510fa71c605SDmitry Torokhov HIL_IDD_NUM_AXES_PER_SET(*idd)) { 511fa71c605SDmitry Torokhov printk(KERN_INFO PREFIX 512fa71c605SDmitry Torokhov "combo devices are not supported.\n"); 513fa71c605SDmitry Torokhov goto bail1; 514fa71c605SDmitry Torokhov } 515fa71c605SDmitry Torokhov 516fa71c605SDmitry Torokhov dev->is_pointer = false; 517fa71c605SDmitry Torokhov hil_dev_keyboard_setup(dev); 5181da177e4SLinus Torvalds break; 519fa71c605SDmitry Torokhov 520fa71c605SDmitry Torokhov case HIL_IDD_DID_TYPE_REL: 521fa71c605SDmitry Torokhov case HIL_IDD_DID_TYPE_ABS: 522fa71c605SDmitry Torokhov dev->is_pointer = true; 523fa71c605SDmitry Torokhov hil_dev_pointer_setup(dev); 524fa71c605SDmitry Torokhov break; 525fa71c605SDmitry Torokhov 5261da177e4SLinus Torvalds default: 5276777f017SDmitry Torokhov goto bail1; 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 5306777f017SDmitry Torokhov input_dev->id.bustype = BUS_HIL; 5316777f017SDmitry Torokhov input_dev->id.vendor = PCI_VENDOR_ID_HP; 5326777f017SDmitry Torokhov input_dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ 5336777f017SDmitry Torokhov input_dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ 5346777f017SDmitry Torokhov input_dev->dev.parent = &serio->dev; 5351da177e4SLinus Torvalds 536fa71c605SDmitry Torokhov if (!dev->is_pointer) { 537dd0d5443SDmitry Torokhov serio_write(serio, 0); 538dd0d5443SDmitry Torokhov serio_write(serio, 0); 539dd0d5443SDmitry Torokhov serio_write(serio, HIL_PKT_CMD >> 8); 540fa71c605SDmitry Torokhov /* Enable Keyswitch Autorepeat 1 */ 541fa71c605SDmitry Torokhov serio_write(serio, HIL_CMD_EK1); 5426777f017SDmitry Torokhov /* No need to wait for completion */ 543fa71c605SDmitry Torokhov } 5446777f017SDmitry Torokhov 5451437dc30SDmitry Torokhov error = input_register_device(input_dev); 5466777f017SDmitry Torokhov if (error) 5476777f017SDmitry Torokhov goto bail1; 5481da177e4SLinus Torvalds 5496ab0f5cdSMatthew Wilcox return 0; 5506777f017SDmitry Torokhov 5516777f017SDmitry Torokhov bail1: 5521da177e4SLinus Torvalds serio_close(serio); 553d668da80SMatthew Wilcox serio_set_drvdata(serio, NULL); 5541da177e4SLinus Torvalds bail0: 5556777f017SDmitry Torokhov input_free_device(input_dev); 5561437dc30SDmitry Torokhov kfree(dev); 5576777f017SDmitry Torokhov return error; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds 5601437dc30SDmitry Torokhov static struct serio_device_id hil_dev_ids[] = { 5616ab0f5cdSMatthew Wilcox { 5626ab0f5cdSMatthew Wilcox .type = SERIO_HIL_MLC, 5636ab0f5cdSMatthew Wilcox .proto = SERIO_HIL, 5646ab0f5cdSMatthew Wilcox .id = SERIO_ANY, 5656ab0f5cdSMatthew Wilcox .extra = SERIO_ANY, 5666ab0f5cdSMatthew Wilcox }, 5676ab0f5cdSMatthew Wilcox { 0 } 5686ab0f5cdSMatthew Wilcox }; 5691da177e4SLinus Torvalds 5701437dc30SDmitry Torokhov static struct serio_driver hil_serio_drv = { 5711da177e4SLinus Torvalds .driver = { 572fa71c605SDmitry Torokhov .name = "hil_dev", 5731da177e4SLinus Torvalds }, 574fa71c605SDmitry Torokhov .description = "HP HIL keyboard/mouse/tablet driver", 5751437dc30SDmitry Torokhov .id_table = hil_dev_ids, 5761437dc30SDmitry Torokhov .connect = hil_dev_connect, 5771437dc30SDmitry Torokhov .disconnect = hil_dev_disconnect, 5781437dc30SDmitry Torokhov .interrupt = hil_dev_interrupt 5791da177e4SLinus Torvalds }; 5801da177e4SLinus Torvalds 5811437dc30SDmitry Torokhov static int __init hil_dev_init(void) 5821da177e4SLinus Torvalds { 5831437dc30SDmitry Torokhov return serio_register_driver(&hil_serio_drv); 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds 5861437dc30SDmitry Torokhov static void __exit hil_dev_exit(void) 5871da177e4SLinus Torvalds { 5881437dc30SDmitry Torokhov serio_unregister_driver(&hil_serio_drv); 5891da177e4SLinus Torvalds } 5901da177e4SLinus Torvalds 5911437dc30SDmitry Torokhov module_init(hil_dev_init); 5921437dc30SDmitry Torokhov module_exit(hil_dev_exit); 593