aboutsummaryrefslogtreecommitdiff
path: root/drivers/input/keyboard
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-13 21:16:56 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-13 21:16:56 -0700
commitfc8e1ead9314cf0e0f1922e661428b93d3a50d88 (patch)
treef3cb97c4769b74f6627a59769f1ed5c92a13c58a /drivers/input/keyboard
parent2bcaa6a4238094c5695d5b1943078388d82d3004 (diff)
parent9de48cc300fb10f7d9faa978670becf5e352462a (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r--drivers/input/keyboard/Kconfig26
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/atkbd.c43
-rw-r--r--drivers/input/keyboard/bf54x-keys.c26
-rw-r--r--drivers/input/keyboard/gpio_keys.c19
-rw-r--r--drivers/input/keyboard/hil_kbd.c607
-rw-r--r--drivers/input/keyboard/lkkbd.c62
-rw-r--r--drivers/input/keyboard/matrix_keypad.c15
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c217
-rw-r--r--drivers/input/keyboard/sh_keysc.c22
-rw-r--r--drivers/input/keyboard/sunkbd.c142
-rw-r--r--drivers/input/keyboard/tosakbd.c18
-rw-r--r--drivers/input/keyboard/twl4030_keypad.c480
-rw-r--r--drivers/input/keyboard/w90p910_keypad.c281
14 files changed, 1496 insertions, 464 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a6b989a9dc0..3525c19be42 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -187,7 +187,7 @@ config KEYBOARD_HIL_OLD
submenu.
config KEYBOARD_HIL
- tristate "HP HIL keyboard support"
+ tristate "HP HIL keyboard/pointer support"
depends on GSC || HP300
default y
select HP_SDC
@@ -196,7 +196,8 @@ config KEYBOARD_HIL
help
The "Human Interface Loop" is a older, 8-channel USB-like
controller used in several Hewlett Packard models.
- This driver implements support for HIL-keyboards attached
+ This driver implements support for HIL-keyboards and pointing
+ devices (mice, tablets, touchscreens) attached
to your machine, so normally you should say Y here.
config KEYBOARD_HP6XX
@@ -329,6 +330,17 @@ config KEYBOARD_OMAP
To compile this driver as a module, choose M here: the
module will be called omap-keypad.
+config KEYBOARD_TWL4030
+ tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
+ depends on TWL4030_CORE
+ help
+ Say Y here if your board use the keypad controller on
+ TWL4030 family chips. It's safe to say enable this
+ even on boards that don't use the keypad controller.
+
+ To compile this driver as a module, choose M here: the
+ module will be called twl4030_keypad.
+
config KEYBOARD_TOSA
tristate "Tosa keyboard"
depends on MACH_TOSA
@@ -361,4 +373,14 @@ config KEYBOARD_XTKBD
To compile this driver as a module, choose M here: the
module will be called xtkbd.
+config KEYBOARD_W90P910
+ tristate "W90P910 Matrix Keypad support"
+ depends on ARCH_W90X900
+ help
+ Say Y here to enable the matrix keypad on evaluation board
+ based on W90P910.
+
+ To compile this driver as a module, choose M here: the
+ module will be called w90p910_keypad.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index b5b5eae9724..8a7a22b3026 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -30,4 +30,6 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
+obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
+obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 6c6a09b1c0f..c9523e48c6a 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -68,7 +68,9 @@ MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and
* are loadable via a userland utility.
*/
-static const unsigned short atkbd_set2_keycode[512] = {
+#define ATKBD_KEYMAP_SIZE 512
+
+static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
@@ -99,7 +101,7 @@ static const unsigned short atkbd_set2_keycode[512] = {
#endif
};
-static const unsigned short atkbd_set3_keycode[512] = {
+static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = {
0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
@@ -200,8 +202,8 @@ struct atkbd {
char phys[32];
unsigned short id;
- unsigned short keycode[512];
- DECLARE_BITMAP(force_release_mask, 512);
+ unsigned short keycode[ATKBD_KEYMAP_SIZE];
+ DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
unsigned char set;
unsigned char translated;
unsigned char extra;
@@ -253,6 +255,7 @@ static struct device_attribute atkbd_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
ATKBD_DEFINE_ATTR(extra);
+ATKBD_DEFINE_ATTR(force_release);
ATKBD_DEFINE_ATTR(scroll);
ATKBD_DEFINE_ATTR(set);
ATKBD_DEFINE_ATTR(softrepeat);
@@ -272,6 +275,7 @@ ATKBD_DEFINE_RO_ATTR(err_count);
static struct attribute *atkbd_attributes[] = {
&atkbd_attr_extra.attr,
+ &atkbd_attr_force_release.attr,
&atkbd_attr_scroll.attr,
&atkbd_attr_set.attr,
&atkbd_attr_softrepeat.attr,
@@ -934,7 +938,7 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd)
int i, j;
memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
- bitmap_zero(atkbd->force_release_mask, 512);
+ bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
if (atkbd->translated) {
for (i = 0; i < 128; i++) {
@@ -1041,7 +1045,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
- for (i = 0; i < 512; i++)
+ for (i = 0; i < ATKBD_KEYMAP_SIZE; i++)
if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
__set_bit(atkbd->keycode[i], input_dev->keybit);
}
@@ -1309,6 +1313,33 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
return count;
}
+static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
+{
+ size_t len = bitmap_scnlistprintf(buf, PAGE_SIZE - 2,
+ atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
+
+ buf[len++] = '\n';
+ buf[len] = '\0';
+
+ return len;
+}
+
+static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
+ const char *buf, size_t count)
+{
+ /* 64 bytes on stack should be acceptable */
+ DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
+ int err;
+
+ err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
+ if (err)
+ return err;
+
+ memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
+ return count;
+}
+
+
static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
{
return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
index d427f322e20..fe376a27fe5 100644
--- a/drivers/input/keyboard/bf54x-keys.c
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -184,14 +184,13 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
int i, error;
if (!pdata->rows || !pdata->cols || !pdata->keymap) {
- printk(KERN_ERR DRV_NAME
- ": No rows, cols or keymap from pdata\n");
+ dev_err(&pdev->dev, "no rows, cols or keymap from pdata\n");
return -EINVAL;
}
if (!pdata->keymapsize ||
pdata->keymapsize > (pdata->rows * pdata->cols)) {
- printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n");
+ dev_err(&pdev->dev, "invalid keymapsize\n");
return -EINVAL;
}
@@ -211,8 +210,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
if (!pdata->debounce_time || pdata->debounce_time > MAX_MULT ||
!pdata->coldrive_time || pdata->coldrive_time > MAX_MULT) {
- printk(KERN_WARNING DRV_NAME
- ": Invalid Debounce/Columndrive Time in platform data\n");
+ dev_warn(&pdev->dev,
+ "invalid platform debounce/columndrive time\n");
bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */
} else {
bfin_write_KPAD_MSEL(
@@ -231,16 +230,14 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows],
DRV_NAME)) {
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
+ dev_err(&pdev->dev, "requesting peripherals failed\n");
error = -EFAULT;
goto out0;
}
if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols],
DRV_NAME)) {
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
+ dev_err(&pdev->dev, "requesting peripherals failed\n");
error = -EFAULT;
goto out1;
}
@@ -254,9 +251,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
error = request_irq(bf54x_kpad->irq, bfin_kpad_isr,
0, DRV_NAME, pdev);
if (error) {
- printk(KERN_ERR DRV_NAME
- ": unable to claim irq %d; error %d\n",
- bf54x_kpad->irq, error);
+ dev_err(&pdev->dev, "unable to claim irq %d\n",
+ bf54x_kpad->irq);
goto out2;
}
@@ -297,8 +293,7 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
error = input_register_device(input);
if (error) {
- printk(KERN_ERR DRV_NAME
- ": Unable to register input device (%d)\n", error);
+ dev_err(&pdev->dev, "unable to register input device\n");
goto out4;
}
@@ -316,9 +311,6 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- printk(KERN_ERR DRV_NAME
- ": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq);
-
return 0;
out4:
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index efed0c9e242..a88aff3816a 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -216,8 +216,9 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
-static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
+static int gpio_keys_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
@@ -234,8 +235,9 @@ static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int gpio_keys_resume(struct platform_device *pdev)
+static int gpio_keys_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
@@ -251,19 +253,22 @@ static int gpio_keys_resume(struct platform_device *pdev)
return 0;
}
-#else
-#define gpio_keys_suspend NULL
-#define gpio_keys_resume NULL
+
+static const struct dev_pm_ops gpio_keys_pm_ops = {
+ .suspend = gpio_keys_suspend,
+ .resume = gpio_keys_resume,
+};
#endif
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
- .suspend = gpio_keys_suspend,
- .resume = gpio_keys_resume,
.driver = {
.name = "gpio-keys",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &gpio_keys_pm_ops,
+#endif
}
};
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 6f356705ee3..c83f4b2ec7d 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -37,19 +37,19 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/semaphore.h>
+#include <linux/completion.h>
#include <linux/slab.h>
#include <linux/pci_ids.h>
-#define PREFIX "HIL KEYB: "
-#define HIL_GENERIC_NAME "HIL keyboard"
+#define PREFIX "HIL: "
MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
-MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
+MODULE_DESCRIPTION("HIL keyboard/mouse driver");
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("serio:ty03pr25id00ex*");
+MODULE_ALIAS("serio:ty03pr25id00ex*"); /* HIL keyboard */
+MODULE_ALIAS("serio:ty03pr25id0Fex*"); /* HIL mouse */
-#define HIL_KBD_MAX_LENGTH 16
+#define HIL_PACKET_MAX_LENGTH 16
#define HIL_KBD_SET1_UPBIT 0x01
#define HIL_KBD_SET1_SHIFT 1
@@ -67,308 +67,497 @@ static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly =
static const char hil_language[][16] = { HIL_LOCALE_MAP };
-struct hil_kbd {
+struct hil_dev {
struct input_dev *dev;
struct serio *serio;
/* Input buffer and index for packets from HIL bus. */
- hil_packet data[HIL_KBD_MAX_LENGTH];
+ hil_packet data[HIL_PACKET_MAX_LENGTH];
int idx4; /* four counts per packet */
/* Raw device info records from HIL bus, see hil.h for fields. */
- char idd[HIL_KBD_MAX_LENGTH]; /* DID byte and IDD record */
- char rsc[HIL_KBD_MAX_LENGTH]; /* RSC record */
- char exd[HIL_KBD_MAX_LENGTH]; /* EXD record */
- char rnm[HIL_KBD_MAX_LENGTH + 1]; /* RNM record + NULL term. */
+ char idd[HIL_PACKET_MAX_LENGTH]; /* DID byte and IDD record */
+ char rsc[HIL_PACKET_MAX_LENGTH]; /* RSC record */
+ char exd[HIL_PACKET_MAX_LENGTH]; /* EXD record */
+ char rnm[HIL_PACKET_MAX_LENGTH + 1]; /* RNM record + NULL term. */
- /* Something to sleep around with. */
- struct semaphore sem;
+ struct completion cmd_done;
+
+ bool is_pointer;
+ /* Extra device details needed for pointing devices. */
+ unsigned int nbtn, naxes;
+ unsigned int btnmap[7];
};
-/* Process a complete packet after transfer from the HIL */
-static void hil_kbd_process_record(struct hil_kbd *kbd)
+static bool hil_dev_is_command_response(hil_packet p)
{
- struct input_dev *dev = kbd->dev;
- hil_packet *data = kbd->data;
- hil_packet p;
- int idx, i, cnt;
+ if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
+ return false;
- idx = kbd->idx4/4;
- p = data[idx - 1];
+ if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
+ return false;
- if ((p & ~HIL_CMDCT_POL) ==
- (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
- goto report;
- if ((p & ~HIL_CMDCT_RPL) ==
- (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
- goto report;
+ return true;
+}
+
+static void hil_dev_handle_command_response(struct hil_dev *dev)
+{
+ hil_packet p;
+ char *buf;
+ int i, idx;
+
+ idx = dev->idx4 / 4;
+ p = dev->data[idx - 1];
- /* Not a poll response. See if we are loading config records. */
switch (p & HIL_PKT_DATA_MASK) {
case HIL_CMD_IDD:
- for (i = 0; i < idx; i++)
- kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
- for (; i < HIL_KBD_MAX_LENGTH; i++)
- kbd->idd[i] = 0;
+ buf = dev->idd;
break;
case HIL_CMD_RSC:
- for (i = 0; i < idx; i++)
- kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
- for (; i < HIL_KBD_MAX_LENGTH; i++)
- kbd->rsc[i] = 0;
+ buf = dev->rsc;
break;
case HIL_CMD_EXD:
- for (i = 0; i < idx; i++)
- kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
- for (; i < HIL_KBD_MAX_LENGTH; i++)
- kbd->exd[i] = 0;
+ buf = dev->exd;
break;
case HIL_CMD_RNM:
- for (i = 0; i < idx; i++)
- kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
- for (; i < HIL_KBD_MAX_LENGTH + 1; i++)
- kbd->rnm[i] = '\0';
+ dev->rnm[HIL_PACKET_MAX_LENGTH] = 0;
+ buf = dev->rnm;
break;
default:
/* These occur when device isn't present */
- if (p == (HIL_ERR_INT | HIL_PKT_CMD))
- break;
- /* Anything else we'd like to know about. */
- printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
- break;
+ if (p != (HIL_ERR_INT | HIL_PKT_CMD)) {
+ /* Anything else we'd like to know about. */
+ printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
+ }
+ goto out;
}
- goto out;
- report:
- cnt = 1;
+ for (i = 0; i < idx; i++)
+ buf[i] = dev->data[i] & HIL_PKT_DATA_MASK;
+ for (; i < HIL_PACKET_MAX_LENGTH; i++)
+ buf[i] = 0;
+ out:
+ complete(&dev->cmd_done);
+}
+
+static void hil_dev_handle_kbd_events(struct hil_dev *kbd)
+{
+ struct input_dev *dev = kbd->dev;
+ int idx = kbd->idx4 / 4;
+ int i;
+
switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
case HIL_POL_CHARTYPE_NONE:
- break;
+ return;
case HIL_POL_CHARTYPE_ASCII:
- while (cnt < idx - 1)
- input_report_key(dev, kbd->data[cnt++] & 0x7f, 1);
+ for (i = 1; i < idx - 1; i++)
+ input_report_key(dev, kbd->data[i] & 0x7f, 1);
break;
case HIL_POL_CHARTYPE_RSVD1:
case HIL_POL_CHARTYPE_RSVD2:
case HIL_POL_CHARTYPE_BINARY:
- while (cnt < idx - 1)
- input_report_key(dev, kbd->data[cnt++], 1);
+ for (i = 1; i < idx - 1; i++)
+ input_report_key(dev, kbd->data[i], 1);
break;
case HIL_POL_CHARTYPE_SET1:
- while (cnt < idx - 1) {
- unsigned int key;
- int up;
- key = kbd->data[cnt++];
- up = key & HIL_KBD_SET1_UPBIT;
+ for (i = 1; i < idx - 1; i++) {
+ unsigned int key = kbd->data[i];
+ int up = key & HIL_KBD_SET1_UPBIT;
+
key &= (~HIL_KBD_SET1_UPBIT & 0xff);
key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT];
- if (key != KEY_RESERVED)
- input_report_key(dev, key, !up);
+ input_report_key(dev, key, !up);
}
break;
case HIL_POL_CHARTYPE_SET2:
- while (cnt < idx - 1) {
- unsigned int key;
- int up;
- key = kbd->data[cnt++];
- up = key & HIL_KBD_SET2_UPBIT;
+ for (i = 1; i < idx - 1; i++) {
+ unsigned int key = kbd->data[i];
+ int up = key & HIL_KBD_SET2_UPBIT;
+
key &= (~HIL_KBD_SET1_UPBIT & 0xff);
key = key >> HIL_KBD_SET2_SHIFT;
- if (key != KEY_RESERVED)
- input_report_key(dev, key, !up);
+ input_report_key(dev, key, !up);
}
break;
case HIL_POL_CHARTYPE_SET3:
- while (cnt < idx - 1) {
- unsigned int key;
- int up;
- key = kbd->data[cnt++];
- up = key & HIL_KBD_SET3_UPBIT;
+ for (i = 1; i < idx - 1; i++) {
+ unsigned int key = kbd->data[i];
+ int up = key & HIL_KBD_SET3_UPBIT;
+
key &= (~HIL_KBD_SET1_UPBIT & 0xff);
key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT];
- if (key != KEY_RESERVED)
- input_report_key(dev, key, !up);
+ input_report_key(dev, key, !up);
}
break;
}
- out:
- kbd->idx4 = 0;
- up(&kbd->sem);
+
+ input_sync(dev);
}
-static void hil_kbd_process_err(struct hil_kbd *kbd)
+static void hil_dev_handle_ptr_events(struct hil_dev *ptr)
+{
+ struct input_dev *dev = ptr->dev;
+ int idx = ptr->idx4 / 4;
+ hil_packet p = ptr->data[idx - 1];
+ int i, cnt, laxis;
+ bool absdev, ax16;
+
+ if ((p & HIL_CMDCT_POL) != idx - 1) {
+ printk(KERN_WARNING PREFIX
+ "Malformed poll packet %x (idx = %i)\n", p, idx);
+ return;
+ }
+
+ i = (p & HIL_POL_AXIS_ALT) ? 3 : 0;
+ laxis = (p & HIL_POL_NUM_AXES_MASK) + i;
+
+ ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
+ absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
+
+ for (cnt = 1; i < laxis; i++) {
+ unsigned int lo, hi, val;
+
+ lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK;
+ hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0;
+
+ if (absdev) {
+ val = lo + (hi << 8);
+#ifdef TABLET_AUTOADJUST
+ if (val < dev->absmin[ABS_X + i])
+ dev->absmin[ABS_X + i] = val;
+ if (val > dev->absmax[ABS_X + i])
+ dev->absmax[ABS_X + i] = val;
+#endif
+ if (i%3) val = dev->absmax[ABS_X + i] - val;
+ input_report_abs(dev, ABS_X + i, val);
+ } else {
+ val = (int) (((int8_t)lo) | ((int8_t)hi << 8));
+ if (i % 3)
+ val *= -1;
+ input_report_rel(dev, REL_X + i, val);
+ }
+ }
+
+ while (cnt < idx - 1) {
+ unsigned int btn = ptr->data[cnt++];
+ int up = btn & 1;
+
+ btn &= 0xfe;
+ if (btn == 0x8e)
+ continue; /* TODO: proximity == touch? */
+ if (btn > 0x8c || btn < 0x80)
+ continue;
+ btn = (btn - 0x80) >> 1;
+ btn = ptr->btnmap[btn];
+ input_report_key(dev, btn, !up);
+ }
+
+ input_sync(dev);
+}
+
+static void hil_dev_process_err(struct hil_dev *dev)
{
printk(KERN_WARNING PREFIX "errored HIL packet\n");
- kbd->idx4 = 0;
- up(&kbd->sem);
+ dev->idx4 = 0;
+ complete(&dev->cmd_done); /* just in case somebody is waiting */
}
-static irqreturn_t hil_kbd_interrupt(struct serio *serio,
+static irqreturn_t hil_dev_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
- struct hil_kbd *kbd;
+ struct hil_dev *dev;
hil_packet packet;
int idx;
- kbd = serio_get_drvdata(serio);
- BUG_ON(kbd == NULL);
+ dev = serio_get_drvdata(serio);
+ BUG_ON(dev == NULL);
- if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
- hil_kbd_process_err(kbd);
- return IRQ_HANDLED;
+ if (dev->idx4 >= HIL_PACKET_MAX_LENGTH * sizeof(hil_packet)) {
+ hil_dev_process_err(dev);
+ goto out;
}
- idx = kbd->idx4/4;
- if (!(kbd->idx4 % 4))
- kbd->data[idx] = 0;
- packet = kbd->data[idx];
- packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
- kbd->data[idx] = packet;
+
+ idx = dev->idx4 / 4;
+ if (!(dev->idx4 % 4))
+ dev->data[idx] = 0;
+ packet = dev->data[idx];
+ packet |= ((hil_packet)data) << ((3 - (dev->idx4 % 4)) * 8);
+ dev->data[idx] = packet;
/* Records of N 4-byte hil_packets must terminate with a command. */
- if ((++(kbd->idx4)) % 4)
- return IRQ_HANDLED;
- if ((packet & 0xffff0000) != HIL_ERR_INT) {
- hil_kbd_process_err(kbd);
- return IRQ_HANDLED;
+ if ((++dev->idx4 % 4) == 0) {
+ if ((packet & 0xffff0000) != HIL_ERR_INT) {
+ hil_dev_process_err(dev);
+ } else if (packet & HIL_PKT_CMD) {
+ if (hil_dev_is_command_response(packet))
+ hil_dev_handle_command_response(dev);
+ else if (dev->is_pointer)
+ hil_dev_handle_ptr_events(dev);
+ else
+ hil_dev_handle_kbd_events(dev);
+ dev->idx4 = 0;
+ }
}
- if (packet & HIL_PKT_CMD)
- hil_kbd_process_record(kbd);
+ out:
return IRQ_HANDLED;
}
-static void hil_kbd_disconnect(struct serio *serio)
+static void hil_dev_disconnect(struct serio *serio)
{
- struct hil_kbd *kbd;
+ struct hil_dev *dev = serio_get_drvdata(serio);
- kbd = serio_get_drvdata(serio);
- BUG_ON(kbd == NULL);
+ BUG_ON(dev == NULL);
serio_close(serio);
- input_unregister_device(kbd->dev);
- kfree(kbd);
+ input_unregister_device(dev->dev);
+ serio_set_drvdata(serio, NULL);
+ kfree(dev);
+}
+
+static void hil_dev_keyboard_setup(struct hil_dev *kbd)
+{
+ struct input_dev *input_dev = kbd->dev;
+ uint8_t did = kbd->idd[0];
+ int i;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
+ BIT_MASK(LED_SCROLLL);
+
+ for (i = 0; i < 128; i++) {
+ __set_bit(hil_kbd_set1[i], input_dev->keybit);
+ __set_bit(hil_kbd_set3[i], input_dev->keybit);
+ }
+ __clear_bit(KEY_RESERVED, input_dev->keybit);
+
+ input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
+ input_dev->keycodesize = sizeof(hil_kbd_set1[0]);
+ input_dev->keycode = hil_kbd_set1;
+
+ input_dev->name = strlen(kbd->rnm) ? kbd->rnm : "HIL keyboard";
+ input_dev->phys = "hpkbd/input0";
+
+ printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n",
+ did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
}
-static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
+static void hil_dev_pointer_setup(struct hil_dev *ptr)
{
- struct hil_kbd *kbd;
- uint8_t did, *idd;
- int i;
+ struct input_dev *input_dev = ptr->dev;
+ uint8_t did = ptr->idd[0];
+ uint8_t *idd = ptr->idd + 1;
+ unsigned int naxsets = HIL_IDD_NUM_AXSETS(*idd);
+ unsigned int i, btntype;
+ const char *txt;
+
+ ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
+
+ switch (did & HIL_IDD_DID_TYPE_MASK) {
+ case HIL_IDD_DID_TYPE_REL:
+ input_dev->evbit[0] = BIT_MASK(EV_REL);
- kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
- if (!kbd)
- return -ENOMEM;
+ for (i = 0; i < ptr->naxes; i++)
+ __set_bit(REL_X + i, input_dev->relbit);
- kbd->dev = input_allocate_device();
- if (!kbd->dev)
+ for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++)
+ __set_bit(REL_X + i, input_dev->relbit);
+
+ txt = "relative";
+ break;
+
+ case HIL_IDD_DID_TYPE_ABS:
+ input_dev->evbit[0] = BIT_MASK(EV_ABS);
+
+ for (i = 0; i < ptr->naxes; i++)
+ input_set_abs_params(input_dev, ABS_X + i,
+ 0, HIL_IDD_AXIS_MAX(idd, i), 0, 0);
+
+ for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++)
+ input_set_abs_params(input_dev, ABS_X + i,
+ 0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0);
+
+#ifdef TABLET_AUTOADJUST
+ for (i = 0; i < ABS_MAX; i++) {
+ int diff = input_dev->absmax[ABS_X + i] / 10;
+ input_dev->absmin[ABS_X + i] += diff;
+ input_dev->absmax[ABS_X + i] -= diff;
+ }
+#endif
+
+ txt = "absolute";
+ break;
+
+ default:
+ BUG();
+ }
+
+ ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
+ if (ptr->nbtn)
+ input_dev->evbit[0] |= BIT_MASK(EV_KEY);
+
+ btntype = BTN_MISC;
+ if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
+#ifdef TABLET_SIMULATES_MOUSE
+ btntype = BTN_TOUCH;
+#else
+ btntype = BTN_DIGI;
+#endif
+ if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
+ btntype = BTN_TOUCH;
+
+ if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
+ btntype = BTN_MOUSE;
+
+ for (i = 0; i < ptr->nbtn; i++) {
+ __set_bit(btntype | i, input_dev->keybit);
+ ptr->btnmap[i] = btntype | i;
+ }
+
+ if (btntype == BTN_MOUSE) {
+ /* Swap buttons 2 and 3 */
+ ptr->btnmap[1] = BTN_MIDDLE;
+ ptr->btnmap[2] = BTN_RIGHT;
+ }
+
+ input_dev->name = strlen(ptr->rnm) ? ptr->rnm : "HIL pointer device";
+
+ printk(KERN_INFO PREFIX
+ "HIL pointer device found (did: 0x%02x, axis: %s)\n",
+ did, txt);
+ printk(KERN_INFO PREFIX
+ "HIL pointer has %i buttons and %i sets of %i axes\n",
+ ptr->nbtn, naxsets, ptr->naxes);
+}
+
+static int hil_dev_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct hil_dev *dev;
+ struct input_dev *input_dev;
+ uint8_t did, *idd;
+ int error;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!dev || !input_dev) {
+ error = -ENOMEM;
goto bail0;
+ }
- if (serio_open(serio, drv))
- goto bail1;
+ dev->serio = serio;
+ dev->dev = input_dev;
- serio_set_drvdata(serio, kbd);
- kbd->serio = serio;
+ error = serio_open(serio, drv);
+ if (error)
+ goto bail0;
- init_MUTEX_LOCKED(&kbd->sem);
+ serio_set_drvdata(serio, dev);
/* Get device info. MLC driver supplies devid/status/etc. */
- serio->write(serio, 0);
- serio->write(serio, 0);
- serio->write(serio, HIL_PKT_CMD >> 8);
- serio->write(serio, HIL_CMD_IDD);
- down(&kbd->sem);
-
- serio->write(serio, 0);
- serio->write(serio, 0);
- serio->write(serio, HIL_PKT_CMD >> 8);
- serio->write(serio, HIL_CMD_RSC);
- down(&kbd->sem);
-
- serio->write(serio, 0);
- serio->write(serio, 0);
- serio->write(serio, HIL_PKT_CMD >> 8);
- serio->write(serio, HIL_CMD_RNM);
- down(&kbd->sem);
-
- serio->write(serio, 0);
- serio->write(serio, 0);
- serio->write(serio, HIL_PKT_CMD >> 8);
- serio->write(serio, HIL_CMD_EXD);
- down(&kbd->sem);
-
- up(&kbd->sem);
-
- did = kbd->idd[0];
- idd = kbd->idd + 1;
+ init_completion(&dev->cmd_done);
+ serio_write(serio, 0);
+ serio_write(serio, 0);
+ serio_write(serio, HIL_PKT_CMD >> 8);
+ serio_write(serio, HIL_CMD_IDD);
+ error = wait_for_completion_killable(&dev->cmd_done);
+ if (error)
+ goto bail1;
+
+ init_completion(&dev->cmd_done);
+ serio_write(serio, 0);
+ serio_write(serio, 0);
+ serio_write(serio, HIL_PKT_CMD >> 8);
+ serio_write(serio, HIL_CMD_RSC);
+ error = wait_for_completion_killable(&dev->cmd_done);
+ if (error)
+ goto bail1;
+
+ init_completion(&dev->cmd_done);
+ serio_write(serio, 0);
+ serio_write(serio, 0);
+ serio_write(serio, HIL_PKT_CMD >> 8);
+ serio_write(serio, HIL_CMD_RNM);
+ error = wait_for_completion_killable(&dev->cmd_done);
+ if (error)
+ goto bail1;
+
+ init_completion(&dev->cmd_done);
+ serio_write(serio, 0);
+ serio_write(serio, 0);
+ serio_write(serio, HIL_PKT_CMD >> 8);
+ serio_write(serio, HIL_CMD_EXD);
+ error = wait_for_completion_killable(&dev->cmd_done);
+ if (error)
+ goto bail1;
+
+ did = dev->idd[0];
+ idd = dev->idd + 1;
+
switch (did & HIL_IDD_DID_TYPE_MASK) {
case HIL_IDD_DID_TYPE_KB_INTEGRAL:
case HIL_IDD_DID_TYPE_KB_ITF:
case HIL_IDD_DID_TYPE_KB_RSVD:
case HIL_IDD_DID_TYPE_CHAR:
- printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n",
- did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
- break;
- default:
- goto bail2;
- }
+ if (HIL_IDD_NUM_BUTTONS(idd) ||
+ HIL_IDD_NUM_AXES_PER_SET(*idd)) {
+ printk(KERN_INFO PREFIX
+ "combo devices are not supported.\n");
+ goto bail1;
+ }
- if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
- printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
- goto bail2;
- }
+ dev->is_pointer = false;
+ hil_dev_keyboard_setup(dev);
+ break;
- kbd->dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
- kbd->dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
- BIT_MASK(LED_SCROLLL);
- kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
- kbd->dev->keycodesize = sizeof(hil_kbd_set1[0]);
- kbd->dev->keycode = hil_kbd_set1;
- kbd->dev->name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
- kbd->dev->phys = "hpkbd/input0"; /* XXX */
-
- kbd->dev->id.bustype = BUS_HIL;
- kbd->dev->id.vendor = PCI_VENDOR_ID_HP;
- kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */
- kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */
- kbd->dev->dev.parent = &serio->dev;
+ case HIL_IDD_DID_TYPE_REL:
+ case HIL_IDD_DID_TYPE_ABS:
+ dev->is_pointer = true;
+ hil_dev_pointer_setup(dev);
+ break;
- for (i = 0; i < 128; i++) {
- set_bit(hil_kbd_set1[i], kbd->dev->keybit);
- set_bit(hil_kbd_set3[i], kbd->dev->keybit);
+ default:
+ goto bail1;
}
- clear_bit(0, kbd->dev->keybit);
- input_register_device(kbd->dev);
- printk(KERN_INFO "input: %s, ID: %d\n",
- kbd->dev->name, did);
+ input_dev->id.bustype = BUS_HIL;
+ input_dev->id.vendor = PCI_VENDOR_ID_HP;
+ input_dev->id.product = 0x0001; /* TODO: get from kbd->rsc */
+ input_dev->id.version = 0x0100; /* TODO: get from kbd->rsc */
+ input_dev->dev.parent = &serio->dev;
+
+ if (!dev->is_pointer) {
+