Path: blob/master/drivers/input/keyboard/hil_kbd.c
15109 views
/*1* Generic linux-input device driver for keyboard devices2*3* Copyright (c) 2001 Brian S. Julin4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions, and the following disclaimer,11* without modification.12* 2. The name of the author may not be used to endorse or promote products13* derived from this software without specific prior written permission.14*15* Alternatively, this software may be distributed under the terms of the16* GNU General Public License ("GPL").17*18* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND19* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR22* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL23* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS24* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)25* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT26* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY27*28* References:29* HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A30*31*/3233#include <linux/hil.h>34#include <linux/input.h>35#include <linux/serio.h>36#include <linux/kernel.h>37#include <linux/module.h>38#include <linux/init.h>39#include <linux/completion.h>40#include <linux/slab.h>41#include <linux/pci_ids.h>4243#define PREFIX "HIL: "4445MODULE_AUTHOR("Brian S. Julin <[email protected]>");46MODULE_DESCRIPTION("HIL keyboard/mouse driver");47MODULE_LICENSE("Dual BSD/GPL");48MODULE_ALIAS("serio:ty03pr25id00ex*"); /* HIL keyboard */49MODULE_ALIAS("serio:ty03pr25id0Fex*"); /* HIL mouse */5051#define HIL_PACKET_MAX_LENGTH 165253#define HIL_KBD_SET1_UPBIT 0x0154#define HIL_KBD_SET1_SHIFT 155static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =56{ HIL_KEYCODES_SET1 };5758#define HIL_KBD_SET2_UPBIT 0x0159#define HIL_KBD_SET2_SHIFT 160/* Set2 is user defined */6162#define HIL_KBD_SET3_UPBIT 0x8063#define HIL_KBD_SET3_SHIFT 064static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly =65{ HIL_KEYCODES_SET3 };6667static const char hil_language[][16] = { HIL_LOCALE_MAP };6869struct hil_dev {70struct input_dev *dev;71struct serio *serio;7273/* Input buffer and index for packets from HIL bus. */74hil_packet data[HIL_PACKET_MAX_LENGTH];75int idx4; /* four counts per packet */7677/* Raw device info records from HIL bus, see hil.h for fields. */78char idd[HIL_PACKET_MAX_LENGTH]; /* DID byte and IDD record */79char rsc[HIL_PACKET_MAX_LENGTH]; /* RSC record */80char exd[HIL_PACKET_MAX_LENGTH]; /* EXD record */81char rnm[HIL_PACKET_MAX_LENGTH + 1]; /* RNM record + NULL term. */8283struct completion cmd_done;8485bool is_pointer;86/* Extra device details needed for pointing devices. */87unsigned int nbtn, naxes;88unsigned int btnmap[7];89};9091static bool hil_dev_is_command_response(hil_packet p)92{93if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))94return false;9596if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))97return false;9899return true;100}101102static void hil_dev_handle_command_response(struct hil_dev *dev)103{104hil_packet p;105char *buf;106int i, idx;107108idx = dev->idx4 / 4;109p = dev->data[idx - 1];110111switch (p & HIL_PKT_DATA_MASK) {112case HIL_CMD_IDD:113buf = dev->idd;114break;115116case HIL_CMD_RSC:117buf = dev->rsc;118break;119120case HIL_CMD_EXD:121buf = dev->exd;122break;123124case HIL_CMD_RNM:125dev->rnm[HIL_PACKET_MAX_LENGTH] = 0;126buf = dev->rnm;127break;128129default:130/* These occur when device isn't present */131if (p != (HIL_ERR_INT | HIL_PKT_CMD)) {132/* Anything else we'd like to know about. */133printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);134}135goto out;136}137138for (i = 0; i < idx; i++)139buf[i] = dev->data[i] & HIL_PKT_DATA_MASK;140for (; i < HIL_PACKET_MAX_LENGTH; i++)141buf[i] = 0;142out:143complete(&dev->cmd_done);144}145146static void hil_dev_handle_kbd_events(struct hil_dev *kbd)147{148struct input_dev *dev = kbd->dev;149int idx = kbd->idx4 / 4;150int i;151152switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {153case HIL_POL_CHARTYPE_NONE:154return;155156case HIL_POL_CHARTYPE_ASCII:157for (i = 1; i < idx - 1; i++)158input_report_key(dev, kbd->data[i] & 0x7f, 1);159break;160161case HIL_POL_CHARTYPE_RSVD1:162case HIL_POL_CHARTYPE_RSVD2:163case HIL_POL_CHARTYPE_BINARY:164for (i = 1; i < idx - 1; i++)165input_report_key(dev, kbd->data[i], 1);166break;167168case HIL_POL_CHARTYPE_SET1:169for (i = 1; i < idx - 1; i++) {170unsigned int key = kbd->data[i];171int up = key & HIL_KBD_SET1_UPBIT;172173key &= (~HIL_KBD_SET1_UPBIT & 0xff);174key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT];175input_report_key(dev, key, !up);176}177break;178179case HIL_POL_CHARTYPE_SET2:180for (i = 1; i < idx - 1; i++) {181unsigned int key = kbd->data[i];182int up = key & HIL_KBD_SET2_UPBIT;183184key &= (~HIL_KBD_SET1_UPBIT & 0xff);185key = key >> HIL_KBD_SET2_SHIFT;186input_report_key(dev, key, !up);187}188break;189190case HIL_POL_CHARTYPE_SET3:191for (i = 1; i < idx - 1; i++) {192unsigned int key = kbd->data[i];193int up = key & HIL_KBD_SET3_UPBIT;194195key &= (~HIL_KBD_SET1_UPBIT & 0xff);196key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT];197input_report_key(dev, key, !up);198}199break;200}201202input_sync(dev);203}204205static void hil_dev_handle_ptr_events(struct hil_dev *ptr)206{207struct input_dev *dev = ptr->dev;208int idx = ptr->idx4 / 4;209hil_packet p = ptr->data[idx - 1];210int i, cnt, laxis;211bool absdev, ax16;212213if ((p & HIL_CMDCT_POL) != idx - 1) {214printk(KERN_WARNING PREFIX215"Malformed poll packet %x (idx = %i)\n", p, idx);216return;217}218219i = (p & HIL_POL_AXIS_ALT) ? 3 : 0;220laxis = (p & HIL_POL_NUM_AXES_MASK) + i;221222ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */223absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;224225for (cnt = 1; i < laxis; i++) {226unsigned int lo, hi, val;227228lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK;229hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0;230231if (absdev) {232val = lo + (hi << 8);233#ifdef TABLET_AUTOADJUST234if (val < input_abs_get_min(dev, ABS_X + i))235input_abs_set_min(dev, ABS_X + i, val);236if (val > input_abs_get_max(dev, ABS_X + i))237input_abs_set_max(dev, ABS_X + i, val);238#endif239if (i % 3)240val = input_abs_get_max(dev, ABS_X + i) - val;241input_report_abs(dev, ABS_X + i, val);242} else {243val = (int) (((int8_t) lo) | ((int8_t) hi << 8));244if (i % 3)245val *= -1;246input_report_rel(dev, REL_X + i, val);247}248}249250while (cnt < idx - 1) {251unsigned int btn = ptr->data[cnt++];252int up = btn & 1;253254btn &= 0xfe;255if (btn == 0x8e)256continue; /* TODO: proximity == touch? */257if (btn > 0x8c || btn < 0x80)258continue;259btn = (btn - 0x80) >> 1;260btn = ptr->btnmap[btn];261input_report_key(dev, btn, !up);262}263264input_sync(dev);265}266267static void hil_dev_process_err(struct hil_dev *dev)268{269printk(KERN_WARNING PREFIX "errored HIL packet\n");270dev->idx4 = 0;271complete(&dev->cmd_done); /* just in case somebody is waiting */272}273274static irqreturn_t hil_dev_interrupt(struct serio *serio,275unsigned char data, unsigned int flags)276{277struct hil_dev *dev;278hil_packet packet;279int idx;280281dev = serio_get_drvdata(serio);282BUG_ON(dev == NULL);283284if (dev->idx4 >= HIL_PACKET_MAX_LENGTH * sizeof(hil_packet)) {285hil_dev_process_err(dev);286goto out;287}288289idx = dev->idx4 / 4;290if (!(dev->idx4 % 4))291dev->data[idx] = 0;292packet = dev->data[idx];293packet |= ((hil_packet)data) << ((3 - (dev->idx4 % 4)) * 8);294dev->data[idx] = packet;295296/* Records of N 4-byte hil_packets must terminate with a command. */297if ((++dev->idx4 % 4) == 0) {298if ((packet & 0xffff0000) != HIL_ERR_INT) {299hil_dev_process_err(dev);300} else if (packet & HIL_PKT_CMD) {301if (hil_dev_is_command_response(packet))302hil_dev_handle_command_response(dev);303else if (dev->is_pointer)304hil_dev_handle_ptr_events(dev);305else306hil_dev_handle_kbd_events(dev);307dev->idx4 = 0;308}309}310out:311return IRQ_HANDLED;312}313314static void hil_dev_disconnect(struct serio *serio)315{316struct hil_dev *dev = serio_get_drvdata(serio);317318BUG_ON(dev == NULL);319320serio_close(serio);321input_unregister_device(dev->dev);322serio_set_drvdata(serio, NULL);323kfree(dev);324}325326static void hil_dev_keyboard_setup(struct hil_dev *kbd)327{328struct input_dev *input_dev = kbd->dev;329uint8_t did = kbd->idd[0];330int i;331332input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);333input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |334BIT_MASK(LED_SCROLLL);335336for (i = 0; i < 128; i++) {337__set_bit(hil_kbd_set1[i], input_dev->keybit);338__set_bit(hil_kbd_set3[i], input_dev->keybit);339}340__clear_bit(KEY_RESERVED, input_dev->keybit);341342input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;343input_dev->keycodesize = sizeof(hil_kbd_set1[0]);344input_dev->keycode = hil_kbd_set1;345346input_dev->name = strlen(kbd->rnm) ? kbd->rnm : "HIL keyboard";347input_dev->phys = "hpkbd/input0";348349printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n",350did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);351}352353static void hil_dev_pointer_setup(struct hil_dev *ptr)354{355struct input_dev *input_dev = ptr->dev;356uint8_t did = ptr->idd[0];357uint8_t *idd = ptr->idd + 1;358unsigned int naxsets = HIL_IDD_NUM_AXSETS(*idd);359unsigned int i, btntype;360const char *txt;361362ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);363364switch (did & HIL_IDD_DID_TYPE_MASK) {365case HIL_IDD_DID_TYPE_REL:366input_dev->evbit[0] = BIT_MASK(EV_REL);367368for (i = 0; i < ptr->naxes; i++)369__set_bit(REL_X + i, input_dev->relbit);370371for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++)372__set_bit(REL_X + i, input_dev->relbit);373374txt = "relative";375break;376377case HIL_IDD_DID_TYPE_ABS:378input_dev->evbit[0] = BIT_MASK(EV_ABS);379380for (i = 0; i < ptr->naxes; i++)381input_set_abs_params(input_dev, ABS_X + i,3820, HIL_IDD_AXIS_MAX(idd, i), 0, 0);383384for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++)385input_set_abs_params(input_dev, ABS_X + i,3860, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0);387388#ifdef TABLET_AUTOADJUST389for (i = 0; i < ABS_MAX; i++) {390int diff = input_abs_get_max(input_dev, ABS_X + i) / 10;391input_abs_set_min(input_dev, ABS_X + i,392input_abs_get_min(input_dev, ABS_X + i) + diff);393input_abs_set_max(input_dev, ABS_X + i,394input_abs_get_max(input_dev, ABS_X + i) - diff);395}396#endif397398txt = "absolute";399break;400401default:402BUG();403}404405ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);406if (ptr->nbtn)407input_dev->evbit[0] |= BIT_MASK(EV_KEY);408409btntype = BTN_MISC;410if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)411#ifdef TABLET_SIMULATES_MOUSE412btntype = BTN_TOUCH;413#else414btntype = BTN_DIGI;415#endif416if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)417btntype = BTN_TOUCH;418419if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)420btntype = BTN_MOUSE;421422for (i = 0; i < ptr->nbtn; i++) {423__set_bit(btntype | i, input_dev->keybit);424ptr->btnmap[i] = btntype | i;425}426427if (btntype == BTN_MOUSE) {428/* Swap buttons 2 and 3 */429ptr->btnmap[1] = BTN_MIDDLE;430ptr->btnmap[2] = BTN_RIGHT;431}432433input_dev->name = strlen(ptr->rnm) ? ptr->rnm : "HIL pointer device";434435printk(KERN_INFO PREFIX436"HIL pointer device found (did: 0x%02x, axis: %s)\n",437did, txt);438printk(KERN_INFO PREFIX439"HIL pointer has %i buttons and %i sets of %i axes\n",440ptr->nbtn, naxsets, ptr->naxes);441}442443static int hil_dev_connect(struct serio *serio, struct serio_driver *drv)444{445struct hil_dev *dev;446struct input_dev *input_dev;447uint8_t did, *idd;448int error;449450dev = kzalloc(sizeof(*dev), GFP_KERNEL);451input_dev = input_allocate_device();452if (!dev || !input_dev) {453error = -ENOMEM;454goto bail0;455}456457dev->serio = serio;458dev->dev = input_dev;459460error = serio_open(serio, drv);461if (error)462goto bail0;463464serio_set_drvdata(serio, dev);465466/* Get device info. MLC driver supplies devid/status/etc. */467init_completion(&dev->cmd_done);468serio_write(serio, 0);469serio_write(serio, 0);470serio_write(serio, HIL_PKT_CMD >> 8);471serio_write(serio, HIL_CMD_IDD);472error = wait_for_completion_killable(&dev->cmd_done);473if (error)474goto bail1;475476init_completion(&dev->cmd_done);477serio_write(serio, 0);478serio_write(serio, 0);479serio_write(serio, HIL_PKT_CMD >> 8);480serio_write(serio, HIL_CMD_RSC);481error = wait_for_completion_killable(&dev->cmd_done);482if (error)483goto bail1;484485init_completion(&dev->cmd_done);486serio_write(serio, 0);487serio_write(serio, 0);488serio_write(serio, HIL_PKT_CMD >> 8);489serio_write(serio, HIL_CMD_RNM);490error = wait_for_completion_killable(&dev->cmd_done);491if (error)492goto bail1;493494init_completion(&dev->cmd_done);495serio_write(serio, 0);496serio_write(serio, 0);497serio_write(serio, HIL_PKT_CMD >> 8);498serio_write(serio, HIL_CMD_EXD);499error = wait_for_completion_killable(&dev->cmd_done);500if (error)501goto bail1;502503did = dev->idd[0];504idd = dev->idd + 1;505506switch (did & HIL_IDD_DID_TYPE_MASK) {507case HIL_IDD_DID_TYPE_KB_INTEGRAL:508case HIL_IDD_DID_TYPE_KB_ITF:509case HIL_IDD_DID_TYPE_KB_RSVD:510case HIL_IDD_DID_TYPE_CHAR:511if (HIL_IDD_NUM_BUTTONS(idd) ||512HIL_IDD_NUM_AXES_PER_SET(*idd)) {513printk(KERN_INFO PREFIX514"combo devices are not supported.\n");515goto bail1;516}517518dev->is_pointer = false;519hil_dev_keyboard_setup(dev);520break;521522case HIL_IDD_DID_TYPE_REL:523case HIL_IDD_DID_TYPE_ABS:524dev->is_pointer = true;525hil_dev_pointer_setup(dev);526break;527528default:529goto bail1;530}531532input_dev->id.bustype = BUS_HIL;533input_dev->id.vendor = PCI_VENDOR_ID_HP;534input_dev->id.product = 0x0001; /* TODO: get from kbd->rsc */535input_dev->id.version = 0x0100; /* TODO: get from kbd->rsc */536input_dev->dev.parent = &serio->dev;537538if (!dev->is_pointer) {539serio_write(serio, 0);540serio_write(serio, 0);541serio_write(serio, HIL_PKT_CMD >> 8);542/* Enable Keyswitch Autorepeat 1 */543serio_write(serio, HIL_CMD_EK1);544/* No need to wait for completion */545}546547error = input_register_device(input_dev);548if (error)549goto bail1;550551return 0;552553bail1:554serio_close(serio);555serio_set_drvdata(serio, NULL);556bail0:557input_free_device(input_dev);558kfree(dev);559return error;560}561562static struct serio_device_id hil_dev_ids[] = {563{564.type = SERIO_HIL_MLC,565.proto = SERIO_HIL,566.id = SERIO_ANY,567.extra = SERIO_ANY,568},569{ 0 }570};571572MODULE_DEVICE_TABLE(serio, hil_dev_ids);573574static struct serio_driver hil_serio_drv = {575.driver = {576.name = "hil_dev",577},578.description = "HP HIL keyboard/mouse/tablet driver",579.id_table = hil_dev_ids,580.connect = hil_dev_connect,581.disconnect = hil_dev_disconnect,582.interrupt = hil_dev_interrupt583};584585static int __init hil_dev_init(void)586{587return serio_register_driver(&hil_serio_drv);588}589590static void __exit hil_dev_exit(void)591{592serio_unregister_driver(&hil_serio_drv);593}594595module_init(hil_dev_init);596module_exit(hil_dev_exit);597598599