diff options
Diffstat (limited to 'drivers/input')
75 files changed, 4098 insertions, 1435 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index cd50c00ab20f..07c2cd43109c 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -8,7 +8,7 @@ menu "Input device support" config INPUT tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED default y - ---help--- + help Say Y here if you have any input device (mouse, keyboard, tablet, joystick, steering wheel ...) connected to your system and want it to be available to applications. This includes standard PS/2 @@ -27,8 +27,7 @@ if INPUT config INPUT_FF_MEMLESS tristate "Support for memoryless force-feedback devices" - default n - ---help--- + help Say Y here if you have memoryless force-feedback input device such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual Power 2, or similar. You will also need to enable hardware-specific @@ -52,12 +51,25 @@ config INPUT_POLLDEV To compile this driver as a module, choose M here: the module will be called input-polldev. +config INPUT_SPARSEKMAP + tristate "Sparse keymap support library" + help + Say Y here if you are using a driver for an input + device that uses sparse keymap. This option is only + useful for out-of-tree drivers since in-tree drivers + select it automatically. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sparse-keymap. + comment "Userland interfaces" config INPUT_MOUSEDEV tristate "Mouse interface" if EMBEDDED default y - ---help--- + help Say Y here if you want your mouse to be accessible as char devices 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated IntelliMouse Explorer PS/2 mouse. That way, all user space @@ -73,7 +85,7 @@ config INPUT_MOUSEDEV_PSAUX bool "Provide legacy /dev/psaux device" default y depends on INPUT_MOUSEDEV - ---help--- + help Say Y here if you want your mouse also be accessible as char device 10:1 - /dev/psaux. The data available through /dev/psaux is exactly the same as the data from /dev/input/mice. @@ -103,7 +115,7 @@ config INPUT_MOUSEDEV_SCREEN_Y config INPUT_JOYDEV tristate "Joystick interface" - ---help--- + help Say Y here if you want your joystick or gamepad to be accessible as char device 13:0+ - /dev/input/jsX device. @@ -125,7 +137,7 @@ config INPUT_EVDEV config INPUT_EVBUG tristate "Event debugging" - ---help--- + help Say Y here if you have a problem with the input subsystem and want all events (keypresses, mouse movements), to be output to the system log. While this is useful for debugging, it's also @@ -140,7 +152,7 @@ config INPUT_EVBUG config INPUT_APMPOWER tristate "Input Power Event -> APM Bridge" if EMBEDDED depends on INPUT && APM_EMULATION - ---help--- + help Say Y here if you want suspend key events to trigger a user requested suspend through APM. This is useful on embedded systems where such behaviour is desired without userspace @@ -153,6 +165,7 @@ config XEN_KBDDEV_FRONTEND tristate "Xen virtual keyboard and mouse support" depends on XEN_FBDEV_FRONTEND default y + select XEN_XENBUS_FRONTEND help This driver implements the front-end of the Xen virtual keyboard and mouse device driver. It communicates with a back-end diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 4c9c745a7020..7ad212d31f99 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -9,6 +9,7 @@ input-core-objs := input.o input-compat.o ff-core.o obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o +obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 38df81fcdc3a..b2f07aa1604b 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -353,7 +353,7 @@ int input_ff_create(struct input_dev *dev, int max_effects) EXPORT_SYMBOL_GPL(input_ff_create); /** - * input_ff_free() - frees force feedback portion of input device + * input_ff_destroy() - frees force feedback portion of input device * @dev: input device supporting force feedback * * This function is only needed in error path as input core will @@ -369,6 +369,7 @@ void input_ff_destroy(struct input_dev *dev) if (ff->destroy) ff->destroy(ff); kfree(ff->private); + kfree(ff->effects); kfree(ff); dev->ff = NULL; } diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 0d3ce7a50fb1..aa6713b4a988 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -56,14 +56,10 @@ static void input_polldev_stop_workqueue(void) mutex_unlock(&polldev_mutex); } -static void input_polled_device_work(struct work_struct *work) +static void input_polldev_queue_work(struct input_polled_dev *dev) { - struct input_polled_dev *dev = - container_of(work, struct input_polled_dev, work.work); unsigned long delay; - dev->poll(dev); - delay = msecs_to_jiffies(dev->poll_interval); if (delay >= HZ) delay = round_jiffies_relative(delay); @@ -71,6 +67,15 @@ static void input_polled_device_work(struct work_struct *work) queue_delayed_work(polldev_wq, &dev->work, delay); } +static void input_polled_device_work(struct work_struct *work) +{ + struct input_polled_dev *dev = + container_of(work, struct input_polled_dev, work.work); + + dev->poll(dev); + input_polldev_queue_work(dev); +} + static int input_open_polled_device(struct input_dev *input) { struct input_polled_dev *dev = input_get_drvdata(input); @@ -80,11 +85,12 @@ static int input_open_polled_device(struct input_dev *input) if (error) return error; - if (dev->flush) - dev->flush(dev); + if (dev->open) + dev->open(dev); - queue_delayed_work(polldev_wq, &dev->work, - msecs_to_jiffies(dev->poll_interval)); + /* Only start polling if polling is enabled */ + if (dev->poll_interval > 0) + queue_delayed_work(polldev_wq, &dev->work, 0); return 0; } @@ -95,8 +101,88 @@ static void input_close_polled_device(struct input_dev *input) cancel_delayed_work_sync(&dev->work); input_polldev_stop_workqueue(); + + if (dev->close) + dev->close(dev); } +/* SYSFS interface */ + +static ssize_t input_polldev_get_poll(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_polled_dev *polldev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", polldev->poll_interval); +} + +static ssize_t input_polldev_set_poll(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct input_polled_dev *polldev = dev_get_drvdata(dev); + struct input_dev *input = polldev->input; + unsigned long interval; + + if (strict_strtoul(buf, 0, &interval)) + return -EINVAL; + + if (interval < polldev->poll_interval_min) + return -EINVAL; + + if (interval > polldev->poll_interval_max) + return -EINVAL; + + mutex_lock(&input->mutex); + + polldev->poll_interval = interval; + + if (input->users) { + cancel_delayed_work_sync(&polldev->work); + if (polldev->poll_interval > 0) + input_polldev_queue_work(polldev); + } + + mutex_unlock(&input->mutex); + + return count; +} + +static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll, + input_polldev_set_poll); + + +static ssize_t input_polldev_get_max(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_polled_dev *polldev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", polldev->poll_interval_max); +} + +static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL); + +static ssize_t input_polldev_get_min(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_polled_dev *polldev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", polldev->poll_interval_min); +} + +static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL); + +static struct attribute *sysfs_attrs[] = { + &dev_attr_poll.attr, + &dev_attr_max.attr, + &dev_attr_min.attr, + NULL +}; + +static struct attribute_group input_polldev_attribute_group = { + .attrs = sysfs_attrs +}; + /** * input_allocate_polled_device - allocated memory polled device * @@ -126,7 +212,7 @@ EXPORT_SYMBOL(input_allocate_polled_device); * @dev: device to free * * The function frees memory allocated for polling device and drops - * reference to the associated input device (if present). + * reference to the associated input device. */ void input_free_polled_device(struct input_polled_dev *dev) { @@ -150,15 +236,38 @@ EXPORT_SYMBOL(input_free_polled_device); int input_register_polled_device(struct input_polled_dev *dev) { struct input_dev *input = dev->input; + int error; input_set_drvdata(input, dev); INIT_DELAYED_WORK(&dev->work, input_polled_device_work); if (!dev->poll_interval) dev->poll_interval = 500; + if (!dev->poll_interval_max) + dev->poll_interval_max = dev->poll_interval; input->open = input_open_polled_device; input->close = input_close_polled_device; - return input_register_device(input); + error = input_register_device(input); + if (error) + return error; + + error = sysfs_create_group(&input->dev.kobj, + &input_polldev_attribute_group); + if (error) { + input_unregister_device(input); + return error; + } + + /* + * Take extra reference to the underlying input device so + * that it survives call to input_unregister_polled_device() + * and is deleted only after input_free_polled_device() + * has been invoked. This is needed to ease task of freeing + * sparse keymaps. + */ + input_get_device(input); + + return 0; } EXPORT_SYMBOL(input_register_polled_device); @@ -169,13 +278,13 @@ EXPORT_SYMBOL(input_register_polled_device); * The function unregisters previously registered polled input * device from input layer. Polling is stopped and device is * ready to be freed with call to input_free_polled_device(). - * Callers should not attempt to access dev->input pointer - * after calling this function. */ void input_unregister_polled_device(struct input_polled_dev *dev) { + sysfs_remove_group(&dev->input->dev.kobj, + &input_polldev_attribute_group); + input_unregister_device(dev->input); - dev->input = NULL; } EXPORT_SYMBOL(input_unregister_polled_device); diff --git a/drivers/input/input.c b/drivers/input/input.c index 2266ecbfbc01..ab060710688f 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -296,9 +296,15 @@ static void input_handle_event(struct input_dev *dev, * @value: value of the event * * This function should be used by drivers implementing various input - * devices. See also input_inject_event(). + * devices to report input events. See also input_inject_event(). + * + * NOTE: input_event() may be safely used right after input device was + * allocated with input_allocate_device(), even before it is registered + * with input_register_device(), but the event will not reach any of the + * input handlers. Such early invocation of input_event() may be used + * to 'seed' initial state of a switch or initial position of absolute + * axis, etc. */ - void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -1658,6 +1664,38 @@ void input_unregister_handler(struct input_handler *handler) EXPORT_SYMBOL(input_unregister_handler); /** + * input_handler_for_each_handle - handle iterator + * @handler: input handler to iterate + * @data: data for the callback + * @fn: function to be called for each handle + * + * Iterate over @bus's list of devices, and call @fn for each, passing + * it @data and stop when @fn returns a non-zero value. The function is + * using RCU to traverse the list and therefore may be usind in atonic + * contexts. The @fn callback is invoked from RCU critical section and + * thus must not sleep. + */ +int input_handler_for_each_handle(struct input_handler *handler, void *data, + int (*fn)(struct input_handle *, void *)) +{ + struct input_handle *handle; + int retval = 0; + + rcu_read_lock(); + + list_for_each_entry_rcu(handle, &handler->h_list, h_node) { + retval = fn(handle, data); + if (retval) + break; + } + + rcu_read_unlock(); + + return retval; +} +EXPORT_SYMBOL(input_handler_for_each_handle); + +/** * input_register_handle - register a new input handle * @handle: handle to register * @@ -1690,7 +1728,7 @@ int input_register_handle(struct input_handle *handle) * we can't be racing with input_unregister_handle() * and so separate lock is not needed here. */ - list_add_tail(&handle->h_node, &handler->h_list); + list_add_tail_rcu(&handle->h_node, &handler->h_list); if (handler->start) handler->start(handle); @@ -1713,7 +1751,7 @@ void input_unregister_handle(struct input_handle *handle) { struct input_dev *dev = handle->dev; - list_del_init(&handle->h_node); + list_del_rcu(&handle->h_node); /* * Take dev->mutex to prevent race with input_release_device(). @@ -1721,6 +1759,7 @@ void input_unregister_handle(struct input_handle *handle) mutex_lock(&dev->mutex); list_del_rcu(&handle->d_node); mutex_unlock(&dev->mutex); + synchronize_rcu(); } EXPORT_SYMBOL(input_unregister_handle); diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 79e3edcced1a..482cb1204e43 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -125,6 +125,7 @@ static const struct xpad_device { { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, + { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX }, @@ -146,6 +147,7 @@ static const struct xpad_device { { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN } }; @@ -212,6 +214,7 @@ static struct usb_device_id xpad_table [] = { XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */ XPAD_XBOX360_VENDOR(0x1bad), /* Rock Band Drums */ + XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ { } }; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index ee98b1bc5d89..02c836e11813 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -24,6 +24,16 @@ config KEYBOARD_AAED2000 To compile this driver as a module, choose M here: the module will be called aaed2000_kbd. +config KEYBOARD_ADP5520 + tristate "Keypad Support for ADP5520 PMIC" + depends on PMIC_ADP5520 + help + This option enables support for the keypad scan matrix + on Analog Devices ADP5520 PMICs. + + To compile this driver as a module, choose M here: the module will + be called adp5520-keys. + config KEYBOARD_ADP5588 tristate "ADP5588 I2C QWERTY Keypad and IO Expander" depends on I2C @@ -361,6 +371,16 @@ config KEYBOARD_SH_KEYSC To compile this driver as a module, choose M here: the module will be called sh_keysc. +config KEYBOARD_DAVINCI + tristate "TI DaVinci Key Scan" + depends on ARCH_DAVINCI_DM365 + help + Say Y to enable keypad module support for the TI DaVinci + platforms (DM365). + + To compile this driver as a module, choose M here: the + module will be called davinci_keyscan. + config KEYBOARD_OMAP tristate "TI OMAP keypad support" depends on (ARCH_OMAP1 || ARCH_OMAP2) diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index babad5e58b77..78654ef65206 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -5,12 +5,14 @@ # Each configuration option enables a list of files. obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o +obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o +obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c new file mode 100644 index 000000000000..a7ba27fb4109 --- /dev/null +++ b/drivers/input/keyboard/adp5520-keys.c @@ -0,0 +1,220 @@ +/* + * Keypad driver for Analog Devices ADP5520 MFD PMICs + * + * Copyright 2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/mfd/adp5520.h> + +struct adp5520_keys { + struct input_dev *input; + struct notifier_block notifier; + struct device *master; + unsigned short keycode[ADP5520_KEYMAPSIZE]; +}; + +static void adp5520_keys_report_event(struct adp5520_keys *dev, + unsigned short keymask, int value) +{ + int i; + + for (i = 0; i < ADP5520_MAXKEYS; i++) + if (keymask & (1 << i)) + input_report_key(dev->input, dev->keycode[i], value); + + input_sync(dev->input); +} + +static int adp5520_keys_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct adp5520_keys *dev; + uint8_t reg_val_lo, reg_val_hi; + unsigned short keymask; + + dev = container_of(nb, struct adp5520_keys, notifier); + + if (event & ADP5520_KP_INT) { + adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, ®_val_lo); + adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, ®_val_hi); + + keymask = (reg_val_hi << 8) | reg_val_lo; + /* Read twice to clear */ + adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, ®_val_lo); + adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, ®_val_hi); + keymask |= (reg_val_hi << 8) | reg_val_lo; + adp5520_keys_report_event(dev, keymask, 1); + } + + if (event & ADP5520_KR_INT) { + adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, ®_val_lo); + adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, ®_val_hi); + + keymask = (reg_val_hi << 8) | reg_val_lo; + /* Read twice to clear */ + adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, ®_val_lo); + adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, ®_val_hi); + keymask |= (reg_val_hi << 8) | reg_val_lo; + adp5520_keys_report_event(dev, keymask, 0); + } + + return 0; +} + +static int __devinit adp5520_keys_probe(struct platform_device *pdev) +{ + struct adp5520_keys_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input; + struct adp5520_keys *dev; + int ret, i; + unsigned char en_mask, ctl_mask = 0; + + if (pdev->id != ID_ADP5520) { + dev_err(&pdev->dev, "only ADP5520 supports Keypad\n"); + return -EINVAL; + } + + if (pdata == NULL) { + dev_err(&pdev->dev, "missing platform data\n"); + return -EINVAL; + } + + if (!(pdata->rows_en_mask && pdata->cols_en_mask)) + return -EINVAL; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&pdev->dev, "failed to alloc memory\n"); + return -ENOMEM; + } + + input = input_allocate_device(); + if (!input) { + ret = -ENOMEM; + goto err; + } + + dev->master = pdev->dev.parent; + dev->input = input; + + input->name = pdev->name; + input->phys = "adp5520-keys/input0"; + input->dev.parent = &pdev->dev; + + input_set_drvdata(input, dev); + + input->id.bustype = BUS_I2C; + input->id.vendor = 0x0001; + input->id.product = 0x5520; + input->id.version = 0x0001; + + input->keycodesize = sizeof(dev->keycode[0]); + input->keycodemax = pdata->keymapsize; + input->keycode = dev->keycode; + + memcpy(dev->keycode, pdata->keymap, + pdata->keymapsize * input->keycodesize); + + /* setup input device */ + __set_bit(EV_KEY, input->evbit); + + if (pdata->repeat) + __set_bit(EV_REP, input->evbit); + + for (i = 0; i < input->keycodemax; i++) + __set_bit(dev->keycode[i], input->keybit); + __clear_bit(KEY_RESERVED, input->keybit); + + ret = input_register_device(input); + if (ret) { + dev_err(&pdev->dev, "unable to register input device\n"); + goto err; + } + + en_mask = pdata->rows_en_mask | pdata->cols_en_mask; + + ret = adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_1, en_mask); + + if (en_mask & ADP5520_COL_C3) + ctl_mask |= ADP5520_C3_MODE; + + if (en_mask & ADP5520_ROW_R3) + ctl_mask |= ADP5520_R3_MODE; + + if (ctl_mask) + ret |= adp5520_set_bits(dev->master, ADP5520_LED_CONTROL, + ctl_mask); + + ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP, + pdata->rows_en_mask); + + if (ret) { + dev_err(&pdev->dev, "failed to write\n"); + ret = -EIO; + goto err1; + } + + dev->notifier.notifier_call = adp5520_keys_notifier; + ret = adp5520_register_notifier(dev->master, &dev->notifier, + ADP5520_KP_IEN | ADP5520_KR_IEN); + if (ret) { + dev_err(&pdev->dev, "failed to register notifier\n"); + goto err1; + } + + platform_set_drvdata(pdev, dev); + return 0; + +err1: + input_unregister_device(input); + input = NULL; +err: + input_free_device(input); + kfree(dev); + return ret; +} + +static int __devexit adp5520_keys_remove(struct platform_device *pdev) +{ + struct adp5520_keys *dev = platform_get_drvdata(pdev); + + adp5520_unregister_notifier(dev->master, &dev->notifier, + ADP5520_KP_IEN | ADP5520_KR_IEN); + + input_unregister_device(dev->input); + kfree(dev); + return 0; +} + +static struct platform_driver adp5520_keys_driver = { + .driver = { + .name = "adp5520-keys", + .owner = THIS_MODULE, + }, + .probe = adp5520_keys_probe, + .remove = __devexit_p(adp5520_keys_remove), +}; + +static int __init adp5520_keys_init(void) +{ + return platform_driver_register(&adp5520_keys_driver); +} +module_init(adp5520_keys_init); + +static void __exit adp5520_keys_exit(void) +{ + platform_driver_unregister(&adp5520_keys_driver); +} +module_exit(adp5520_keys_exit); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Keys ADP5520 Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:adp5520-keys"); diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index d48c808d5928..1edb596d927b 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -319,7 +319,7 @@ static int adp5588_resume(struct device *dev) return 0; } -static struct dev_pm_ops adp5588_dev_pm_ops = { +static const struct dev_pm_ops adp5588_dev_pm_ops = { .suspend = adp5588_suspend, .resume = adp5588_resume, }; diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 28e6110d1ff8..a3573570c52f 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -1567,9 +1567,8 @@ static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id) return 0; } -static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { +static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { { - .ident = "Dell Laptop", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ @@ -1578,7 +1577,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_dell_laptop_forced_release_keys, }, { - .ident = "Dell Laptop", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ @@ -1587,7 +1585,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_dell_laptop_forced_release_keys, }, { - .ident = "HP 2133", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"), @@ -1596,7 +1593,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_hp_forced_release_keys, }, { - .ident = "HP Pavilion ZV6100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), @@ -1605,7 +1601,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "HP Presario R4000", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"), @@ -1614,7 +1609,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "HP Presario R4100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"), @@ -1623,7 +1617,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "HP Presario R4200", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"), @@ -1632,7 +1625,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "Inventec Symphony", + /* Inventec Symphony */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), @@ -1641,7 +1634,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "Samsung NC10", + /* Samsung NC10 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), @@ -1650,7 +1643,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_samsung_forced_release_keys, }, { - .ident = "Samsung NC20", + /* Samsung NC20 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), DMI_MATCH(DMI_PRODUCT_NAME, "NC20"), @@ -1659,7 +1652,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_samsung_forced_release_keys, }, { - .ident = "Samsung SQ45S70S", + /* Samsung SQ45S70S */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), @@ -1668,7 +1661,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_samsung_forced_release_keys, }, { - .ident = "Fujitsu Amilo PA 1510", + /* Fujitsu Amilo PA 1510 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"), @@ -1677,7 +1670,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "Fujitsu Amilo Pi 3525", + /* Fujitsu Amilo Pi 3525 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"), @@ -1686,7 +1679,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_amilo_pi3525_forced_release_keys, }, { - .ident = "Fujitsu Amilo Xi 3650", + /* Fujitsu Amilo Xi 3650 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"), @@ -1695,7 +1688,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_amilo_xi3650_forced_release_keys, }, { - .ident = "Soltech Corporation TA12", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "TA12"), @@ -1704,7 +1696,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkdb_soltech_ta12_forced_release_keys, }, { - .ident = "OQO Model 01+", + /* OQO Model 01+ */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "OQO"), DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c new file mode 100644 index 000000000000..6e52d855f637 --- /dev/null +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -0,0 +1,337 @@ +/* + * DaVinci Key Scan Driver for TI platforms + * + * Copyright (C) 2009 Texas Instruments, Inc + * + * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com> + * + * Intial Code: Sandeep Paulraj <s-paulraj@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/types.h> +#include <linux/input.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/errno.h> + +#include <asm/irq.h> + +#include <mach/hardware.h> +#include <mach/irqs.h> +#include <mach/keyscan.h> + +/* Key scan registers */ +#define DAVINCI_KEYSCAN_KEYCTRL 0x0000 +#define DAVINCI_KEYSCAN_INTENA 0x0004 +#define DAVINCI_KEYSCAN_INTFLAG 0x0008 +#define DAVINCI_KEYSCAN_INTCLR 0x000c +#define DAVINCI_KEYSCAN_STRBWIDTH 0x0010 +#define DAVINCI_KEYSCAN_INTERVAL 0x0014 +#define DAVINCI_KEYSCAN_CONTTIME 0x0018 +#define DAVINCI_KEYSCAN_CURRENTST 0x001c +#define DAVINCI_KEYSCAN_PREVSTATE 0x0020 +#define DAVINCI_KEYSCAN_EMUCTRL 0x0024 +#define DAVINCI_KEYSCAN_IODFTCTRL 0x002c + +/* Key Control Register (KEYCTRL) */ +#define DAVINCI_KEYSCAN_KEYEN 0x00000001 +#define DAVINCI_KEYSCAN_PREVMODE 0x00000002 +#define DAVINCI_KEYSCAN_CHATOFF 0x00000004 +#define DAVINCI_KEYSCAN_AUTODET 0x00000008 +#define DAVINCI_KEYSCAN_SCANMODE 0x00000010 +#define DAVINCI_KEYSCAN_OUTTYPE 0x00000020 + +/* Masks for the interrupts */ +#define DAVINCI_KEYSCAN_INT_CONT 0x00000008 +#define DAVINCI_KEYSCAN_INT_OFF 0x00000004 +#define DAVINCI_KEYSCAN_INT_ON 0x00000002 +#define DAVINCI_KEYSCAN_INT_CHANGE 0x00000001 +#define DAVINCI_KEYSCAN_INT_ALL 0x0000000f + +struct davinci_ks { + struct input_dev *input; + struct davinci_ks_platform_data *pdata; + int irq; + void __iomem *base; + resource_size_t pbase; + size_t base_size; + unsigned short keymap[]; +}; + +/* Initializing the kp Module */ +static int __init davinci_ks_initialize(struct davinci_ks *davinci_ks) +{ + struct device *dev = &davinci_ks->input->dev; + struct davinci_ks_platform_data *pdata = davinci_ks->pdata; + u32 matrix_ctrl; + + /* Enable all interrupts */ + __raw_writel(DAVINCI_KEYSCAN_INT_ALL, + davinci_ks->base + DAVINCI_KEYSCAN_INTENA); + + /* Clear interrupts if any */ + __raw_writel(DAVINCI_KEYSCAN_INT_ALL, + davinci_ks->base + DAVINCI_KEYSCAN_INTCLR); + + /* Setup the scan period = strobe + interval */ + __raw_writel(pdata->strobe, + davinci_ks->base + DAVINCI_KEYSCAN_STRBWIDTH); + __raw_writel(pdata->interval, + davinci_ks->base + DAVINCI_KEYSCAN_INTERVAL); + __raw_writel(0x01, + davinci_ks->base + DAVINCI_KEYSCAN_CONTTIME); + + /* Define matrix type */ + switch (pdata->matrix_type) { + case DAVINCI_KEYSCAN_MATRIX_4X4: + matrix_ctrl = 0; + break; + case DAVINCI_KEYSCAN_MATRIX_5X3: + matrix_ctrl = (1 << 6); + break; + default: + dev_err(dev->parent, "wrong matrix type\n"); + return -EINVAL; + } + + /* Enable key scan module and set matrix type */ + __raw_writel(DAVINCI_KEYSCAN_AUTODET | DAVINCI_KEYSCAN_KEYEN | + matrix_ctrl, davinci_ks->base + DAVINCI_KEYSCAN_KEYCTRL); + + return 0; +} + +static irqreturn_t davinci_ks_interrupt(int irq, void *dev_id) +{ + struct davinci_ks *davinci_ks = dev_id; + struct device *dev = &davinci_ks->input->dev; + unsigned short *keymap = davinci_ks->keymap; + int keymapsize = davinci_ks->pdata->keymapsize; + u32 prev_status, new_status, changed; + bool release; + int keycode = KEY_UNKNOWN; + int i; + + /* Disable interrupt */ + __raw_writel(0x0, davinci_ks->base + DAVINCI_KEYSCAN_INTENA); + + /* Reading previous and new status of the key scan */ + prev_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_PREVSTATE); + new_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_CURRENTST); + + changed = prev_status ^ new_status; + + if (changed) { + /* + * It goes through all bits in 'changed' to ensure + * that no key changes are being missed + */ + for (i = 0 ; i < keymapsize; i++) { + if ((changed>>i) & 0x1) { + keycode = keymap[i]; + release = (new_status >> i) & 0x1; + dev_dbg(dev->parent, "key %d %s\n", keycode, + release ? "released" : "pressed"); + input_report_key(davinci_ks->input, keycode, + !release); + input_sync(davinci_ks->input); + } + } + /* Clearing interrupt */ + __raw_writel(DAVINCI_KEYSCAN_INT_ALL, + davinci_ks->base + DAVINCI_KEYSCAN_INTCLR); + } + + /* Enable interrupts */ + __raw_writel(0x1, davinci_ks->base + DAVINCI_KEYSCAN_INTENA); + + return IRQ_HANDLED; +} + +static int __init davinci_ks_probe(struct platform_device *pdev) +{ + struct davinci_ks *davinci_ks; + struct input_dev *key_dev; + struct resource *res, *mem; + struct device *dev = &pdev->dev; + struct davinci_ks_platform_data *pdata = pdev->dev.platform_data; + int error, i; + + if (!pdata->keymap) { + dev_dbg(dev, "no keymap from pdata\n"); + return -EINVAL; + } + + davinci_ks = kzalloc(sizeof(struct davinci_ks) + + sizeof(unsigned short) * pdata->keymapsize, GFP_KERNEL); + if (!davinci_ks) { + dev_dbg(dev, "could not allocate memory for private data\n"); + return -ENOMEM; + } + + memcpy(davinci_ks->keymap, pdata->keymap, + sizeof(unsigned short) * pdata->keymapsize); + + key_dev = input_allocate_device(); + if (!key_dev) { + dev_dbg(dev, "could not allocate input device\n"); + error = -ENOMEM; + goto fail1; + } + + davinci_ks->input = key_dev; + + davinci_ks->irq = platform_get_irq(pdev, 0); + if (davinci_ks->irq < 0) { + dev_err(dev, "no key scan irq\n"); + error = davinci_ks->irq; + goto fail2; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no mem resource\n"); + error = -EINVAL; + goto fail2; + } + + davinci_ks->pbase = res->start; + davinci_ks->base_size = resource_size(res); + + mem = request_mem_region(davinci_ks->pbase, davinci_ks->base_size, + pdev->name); + if (!mem) { + dev_err(dev, "key scan registers at %08x are not free\n", + davinci_ks->pbase); + error = -EBUSY; + goto fail2; + } + + davinci_ks->base = ioremap(davinci_ks->pbase, davinci_ks->base_size); + if (!davinci_ks->base) { + dev_err(dev, "can't ioremap MEM resource.\n"); + error = -ENOMEM; + goto fail3; + } + + /* Enable auto repeat feature of Linux input subsystem */ + if (pdata->rep) + __set_bit(EV_REP, key_dev->evbit); + + /* Setup input device */ + __set_bit(EV_KEY, key_dev->evbit); + + /* Setup the platform data */ + davinci_ks->pdata = pdata; + + for (i = 0; i < davinci_ks->pdata->keymapsize; i++) + __set_bit(davinci_ks->pdata->keymap[i], key_dev->keybit); + + key_dev->name = "davinci_keyscan"; + key_dev->phys = "davinci_keyscan/input0"; + key_dev->dev.parent = &pdev->dev; + key_dev->id.bustype = BUS_HOST; + key_dev->id.vendor = 0x0001; + key_dev->id.product = 0x0001; + key_dev->id.version = 0x0001; + key_dev->keycode = davinci_ks->keymap; + key_dev->keycodesize = sizeof(davinci_ks->keymap[0]); + key_dev->keycodemax = davinci_ks->pdata->keymapsize; + + error = input_register_device(davinci_ks->input); + if (error < 0) { + dev_err(dev, "unable to register davinci key scan device\n"); + goto fail4; + } + + error = request_irq(davinci_ks->irq, davinci_ks_interrupt, + IRQF_DISABLED, pdev->name, davinci_ks); + if (error < 0) { + dev_err(dev, "unable to register davinci key scan interrupt\n"); + goto fail5; + } + + error = davinci_ks_initialize(davinci_ks); + if (error < 0) { + dev_err(dev, "unable to initialize davinci key scan device\n"); + goto fail6; + } + + platform_set_drvdata(pdev, davinci_ks); + return 0; + +fail6: + free_irq(davinci_ks->irq, davinci_ks); +fail5: + input_unregister_device(davinci_ks->input); + key_dev = NULL; +fail4: + iounmap(davinci_ks->base); +fail3: + release_mem_region(davinci_ks->pbase, davinci_ks->base_size); +fail2: + input_free_device(key_dev); +fail1: + kfree(davinci_ks); + + return error; +} + +static int __devexit davinci_ks_remove(struct platform_device *pdev) +{ + struct davinci_ks *davinci_ks = platform_get_drvdata(pdev); + + free_irq(davinci_ks->irq, davinci_ks); + + input_unregister_device(davinci_ks->input); + + iounmap(davinci_ks->base); + release_mem_region(davinci_ks->pbase, davinci_ks->base_size); + + platform_set_drvdata(pdev, NULL); + + kfree(davinci_ks); + + return 0; +} + +static struct platform_driver davinci_ks_driver = { + .driver = { + .name = "davinci_keyscan", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(davinci_ks_remove), +}; + +static int __init davinci_ks_init(void) +{ + return platform_driver_probe(&davinci_ks_driver, davinci_ks_probe); +} +module_init(davinci_ks_init); + +static void __exit davinci_ks_exit(void) +{ + platform_driver_unregister(&davinci_ks_driver); +} +module_exit(davinci_ks_exit); + +MODULE_AUTHOR("Miguel Aguilar"); +MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 181d30e3018e..e45740429f7e 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -22,11 +22,11 @@ #include <linux/platform_device.h> #include <linux/interrupt.h> -#include <linux/input.h> #include <linux/clk.h> +#include <linux/io.h> +#include <linux/input/matrix_keypad.h> #include <mach/hardware.h> -#include <mach/gpio.h> #include <mach/ep93xx_keypad.h> /* @@ -60,38 +60,37 @@ #define KEY_REG_KEY1_MASK (0x0000003f) #define KEY_REG_KEY1_SHIFT (0) -#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) -#define keypad_writel(v, off) __raw_writel((v), keypad->mmio_base + (off)) - -#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) +#define EP93XX_MATRIX_SIZE (EP93XX_MATRIX_ROWS * EP93XX_MATRIX_COLS) struct ep93xx_keypad { struct ep93xx_keypad_platform_data *pdata; - - struct clk *clk; struct input_dev *input_dev; + struct clk *clk; + void __iomem *mmio_base; - int irq; - int enabled; + unsigned int matrix_keycodes[EP93XX_MATRIX_SIZE]; int key1; int key2; - unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; + int irq; + + bool enabled; }; static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad) { struct ep93xx_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; + unsigned int *key; int i; - for (i = 0; i < pdata->matrix_key_map_size; i++) { - unsigned int key = pdata->matrix_key_map[i]; - int row = (key >> 28) & 0xf; - int col = (key >> 24) & 0xf; - int code = key & 0xffffff; + key = &pdata->matrix_key_map[0]; + for (i = 0; i < pdata->matrix_key_map_size; i++, key++) { + int row = KEY_ROW(*key); + int col = KEY_COL(*key); + int code = KEY_VAL(*key); keypad->matrix_keycodes[(row << 3) + col] = code; __set_bit(code, input_dev->keybit); @@ -102,9 +101,11 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id) { struct ep93xx_keypad *keypad = dev_id; struct input_dev *input_dev = keypad->input_dev; - unsigned int status = keypad_readl(KEY_REG); + unsigned int status; int keycode, key1, key2; + status = __raw_readl(keypad->mmio_base + KEY_REG); + keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT; key1 = keypad->matrix_keycodes[keycode]; @@ -152,7 +153,10 @@ static void ep93xx_keypad_config(struct ep93xx_keypad *keypad) struct ep93xx_keypad_platform_data *pdata = keypad->pdata; unsigned int val = 0; - clk_set_rate(keypad->clk, pdata->flags & EP93XX_KEYPAD_KDIV); + if (pdata->flags & EP93XX_KEYPAD_KDIV) + clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV4); + else + clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV16); if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY) val |= KEY_INIT_DIS3KY; @@ -167,7 +171,7 @@ static void ep93xx_keypad_config(struct ep93xx_keypad *keypad) val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK); - keypad_writel(val, KEY_INIT); + __raw_writel(val, keypad->mmio_base + KEY_INIT); } static int ep93xx_keypad_open(struct input_dev *pdev) @@ -177,7 +181,7 @@ static int ep93xx_keypad_open(struct input_dev *pdev) if (!keypad->enabled) { ep93xx_keypad_config(keypad); clk_enable(keypad->clk); - keypad->enabled = 1; + keypad->enabled = true; } return 0; @@ -189,7 +193,7 @@ static void ep93xx_keypad_close(struct input_dev *pdev) if (keypad->enabled) { clk_disable(keypad->clk); - keypad->enabled = 0; + keypad->enabled = false; } } @@ -211,7 +215,7 @@ static int ep93xx_keypad_suspend(struct platform_device *pdev, if (keypad->enabled) { clk_disable(keypad->clk); - keypad->enabled = 0; + keypad->enabled = false; } mutex_unlock(&input_dev->mutex); @@ -236,7 +240,7 @@ static int ep93xx_keypad_resume(struct platform_device *pdev) if (!keypad->enabled) { ep93xx_keypad_config(keypad); clk_enable(keypad->clk); - keypad->enabled = 1; + keypad->enabled = true; } } @@ -252,88 +256,56 @@ static int ep93xx_keypad_resume(struct platform_device *pdev) static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) { struct ep93xx_keypad *keypad; - struct ep93xx_keypad_platform_data *pdata = pdev->dev.platform_data; struct input_dev *input_dev; struct resource *res; - int irq, err, i, gpio; - - if (!pdata || - !pdata->matrix_key_rows || - pdata->matrix_key_rows > MAX_MATRIX_KEY_ROWS || - !pdata->matrix_key_cols || - pdata->matrix_key_cols > MAX_MATRIX_KEY_COLS) { - dev_err(&pdev->dev, "invalid or missing platform data\n"); - return -EINVAL; - } + int err; keypad = kzalloc(sizeof(struct ep93xx_keypad), GFP_KERNEL); - if (!keypad) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); + if (!keypad) return -ENOMEM; - } - keypad->pdata = pdata; + keypad->pdata = pdev->dev.platform_data; + if (!keypad->pdata) { + err = -EINVAL; + goto failed_free; + } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get keypad irq\n"); + keypad->irq = platform_get_irq(pdev, 0); + if (!keypad->irq) { err = -ENXIO; goto failed_free; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - dev_err(&pdev->dev, "failed to get I/O memory\n"); err = -ENXIO; goto failed_free; } res = request_mem_region(res->start, resource_size(res), pdev->name); if (!res) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); err = -EBUSY; goto failed_free; } keypad->mmio_base = ioremap(res->start, resource_size(res)); if (keypad->mmio_base == NULL) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); err = -ENXIO; goto failed_free_mem; } - /* Request the needed GPIO's */ - gpio = EP93XX_GPIO_LINE_ROW0; - for (i = 0; i < keypad->pdata->matrix_key_rows; i++, gpio++) { - err = gpio_request(gpio, pdev->name); - if (err) { - dev_err(&pdev->dev, "failed to request gpio-%d\n", - gpio); - goto failed_free_rows; - } - } - - gpio = EP93XX_GPIO_LINE_COL0; - for (i = 0; i < keypad->pdata->matrix_key_cols; i++, gpio++) { - err = gpio_request(gpio, pdev->name); - if (err) { - dev_err(&pdev->dev, "failed to request gpio-%d\n", - gpio); - goto failed_free_cols; - } - } + err = ep93xx_keypad_acquire_gpio(pdev); + if (err) + goto failed_free_io; - keypad->clk = clk_get(&pdev->dev, "key_clk"); + keypad->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(keypad->clk)) { - dev_err(&pdev->dev, "failed to get keypad clock\n"); err = PTR_ERR(keypad->clk); - goto failed_free_io; + goto failed_free_gpio; } - /* Create and register the input driver */ input_dev = input_allocate_device(); if (!input_dev) { - dev_err(&pdev->dev, "failed to allocate input device\n"); err = -ENOMEM; goto failed_put_clk; } @@ -358,44 +330,29 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) ep93xx_keypad_build_keycode(keypad); platform_set_drvdata(pdev, keypad); - err = request_irq(irq, ep93xx_keypad_irq_handler, IRQF_DISABLED, - pdev->name, keypad); - if (err) { - dev_err(&pdev->dev, "failed to request IRQ\n"); + err = request_irq(keypad->irq, ep93xx_keypad_irq_handler, + IRQF_DISABLED, pdev->name, keypad); + if (err) goto failed_free_dev; - } - - keypad->irq = irq; - /* Register the input device */ err = input_register_device(input_dev); - if (err) { - dev_err(&pdev->dev, "failed to register input device\n"); + if (err) goto failed_free_irq; - } device_init_wakeup(&pdev->dev, 1); return 0; failed_free_irq: - free_irq(irq, pdev); + free_irq(keypad->irq, pdev); platform_set_drvdata(pdev, NULL); failed_free_dev: input_free_device(input_dev); failed_put_clk: clk_put(keypad->clk); +failed_free_gpio: + ep93xx_keypad_release_gpio(pdev); failed_free_io: - i = keypad->pdata->matrix_key_cols - 1; - gpio = EP93XX_GPIO_LINE_COL0 + i; -failed_free_cols: - for ( ; i >= 0; i--, gpio--) - gpio_free(gpio); - i = keypad->pdata->matrix_key_rows - 1; - gpio = EP93XX_GPIO_LINE_ROW0 + i; -failed_free_rows: - for ( ; i >= 0; i--, gpio--) - gpio_free(gpio); iounmap(keypad->mmio_base); failed_free_mem: release_mem_region(res->start, resource_size(res)); @@ -408,7 +365,6 @@ static int __devexit ep93xx_keypad_remove(struct platform_device *pdev) { struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); struct resource *res; - int i, gpio; free_irq(keypad->irq, pdev); @@ -420,15 +376,7 @@ static int __devexit ep93xx_keypad_remove(struct platform_device *pdev) input_unregister_device(keypad->input_dev); - i = keypad->pdata->matrix_key_cols - 1; - gpio = EP93XX_GPIO_LINE_COL0 + i; - for ( ; i >= 0; i--, gpio--) - gpio_free(gpio); - - i = keypad->pdata->matrix_key_rows - 1; - gpio = EP93XX_GPIO_LINE_ROW0 + i; - for ( ; i >= 0; i--, gpio--) - gpio_free(gpio); + ep93xx_keypad_release_gpio(pdev); iounmap(keypad->mmio_base); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 77d130914259..1aff3b76effd 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -23,8 +23,7 @@ #include <linux/input.h> #include <linux/gpio_keys.h> #include <linux/workqueue.h> - -#include <asm/gpio.h> +#include <linux/gpio.h> struct gpio_button_data { struct gpio_keys_button *button; @@ -38,10 +37,8 @@ struct gpio_keys_drvdata { struct gpio_button_data data[0]; }; -static void gpio_keys_report_event(struct work_struct *work) +static void gpio_keys_report_event(struct gpio_button_data *bdata) { - struct gpio_button_data *bdata = - container_of(work, struct gpio_button_data, work); struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; @@ -51,6 +48,14 @@ static void gpio_keys_report_event(struct work_struct *work) input_sync(input); } +static void gpio_keys_work_func(struct work_struct *work) +{ + struct gpio_button_data *bdata = + container_of(work, struct gpio_button_data, work); + + gpio_keys_report_event(bdata); +} + static void gpio_keys_timer(unsigned long _data) { struct gpio_button_data *data = (struct gpio_button_data *)_data; @@ -74,10 +79,62 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static int __devinit gpio_keys_setup_key(struct device *dev, + struct gpio_button_data *bdata, + struct gpio_keys_button *button) +{ + char *desc = button->desc ? button->desc : "gpio_keys"; + int irq, error; + + setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata); + INIT_WORK(&bdata->work, gpio_keys_work_func); + + error = gpio_request(button->gpio, desc); + if (error < 0) { + dev_err(dev, "failed to request GPIO %d, error %d\n", + button->gpio, error); + goto fail2; + } + + error = gpio_direction_input(button->gpio); + if (error < 0) { + dev_err(dev, "failed to configure" + " direction for GPIO %d, error %d\n", + button->gpio, error); + goto fail3; + } + + irq = gpio_to_irq(button->gpio); + if (irq < 0) { + error = irq; + dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n", + button->gpio, error); + goto fail3; + } + + error = request_irq(irq, gpio_keys_isr, + IRQF_SHARED | + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + desc, bdata); + if (error) { + dev_err(dev, "Unable to claim irq %d; error %d\n", + irq, error); + goto fail3; + } + + return 0; + +fail3: + gpio_free(button->gpio); +fail2: + return error; +} + static int __devinit gpio_keys_probe(struct platform_device *pdev) { struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; struct gpio_keys_drvdata *ddata; + struct device *dev = &pdev->dev; struct input_dev *input; int i, error; int wakeup = 0; @@ -87,6 +144,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) GFP_KERNEL); input = input_allocate_device(); if (!ddata || !input) { + dev_err(dev, "failed to allocate state\n"); error = -ENOMEM; goto fail1; } @@ -111,52 +169,14 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_button_data *bdata = &ddata->data[i]; - int irq; unsigned int type = button->type ?: EV_KEY; bdata->input = input; bdata->button = button; - setup_timer(&bdata->timer, - gpio_keys_timer, (unsigned long)bdata); - INIT_WORK(&bdata->work, gpio_keys_report_event); - - error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); - if (error < 0) { - pr_err("gpio-keys: failed to request GPIO %d," - " error %d\n", button->gpio, error); - goto fail2; - } - - error = gpio_direction_input(button->gpio); - if (error < 0) { - pr_err("gpio-keys: failed to configure input" - " direction for GPIO %d, error %d\n", - button->gpio, error); - gpio_free(button->gpio); - goto fail2; - } - - irq = gpio_to_irq(button->gpio); - if (irq < 0) { - error = irq; - pr_err("gpio-keys: Unable to get irq number" - " for GPIO %d, error %d\n", - button->gpio, error); - gpio_free(button->gpio); - goto fail2; - } - error = request_irq(irq, gpio_keys_isr, - IRQF_SHARED | - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - button->desc ? button->desc : "gpio_keys", - bdata); - if (error) { - pr_err("gpio-keys: Unable to claim irq %d; error %d\n", - irq, error); - gpio_free(button->gpio); + error = gpio_keys_setup_key(dev, bdata, button); + if (error) goto fail2; - } if (button->wakeup) wakeup = 1; @@ -166,11 +186,16 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) error = input_register_device(input); if (error) { - pr_err("gpio-keys: Unable to register input device, " + dev_err(dev, "Unable to register input device, " "error: %d\n", error); goto fail2; } + /* get current state of buttons */ + for (i = 0; i < pdata->nbuttons; i++) + gpio_keys_report_event(&ddata->data[i]); + input_sync(input); + device_init_wakeup(&pdev->dev, wakeup); return 0; @@ -239,18 +264,21 @@ static int gpio_keys_suspend(struct device *dev) static int gpio_keys_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; int i; - if (device_may_wakeup(&pdev->dev)) { - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - if (button->wakeup) { - int irq = gpio_to_irq(button->gpio); - disable_irq_wake(irq); - } + for (i = 0; i < pdata->nbuttons; i++) { + + struct gpio_keys_button *button = &pdata->buttons[i]; + if (button->wakeup && device_may_wakeup(&pdev->dev)) { + int irq = gpio_to_irq(button->gpio); + disable_irq_wake(irq); } + + gpio_keys_report_event(&ddata->data[i]); } + input_sync(ddata->input); return 0; } diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index f9847e0fb553..fa9bb6d235e2 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -72,9 +72,9 @@ #define DRIVER_DESC "LK keyboard driver" -MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); -MODULE_DESCRIPTION (DRIVER_DESC); -MODULE_LICENSE ("GPL"); +MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); /* * Known parameters: @@ -85,27 +85,27 @@ MODULE_LICENSE ("GPL"); * Please notice that there's not yet an API to set these at runtime. */ static int bell_volume = 100; /* % */ -module_param (bell_volume, int, 0); -MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%"); +module_param(bell_volume, int, 0); +MODULE_PARM_DESC(bell_volume, "Bell volume (in %). default is 100%"); static int keyclick_volume = 100; /* % */ -module_param (keyclick_volume, int, 0); -MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%"); +module_param(keyclick_volume, int, 0); +MODULE_PARM_DESC(keyclick_volume, "Keyclick volume (in %), default is 100%"); static int ctrlclick_volume = 100; /* % */ -module_param (ctrlclick_volume, int, 0); -MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); +module_param(ctrlclick_volume, int, 0); +MODULE_PARM_DESC(ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); static int lk201_compose_is_alt; -module_param (lk201_compose_is_alt, int, 0); -MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " - "will act as an Alt key"); +module_param(lk201_compose_is_alt, int, 0); +MODULE_PARM_DESC(lk201_compose_is_alt, + "If set non-zero, LK201' Compose key will act as an Alt key"); #undef LKKBD_DEBUG #ifdef LKKBD_DEBUG -#define DBG(x...) printk (x) +#define DBG(x...) printk(x) #else #define DBG(x...) do {} while (0) #endif @@ -122,7 +122,7 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " #define LK_MODE_DOWN 0x80 #define LK_MODE_AUTODOWN 0x82 #define LK_MODE_UPDOWN 0x86 -#define LK_CMD_SET_MODE(mode,div) ((mode) | ((div) << 3)) +#define LK_CMD_SET_MODE(mode, div) ((mode) | ((div) << 3)) /* Misc commands */ #define LK_CMD_ENABLE_KEYCLICK 0x1b @@ -152,11 +152,8 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " #define LK_NUM_KEYCODES 256 #define LK_NUM_IGNORE_BYTES 6 -typedef u_int16_t lk_keycode_t; - - -static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { +static unsigned short lkkbd_keycode[LK_NUM_KEYCODES] = { [0x56] = KEY_F1, [0x57] = KEY_F2, [0x58] = KEY_F3, @@ -268,7 +265,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { }; #define CHECK_LED(LK, VAR_ON, VAR_OFF, LED, BITS) do { \ - if (test_bit (LED, (LK)->dev->led)) \ + if (test_bit(LED, (LK)->dev->led)) \ VAR_ON |= BITS; \ else \ VAR_OFF |= BITS; \ @@ -278,7 +275,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { * Per-keyboard data */ struct lkkbd { - lk_keycode_t keycode[LK_NUM_KEYCODES]; + unsigned short keycode[LK_NUM_KEYCODES]; int ignore_bytes; unsigned char id[LK_NUM_IGNORE_BYTES]; struct input_dev *dev; @@ -301,26 +298,25 @@ static struct { unsigned char *name; } lk_response[] = { #define RESPONSE(x) { .value = (x), .name = #x, } - RESPONSE (LK_STUCK_KEY), - RESPONSE (LK_SELFTEST_FAILED), - RESPONSE (LK_ALL_KEYS_UP), - RESPONSE (LK_METRONOME), - RESPONSE (LK_OUTPUT_ERROR), - RESPONSE (LK_INPUT_ERROR), - RESPONSE (LK_KBD_LOCKED), - RESPONSE (LK_KBD_TEST_MODE_ACK), - RESPONSE (LK_PREFIX_KEY_DOWN), - RESPONSE (LK_MODE_CHANGE_ACK), - RESPONSE (LK_RESPONSE_RESERVED), + RESPONSE(LK_STUCK_KEY), + RESPONSE(LK_SELFTEST_FAILED), + RESPONSE(LK_ALL_KEYS_UP), + RESPONSE(LK_METRONOME), + RESPONSE(LK_OUTPUT_ERROR), + RESPONSE(LK_INPUT_ERROR), + RESPONSE(LK_KBD_LOCKED), + RESPONSE(LK_KBD_TEST_MODE_ACK), + RESPONSE(LK_PREFIX_KEY_DOWN), + RESPONSE(LK_MODE_CHANGE_ACK), + RESPONSE(LK_RESPONSE_RESERVED), #undef RESPONSE }; -static unsigned char * -response_name (unsigned char value) +static unsigned char *response_name(unsigned char value) { int i; - for (i = 0; i < ARRAY_SIZE (lk_response); i++) + for (i = 0; i < ARRAY_SIZE(lk_response); i++) if (lk_response[i].value == value) return lk_response[i].name; @@ -331,8 +327,7 @@ response_name (unsigned char value) /* * Calculate volume parameter byte for a given volume. */ -static unsigned char -volume_to_hw (int volume_percent) +static unsigned char volume_to_hw(int volume_percent) { unsigned char ret = 0; @@ -363,8 +358,7 @@ volume_to_hw (int volume_percent) return ret; } -static void -lkkbd_detection_done (struct lkkbd *lk) +static void lkkbd_detection_done(struct lkkbd *lk) { int i; @@ -377,190 +371,202 @@ lkkbd_detection_done (struct lkkbd *lk) * Print keyboard name and modify Compose=Alt on user's request. */ switch (lk->id[4]) { - case 1: - strlcpy (lk->name, "DEC LK201 keyboard", - sizeof (lk->name)); - - if (lk201_compose_is_alt) - lk->keycode[0xb1] = KEY_LEFTALT; - break; - - case 2: - strlcpy (lk->name, "DEC LK401 keyboard", - sizeof (lk->name)); - break; - - default: - strlcpy (lk->name, "Unknown DEC keyboard", - sizeof (lk->name)); - printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " - "please report to Jan-Benedict Glaw " - "<jbglaw@lug-owl.de>\n", lk->phys); - printk (KERN_ERR "lkkbd: keyboard ID'ed as:"); - for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) - printk (" 0x%02x", lk->id[i]); - printk ("\n"); - break; + case 1: + strlcpy(lk->name, "DEC LK201 keyboard", sizeof(lk->name)); + + if (lk201_compose_is_alt) + lk->keycode[0xb1] = KEY_LEFTALT; + break; + + case 2: + strlcpy(lk->name, "DEC LK401 keyboard", sizeof(lk->name)); + break; + + default: + strlcpy(lk->name, "Unknown DEC keyboard", sizeof(lk->name)); + printk(KERN_ERR + "lkkbd: keyboard on %s is unknown, please report to " + "Jan-Benedict Glaw <jbglaw@lug-owl.de>\n", lk->phys); + printk(KERN_ERR "lkkbd: keyboard ID'ed as:"); + for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) + printk(" 0x%02x", lk->id[i]); + printk("\n"); + break; } - printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n", - lk->phys, lk->name); + + printk(KERN_INFO "lkkbd: keyboard on %s identified as: %s\n", + lk->phys, lk->name); /* * Report errors during keyboard boot-up. */ switch (lk->id[2]) { - case 0x00: - /* All okay */ - break; - - case LK_STUCK_KEY: - printk (KERN_ERR "lkkbd: Stuck key on keyboard at " - "%s\n", lk->phys); - break; - - case LK_SELFTEST_FAILED: - printk (KERN_ERR "lkkbd: Selftest failed on keyboard " - "at %s, keyboard may not work " - "properly\n", lk->phys); - break; - - default: - printk (KERN_ERR "lkkbd: Unknown error %02x on " - "keyboard at %s\n", lk->id[2], - lk->phys); - break; + case 0x00: + /* All okay */ + break; + + case LK_STUCK_KEY: + printk(KERN_ERR "lkkbd: Stuck key on keyboard at %s\n", + lk->phys); + break; + + case LK_SELFTEST_FAILED: + printk(KERN_ERR + "lkkbd: Selftest failed on keyboard at %s, " + "keyboard may not work properly\n", lk->phys); + break; + + default: + printk(KERN_ERR + "lkkbd: Unknown error %02x on keyboard at %s\n", + lk->id[2], lk->phys); + break; } /* * Try to hint user if there's a stuck key. */ if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0) - printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode " - "is 0x%04x\n", lk->id[3], - lk->keycode[lk->id[3]]); - - return; + printk(KERN_ERR + "Scancode of stuck key is 0x%02x, keycode is 0x%04x\n", + lk->id[3], lk->keycode[lk->id[3]]); } /* * lkkbd_interrupt() is called by the low level driver when a character * is received. */ -static irqreturn_t -lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags) +static irqreturn_t lkkbd_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) { - struct lkkbd *lk = serio_get_drvdata (serio); + struct lkkbd *lk = serio_get_drvdata(serio); + struct input_dev *input_dev = lk->dev; + unsigned int keycode; int i; - DBG (KERN_INFO "Got byte 0x%02x\n", data); + DBG(KERN_INFO "Got byte 0x%02x\n", data); if (lk->ignore_bytes > 0) { - DBG (KERN_INFO "Ignoring a byte on %s\n", lk->name); + DBG(KERN_INFO "Ignoring a byte on %s\n", lk->name); lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; if (lk->ignore_bytes == 0) - lkkbd_detection_done (lk); + lkkbd_detection_done(lk); return IRQ_HANDLED; } switch (data) { - case LK_ALL_KEYS_UP: - for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) - if (lk->keycode[i] != KEY_RESERVED) - input_report_key (lk->dev, lk->keycode[i], 0); - input_sync (lk->dev); - break; - - case 0x01: - DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); - lk->ignore_bytes = LK_NUM_IGNORE_BYTES; - lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; - schedule_work (&lk->tq); - break; - - case LK_METRONOME: - case LK_OUTPUT_ERROR: - case LK_INPUT_ERROR: - case LK_KBD_LOCKED: - case LK_KBD_TEST_MODE_ACK: - case LK_PREFIX_KEY_DOWN: - case LK_MODE_CHANGE_ACK: - case LK_RESPONSE_RESERVED: - DBG (KERN_INFO "Got %s and don't know how to handle...\n", - response_name (data)); - break; - - default: - if (lk->keycode[data] != KEY_RESERVED) { - if (!test_bit (lk->keycode[data], lk->dev->key)) - input_report_key (lk->dev, lk->keycode[data], 1); - else - input_report_key (lk->dev, lk->keycode[data], 0); - input_sync (lk->dev); - } else - printk (KERN_WARNING "%s: Unknown key with " - "scancode 0x%02x on %s.\n", - __FILE__, data, lk->name); + case LK_ALL_KEYS_UP: + for (i = 0; i < ARRAY_SIZE(lkkbd_keycode); i++) + input_report_key(input_dev, lk->keycode[i], 0); + input_sync(input_dev); + break; + + case 0x01: + DBG(KERN_INFO "Got 0x01, scheduling re-initialization\n"); + lk->ignore_bytes = LK_NUM_IGNORE_BYTES; + lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; + schedule_work(&lk->tq); + break; + + case LK_METRONOME: + case LK_OUTPUT_ERROR: + case LK_INPUT_ERROR: + case LK_KBD_LOCKED: + case LK_KBD_TEST_MODE_ACK: + case LK_PREFIX_KEY_DOWN: + case LK_MODE_CHANGE_ACK: + case LK_RESPONSE_RESERVED: + DBG(KERN_INFO "Got %s and don't know how to handle...\n", + response_name(data)); + break; + + default: + keycode = lk->keycode[data]; + if (keycode != KEY_RESERVED) { + input_report_key(input_dev, keycode, + !test_bit(keycode, input_dev->key)); + input_sync(input_dev); + } else { + printk(KERN_WARNING + "%s: Unknown key with scancode 0x%02x on %s.\n", + __FILE__, data, lk->name); + } } return IRQ_HANDLED; } +static void lkkbd_toggle_leds(struct lkkbd *lk) +{ + struct serio *serio = lk->serio; + unsigned char leds_on = 0; + unsigned char leds_off = 0; + + CHECK_LED(lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); + CHECK_LED(lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); + CHECK_LED(lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); + CHECK_LED(lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); + if (leds_on != 0) { + serio_write(serio, LK_CMD_LED_ON); + serio_write(serio, leds_on); + } + if (leds_off != 0) { + serio_write(serio, LK_CMD_LED_OFF); + serio_write(serio, leds_off); + } +} + +static void lkkbd_toggle_keyclick(struct lkkbd *lk, bool on) +{ + struct serio *serio = lk->serio; + + if (on) { + DBG("%s: Activating key clicks\n", __func__); + serio_write(serio, LK_CMD_ENABLE_KEYCLICK); + serio_write(serio, volume_to_hw(lk->keyclick_volume)); + serio_write(serio, LK_CMD_ENABLE_CTRCLICK); + serio_write(serio, volume_to_hw(lk->ctrlclick_volume)); + } else { + DBG("%s: Deactivating key clicks\n", __func__); + serio_write(serio, LK_CMD_DISABLE_KEYCLICK); + serio_write(serio, LK_CMD_DISABLE_CTRCLICK); + } + +} + /* * lkkbd_event() handles events from the input module. */ -static int -lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, - int value) +static int lkkbd_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) { - struct lkkbd *lk = input_get_drvdata (dev); - unsigned char leds_on = 0; - unsigned char leds_off = 0; + struct lkkbd *lk = input_get_drvdata(dev); switch (type) { - case EV_LED: - CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); - CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); - CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); - CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); - if (leds_on != 0) { - serio_write (lk->serio, LK_CMD_LED_ON); - serio_write (lk->serio, leds_on); - } - if (leds_off != 0) { - serio_write (lk->serio, LK_CMD_LED_OFF); - serio_write (lk->serio, leds_off); - } + case EV_LED: + lkkbd_toggle_leds(lk); + return 0; + + case EV_SND: + switch (code) { + case SND_CLICK: + lkkbd_toggle_keyclick(lk, value); return 0; - case EV_SND: - switch (code) { - case SND_CLICK: - if (value == 0) { - DBG ("%s: Deactivating key clicks\n", __func__); - serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK); - serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK); - } else { - DBG ("%s: Activating key clicks\n", __func__); - serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK); - serio_write (lk->serio, volume_to_hw (lk->keyclick_volume)); - serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK); - serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); - } - return 0; - - case SND_BELL: - if (value != 0) - serio_write (lk->serio, LK_CMD_SOUND_BELL); - - return 0; - } - break; - - default: - printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n", - __func__, type, code, value); + case SND_BELL: + if (value != 0) + serio_write(lk->serio, LK_CMD_SOUND_BELL); + + return 0; + } + + break; + + default: + printk(KERN_ERR "%s(): Got unknown type %d, code %d, value %d\n", + __func__, type, code, value); } return -1; @@ -570,79 +576,56 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, * lkkbd_reinit() sets leds and beeps to a state the computer remembers they * were in. */ -static void -lkkbd_reinit (struct work_struct *work) +static void lkkbd_reinit(struct work_struct *work) { struct lkkbd *lk = container_of(work, struct lkkbd, tq); int division; - unsigned char leds_on = 0; - unsigned char leds_off = 0; /* Ask for ID */ - serio_write (lk->serio, LK_CMD_REQUEST_ID); + serio_write(lk->serio, LK_CMD_REQUEST_ID); /* Reset parameters */ - serio_write (lk->serio, LK_CMD_SET_DEFAULTS); + serio_write(lk->serio, LK_CMD_SET_DEFAULTS); /* Set LEDs */ - CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); - CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); - CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); - CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); - if (leds_on != 0) { - serio_write (lk->serio, LK_CMD_LED_ON); - serio_write (lk->serio, leds_on); - } - if (leds_off != 0) { - serio_write (lk->serio, LK_CMD_LED_OFF); - serio_write (lk->serio, leds_off); - } + lkkbd_toggle_leds(lk); /* * Try to activate extended LK401 mode. This command will * only work with a LK401 keyboard and grants access to * LAlt, RAlt, RCompose and RShift. */ - serio_write (lk->serio, LK_CMD_ENABLE_LK401); + serio_write(lk->serio, LK_CMD_ENABLE_LK401); /* Set all keys to UPDOWN mode */ for (division = 1; division <= 14; division++) - serio_write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, - division)); + serio_write(lk->serio, + LK_CMD_SET_MODE(LK_MODE_UPDOWN, division)); /* Enable bell and set volume */ - serio_write (lk->serio, LK_CMD_ENABLE_BELL); - serio_write (lk->serio, volume_to_hw (lk->bell_volume)); + serio_write(lk->serio, LK_CMD_ENABLE_BELL); + serio_write(lk->serio, volume_to_hw(lk->bell_volume)); /* Enable/disable keyclick (and possibly set volume) */ - if (test_bit (SND_CLICK, lk->dev->snd)) { - serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK); - serio_write (lk->serio, volume_to_hw (lk->keyclick_volume)); - serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK); - serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); - } else { - serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK); - serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK); - } + lkkbd_toggle_keyclick(lk, test_bit(SND_CLICK, lk->dev->snd)); /* Sound the bell if needed */ - if (test_bit (SND_BELL, lk->dev->snd)) - serio_write (lk->serio, LK_CMD_SOUND_BELL); + if (test_bit(SND_BELL, lk->dev->snd)) + serio_write(lk->serio, LK_CMD_SOUND_BELL); } /* * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. */ -static int -lkkbd_connect (struct serio *serio, struct serio_driver *drv) +static int lkkbd_connect(struct serio *serio, struct serio_driver *drv) { struct lkkbd *lk; struct input_dev *input_dev; int i; int err; - lk = kzalloc (sizeof (struct lkkbd), GFP_KERNEL); - input_dev = input_allocate_device (); + lk = kzalloc(sizeof(struct lkkbd), GFP_KERNEL); + input_dev = input_allocate_device(); if (!lk || !input_dev) { err = -ENOMEM; goto fail1; @@ -650,14 +633,14 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) lk->serio = serio; lk->dev = input_dev; - INIT_WORK (&lk->tq, lkkbd_reinit); + INIT_WORK(&lk->tq, lkkbd_reinit); lk->bell_volume = bell_volume; lk->keyclick_volume = keyclick_volume; lk->ctrlclick_volume = ctrlclick_volume; - memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); + memcpy(lk->keycode, lkkbd_keycode, sizeof(lk->keycode)); - strlcpy (lk->name, "DEC LK keyboard", sizeof(lk->name)); - snprintf (lk->phys, sizeof(lk->phys), "%s/input0", serio->phys); + strlcpy(lk->name, "DEC LK keyboard", sizeof(lk->name)); + snprintf(lk->phys, sizeof(lk->phys), "%s/input0", serio->phys); input_dev->name = lk->name; input_dev->phys = lk->phys; @@ -668,62 +651,61 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) input_dev->dev.parent = &serio->dev; input_dev->event = lkkbd_event; - input_set_drvdata (input_dev, lk); + input_set_drvdata(input_dev, lk); - set_bit (EV_KEY, input_dev->evbit); - set_bit (EV_LED, input_dev->evbit); - set_bit (EV_SND, input_dev->evbit); - set_bit (EV_REP, input_dev->evbit); - set_bit (LED_CAPSL, input_dev->ledbit); - set_bit (LED_SLEEP, input_dev->ledbit); - set_bit (LED_COMPOSE, input_dev->ledbit); - set_bit (LED_SCROLLL, input_dev->ledbit); - set_bit (SND_BELL, input_dev->sndbit); - set_bit (SND_CLICK, input_dev->sndbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(EV_LED, input_dev->evbit); + __set_bit(EV_SND, input_dev->evbit); + __set_bit(EV_REP, input_dev->evbit); + __set_bit(LED_CAPSL, input_dev->ledbit); + __set_bit(LED_SLEEP, input_dev->ledbit); + __set_bit(LED_COMPOSE, input_dev->ledbit); + __set_bit(LED_SCROLLL, input_dev->ledbit); + __set_bit(SND_BELL, input_dev->sndbit); + __set_bit(SND_CLICK, input_dev->sndbit); input_dev->keycode = lk->keycode; - input_dev->keycodesize = sizeof (lk_keycode_t); - input_dev->keycodemax = LK_NUM_KEYCODES; + input_dev->keycodesize = sizeof(lk->keycode[0]); + input_dev->keycodemax = ARRAY_SIZE(lk->keycode); for (i = 0; i < LK_NUM_KEYCODES; i++) - __set_bit (lk->keycode[i], input_dev->keybit); + __set_bit(lk->keycode[i], input_dev->keybit); __clear_bit(KEY_RESERVED, input_dev->keybit); - serio_set_drvdata (serio, lk); + serio_set_drvdata(serio, lk); - err = serio_open (serio, drv); + err = serio_open(serio, drv); if (err) goto fail2; - err = input_register_device (lk->dev); + err = input_register_device(lk->dev); if (err) goto fail3; - serio_write (lk->serio, LK_CMD_POWERCYCLE_RESET); + serio_write(lk->serio, LK_CMD_POWERCYCLE_RESET); return 0; - fail3: serio_close (serio); - fail2: serio_set_drvdata (serio, NULL); - fail1: input_free_device (input_dev); - kfree (lk); + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(lk); return err; } /* * lkkbd_disconnect() unregisters and closes behind us. */ -static void -lkkbd_disconnect (struct serio *serio) +static void lkkbd_disconnect(struct serio *serio) { - struct lkkbd *lk = serio_get_drvdata (serio); - - input_get_device (lk->dev); - input_unregister_device (lk->dev); - serio_close (serio); - serio_set_drvdata (serio, NULL); - input_put_device (lk->dev); - kfree (lk); + struct lkkbd *lk = serio_get_drvdata(serio); + + input_get_device(lk->dev); + input_unregister_device(lk->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(lk->dev); + kfree(lk); } static struct serio_device_id lkkbd_serio_ids[] = { @@ -752,18 +734,16 @@ static struct serio_driver lkkbd_drv = { /* * The functions for insering/removing us as a module. */ -static int __init -lkkbd_init (void) +static int __init lkkbd_init(void) { return serio_register_driver(&lkkbd_drv); } -static void __exit -lkkbd_exit (void) +static void __exit lkkbd_exit(void) { serio_unregister_driver(&lkkbd_drv); } -module_init (lkkbd_init); -module_exit (lkkbd_exit); +module_init(lkkbd_init); +module_exit(lkkbd_exit); diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 91cfe5170265..34f4a29d4973 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -213,8 +213,9 @@ static void matrix_keypad_stop(struct input_dev *dev) } #ifdef CONFIG_PM -static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t state) +static int matrix_keypad_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct matrix_keypad *keypad = platform_get_drvdata(pdev); const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i; @@ -228,8 +229,9 @@ static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t stat return 0; } -static int matrix_keypad_resume(struct platform_device *pdev) +static int matrix_keypad_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct matrix_keypad *keypad = platform_get_drvdata(pdev); const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i; @@ -242,9 +244,9 @@ static int matrix_keypad_resume(struct platform_device *pdev) return 0; } -#else -#define matrix_keypad_suspend NULL -#define matrix_keypad_resume NULL + +static const SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops, + matrix_keypad_suspend, matrix_keypad_resume); #endif static int __devinit init_matrix_gpio(struct platform_device *pdev, @@ -417,11 +419,12 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev) static struct platform_driver matrix_keypad_driver = { .probe = matrix_keypad_probe, .remove = __devexit_p(matrix_keypad_remove), - .suspend = matrix_keypad_suspend, - .resume = matrix_keypad_resume, .driver = { .name = "matrix-keypad", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &matrix_keypad_pm_ops, +#endif }, }; diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index bba85add35a3..1a494d505431 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -35,12 +35,12 @@ #include <linux/mutex.h> #include <linux/errno.h> #include <mach/gpio.h> -#include <mach/keypad.h> -#include <mach/menelaus.h> +#include <plat/keypad.h> +#include <plat/menelaus.h> #include <asm/irq.h> #include <mach/hardware.h> #include <asm/io.h> -#include <mach/mux.h> +#include <plat/mux.h> #undef NEW_BOARD_LEARNING_MODE diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 887af79b7bff..8e9380bfed40 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -18,9 +18,9 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/input.h> +#include <linux/input/sh_keysc.h> #include <linux/clk.h> #include <linux/io.h> -#include <asm/sh_keysc.h> #define KYCR1_OFFS 0x00 #define KYCR2_OFFS 0x04 @@ -295,7 +295,7 @@ static int sh_keysc_resume(struct device *dev) return 0; } -static struct dev_pm_ops sh_keysc_dev_pm_ops = { +static const struct dev_pm_ops sh_keysc_dev_pm_ops = { .suspend = sh_keysc_suspend, .resume = sh_keysc_resume, }; diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 9a2977c21696..eeaa7acb9cfc 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -31,7 +31,7 @@ #include <linux/interrupt.h> #include <linux/input.h> #include <linux/platform_device.h> -#include <linux/i2c/twl4030.h> +#include <linux/i2c/twl.h> /* @@ -133,7 +133,7 @@ struct twl4030_keypad { static int twl4030_kpread(struct twl4030_keypad *kp, u8 *data, u32 reg, u8 num_bytes) { - int ret = twl4030_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes); + int ret = twl_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes); if (ret < 0) dev_warn(kp->dbg_dev, @@ -145,7 +145,7 @@ static int twl4030_kpread(struct twl4030_keypad *kp, static int twl4030_kpwrite_u8(struct twl4030_keypad *kp, u8 data, u32 reg) { - int ret = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg); + int ret = twl_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg); if (ret < 0) dev_warn(kp->dbg_dev, diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index a9bb2544b2de..16ec5233441c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -80,6 +80,7 @@ config INPUT_WISTRON_BTNS tristate "x86 Wistron laptop button interface" depends on X86 && !X86_64 select INPUT_POLLDEV + select INPUT_SPARSEKMAP select NEW_LEDS select LEDS_CLASS select CHECK_SIGNATURE @@ -281,6 +282,7 @@ config INPUT_RB532_BUTTON config INPUT_DM355EVM tristate "TI DaVinci DM355 EVM Keypad and IR Remote" depends on MFD_DM355EVM_MSP + select INPUT_SPARSEKMAP help Supports the pushbuttons and IR remote used with the DM355 EVM board. diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c index e290fde35e74..614b65d78fe9 100644 --- a/drivers/input/misc/ati_remote.c +++ b/drivers/input/misc/ati_remote.c @@ -766,7 +766,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de ati_remote->interface = interface; usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); - strlcpy(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); + strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); if (udev->manufacturer) strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c index 690f3fafa03b..61d10177fa83 100644 --- a/drivers/input/misc/bfin_rotary.c +++ b/drivers/input/misc/bfin_rotary.c @@ -247,7 +247,7 @@ static int bfin_rotary_resume(struct device *dev) return 0; } -static struct dev_pm_ops bfin_rotary_pm_ops = { +static const struct dev_pm_ops bfin_rotary_pm_ops = { .suspend = bfin_rotary_suspend, .resume = bfin_rotary_resume, }; diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index f2b67dc81d80..766c06911f41 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/input.h> +#include <linux/input/sparse-keymap.h> #include <linux/platform_device.h> #include <linux/interrupt.h> @@ -33,12 +34,8 @@ struct dm355evm_keys { int irq; }; -/* These initial keycodes can be remapped by dm355evm_setkeycode(). */ -static struct { - u16 event; - u16 keycode; -} dm355evm_keys[] = { - +/* These initial keycodes can be remapped */ +static const struct key_entry dm355evm_keys[] = { /* * Pushbuttons on the EVM board ... note that the labels for these * are SW10/SW11/etc on the PC board. The left/right orientation @@ -47,11 +44,11 @@ static struct { * is to the right. (That is, rotate the board counter-clockwise * by 90 degrees from the SW10/etc and "DM355 EVM" labels.) */ - { 0x00d8, KEY_OK, }, /* SW12 */ - { 0x00b8, KEY_UP, }, /* SW13 */ - { 0x00e8, KEY_DOWN, }, /* SW11 */ - { 0x0078, KEY_LEFT, }, /* SW14 */ - { 0x00f0, KEY_RIGHT, }, /* SW10 */ + { KE_KEY, 0x00d8, { KEY_OK } }, /* SW12 */ + { KE_KEY, 0x00b8, { KEY_UP } }, /* SW13 */ + { KE_KEY, 0x00e8, { KEY_DOWN } }, /* SW11 */ + { KE_KEY, 0x0078, { KEY_LEFT } }, /* SW14 */ + { KE_KEY, 0x00f0, { KEY_RIGHT } }, /* SW10 */ /* * IR buttons ... codes assigned to match the universal remote @@ -65,35 +62,35 @@ static struct { * RC5 codes are 14 bits, with two start bits (0x3 prefix) * and a toggle bit (masked out below). */ - { 0x300c, KEY_POWER, }, /* NOTE: docs omit this */ - { 0x3000, KEY_NUMERIC_0, }, - { 0x3001, KEY_NUMERIC_1, }, - { 0x3002, KEY_NUMERIC_2, }, - { 0x3003, KEY_NUMERIC_3, }, - { 0x3004, KEY_NUMERIC_4, }, - { 0x3005, KEY_NUMERIC_5, }, - { 0x3006, KEY_NUMERIC_6, }, - { 0x3007, KEY_NUMERIC_7, }, - { 0x3008, KEY_NUMERIC_8, }, - { 0x3009, KEY_NUMERIC_9, }, - { 0x3022, KEY_ENTER, }, - { 0x30ec, KEY_MODE, }, /* "tv/vcr/..." */ - { 0x300f, KEY_SELECT, }, /* "info" */ - { 0x3020, KEY_CHANNELUP, }, /* "up" */ - { 0x302e, KEY_MENU, }, /* "in/out" */ - { 0x3011, KEY_VOLUMEDOWN, }, /* "left" */ - { 0x300d, KEY_MUTE, }, /* "ok" */ - { 0x3010, KEY_VOLUMEUP, }, /* "right" */ - { 0x301e, KEY_SUBTITLE, }, /* "cc" */ - { 0x3021, KEY_CHANNELDOWN, }, /* "down" */ - { 0x3022, KEY_PREVIOUS, }, - { 0x3026, KEY_SLEEP, }, - { 0x3172, KEY_REWIND, }, /* NOTE: docs wrongly say 0x30ca */ - { 0x3175, KEY_PLAY, }, - { 0x3174, KEY_FASTFORWARD, }, - { 0x3177, KEY_RECORD, }, - { 0x3176, KEY_STOP, }, - { 0x3169, KEY_PAUSE, }, + { KE_KEY, 0x300c, { KEY_POWER } }, /* NOTE: docs omit this */ + { KE_KEY, 0x3000, { KEY_NUMERIC_0 } }, + { KE_KEY, 0x3001, { KEY_NUMERIC_1 } }, + { KE_KEY, 0x3002, { KEY_NUMERIC_2 } }, + { KE_KEY, 0x3003, { KEY_NUMERIC_3 } }, + { KE_KEY, 0x3004, { KEY_NUMERIC_4 } }, + { KE_KEY, 0x3005, { KEY_NUMERIC_5 } }, + { KE_KEY, 0x3006, { KEY_NUMERIC_6 } }, + { KE_KEY, 0x3007, { KEY_NUMERIC_7 } }, + { KE_KEY, 0x3008, { KEY_NUMERIC_8 } }, + { KE_KEY, 0x3009, { KEY_NUMERIC_9 } }, + { KE_KEY, 0x3022, { KEY_ENTER } }, + { KE_KEY, 0x30ec, { KEY_MODE } }, /* "tv/vcr/..." */ + { KE_KEY, 0x300f, { KEY_SELECT } }, /* "info" */ + { KE_KEY, 0x3020, { KEY_CHANNELUP } }, /* "up" */ + { KE_KEY, 0x302e, { KEY_MENU } }, /* "in/out" */ + { KE_KEY, 0x3011, { KEY_VOLUMEDOWN } }, /* "left" */ + { KE_KEY, 0x300d, { KEY_MUTE } }, /* "ok" */ + { KE_KEY, 0x3010, { KEY_VOLUMEUP } }, /* "right" */ + { KE_KEY, 0x301e, { KEY_SUBTITLE } }, /* "cc" */ + { KE_KEY, 0x3021, { KEY_CHANNELDOWN } },/* "down" */ + { KE_KEY, 0x3022, { KEY_PREVIOUS } }, + { KE_KEY, 0x3026, { KEY_SLEEP } }, + { KE_KEY, 0x3172, { KEY_REWIND } }, /* NOTE: docs wrongly say 0x30ca */ + { KE_KEY, 0x3175, { KEY_PLAY } }, + { KE_KEY, 0x3174, { KEY_FASTFORWARD } }, + { KE_KEY, 0x3177, { KEY_RECORD } }, + { KE_KEY, 0x3176, { KEY_STOP } }, + { KE_KEY, 0x3169, { KEY_PAUSE } }, }; /* @@ -105,19 +102,18 @@ static struct { */ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) { - struct dm355evm_keys *keys = _keys; - int status; + static u16 last_event; + struct dm355evm_keys *keys = _keys; + const struct key_entry *ke; + unsigned int keycode; + int status; + u16 event; /* For simplicity we ignore INPUT_COUNT and just read * events until we get the "queue empty" indicator. * Reading INPUT_LOW decrements the count. */ for (;;) { - static u16 last_event; - u16 event; - int keycode; - int i; - status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH); if (status < 0) { dev_dbg(keys->dev, "input high err %d\n", @@ -156,14 +152,9 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) /* ignore the RC5 toggle bit */ event &= ~0x0800; - /* find the key, or leave it as unknown */ - keycode = KEY_UNKNOWN; - for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { - if (dm355evm_keys[i].event != event) - continue; - keycode = dm355evm_keys[i].keycode; - break; - } + /* find the key, or report it as unknown */ + ke = sparse_keymap_entry_from_scancode(keys->input, event); + keycode = ke ? ke->keycode : KEY_UNKNOWN; dev_dbg(keys->dev, "input event 0x%04x--> keycode %d\n", event, keycode); @@ -174,36 +165,8 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) input_report_key(keys->input, keycode, 0); input_sync(keys->input); } - return IRQ_HANDLED; -} -static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode) -{ - u16 old_keycode; - unsigned i; - - if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) - return -EINVAL; - - old_keycode = dm355evm_keys[index].keycode; - dm355evm_keys[index].keycode = keycode; - set_bit(keycode, dev->keybit); - - for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { - if (dm355evm_keys[index].keycode == old_keycode) - goto done; - } - clear_bit(old_keycode, dev->keybit); -done: - return 0; -} - -static int dm355evm_getkeycode(struct input_dev *dev, int index, int *keycode) -{ - if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) - return -EINVAL; - - return dm355evm_keys[index].keycode; + return IRQ_HANDLED; } /*----------------------------------------------------------------------*/ @@ -213,7 +176,6 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev) struct dm355evm_keys *keys; struct input_dev *input; int status; - int i; /* allocate instance struct and input dev */ keys = kzalloc(sizeof *keys, GFP_KERNEL); @@ -242,31 +204,30 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev) input->id.product = 0x0355; input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV); - input->evbit[0] = BIT(EV_KEY); - for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) - __set_bit(dm355evm_keys[i].keycode, input->keybit); - - input->setkeycode = dm355evm_setkeycode; - input->getkeycode = dm355evm_getkeycode; + status = sparse_keymap_setup(input, dm355evm_keys, NULL); + if (status) + goto fail1; /* REVISIT: flush the event queue? */ status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq, IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys); if (status < 0) - goto fail1; + goto fail2; /* register */ status = input_register_device(input); if (status < 0) - goto fail2; + goto fail3; platform_set_drvdata(pdev, keys); return 0; -fail2: +fail3: free_irq(keys->irq, keys); +fail2: + sparse_keymap_free(input); fail1: input_free_device(input); kfree(keys); @@ -280,6 +241,7 @@ static int __devexit dm355evm_keys_remove(struct platform_device *pdev) struct dm355evm_keys *keys = platform_get_drvdata(pdev); free_irq(keys->irq, keys); + sparse_keymap_free(keys->input); input_unregister_device(keys->input); kfree(keys); diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index ea821b546969..ad730e15afc0 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -35,7 +35,6 @@ #include <linux/hp_sdc.h> #include <linux/errno.h> -#include <linux/smp_lock.h> #include <linux/types.h> #include <linux/init.h> #include <linux/module.h> @@ -409,7 +408,6 @@ static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait) static int hp_sdc_rtc_open(struct inode *inode, struct file *file) { - cycle_kernel_lock(); return 0; } diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c index 039dcb00ebd9..008de0c5834b 100644 --- a/drivers/input/misc/pcf50633-input.c +++ b/drivers/input/misc/pcf50633-input.c @@ -55,7 +55,6 @@ pcf50633_input_irq(int irq, void *data) static int __devinit pcf50633_input_probe(struct platform_device *pdev) { struct pcf50633_input *input; - struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data; struct input_dev *input_dev; int ret; @@ -71,7 +70,7 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, input); - input->pcf = pdata->pcf; + input->pcf = dev_to_pcf50633(pdev->dev.parent); input->input_dev = input_dev; input_dev->name = "PCF50633 PMU events"; @@ -85,9 +84,9 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev) kfree(input); return ret; } - pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYR, + pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR, pcf50633_input_irq, input); - pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYF, + pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF, pcf50633_input_irq, input); return 0; diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 21cb755a54fb..ea4e1fd12651 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -127,7 +127,7 @@ static void pcspkr_shutdown(struct platform_device *dev) pcspkr_event(NULL, EV_SND, SND_BELL, 0); } -static struct dev_pm_ops pcspkr_pm_ops = { +static const struct dev_pm_ops pcspkr_pm_ops = { .suspend = pcspkr_suspend, }; diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index a53c4885fbad..668913d12044 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -338,7 +338,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i pm->input = input_dev; usb_make_path(udev, pm->phys, sizeof(pm->phys)); - strlcpy(pm->phys, "/input0", sizeof(pm->phys)); + strlcat(pm->phys, "/input0", sizeof(pm->phys)); spin_lock_init(&pm->lock); diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index f5fc9974a111..bdde5c889035 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -27,7 +27,7 @@ #include <linux/input.h> #include <linux/interrupt.h> #include <linux/platform_device.h> -#include <linux/i2c/twl4030.h> +#include <linux/i2c/twl.h> #define PWR_PWRON_IRQ (1 << 0) @@ -49,7 +49,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr) local_irq_enable(); #endif - err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, + err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, STS_HW_CONDITIONS); if (!err) { input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index a932179c4c9e..38da6ab04384 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -21,6 +21,7 @@ #include <linux/dmi.h> #include <linux/init.h> #include <linux/input-polldev.h> +#include <linux/input/sparse-keymap.h> #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/kernel.h> @@ -224,19 +225,8 @@ static void bios_set_state(u8 subsys, int enable) /* Hardware database */ -struct key_entry { - char type; /* See KE_* below */ - u8 code; - union { - u16 keycode; /* For KE_KEY */ - struct { /* For KE_SW */ - u8 code; - u8 value; - } sw; - }; -}; - -enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; +#define KE_WIFI (KE_LAST + 1) +#define KE_BLUETOOTH (KE_LAST + 2) #define FE_MAIL_LED 0x01 #define FE_WIFI_LED 0x02 @@ -644,10 +634,10 @@ static struct key_entry keymap_prestigio[] __initdata = { * a list of buttons and their key codes (reported when loading this module * with force=1) and the output of dmidecode to $MODULE_AUTHOR. */ -static struct dmi_system_id dmi_ids[] __initdata = { +static const struct dmi_system_id __initconst dmi_ids[] = { { + /* Fujitsu-Siemens Amilo Pro V2000 */ .callback = dmi_matched, - .ident = "Fujitsu-Siemens Amilo Pro V2000", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"), @@ -655,8 +645,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Fujitsu-Siemens Amilo Pro Edition V3505 */ .callback = dmi_matched, - .ident = "Fujitsu-Siemens Amilo Pro Edition V3505", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"), @@ -664,8 +654,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v3505 }, { + /* Fujitsu-Siemens Amilo M7400 */ .callback = dmi_matched, - .ident = "Fujitsu-Siemens Amilo M7400", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "), @@ -673,8 +663,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Maxdata Pro 7000 DX */ .callback = dmi_matched, - .ident = "Maxdata Pro 7000 DX", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"), DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"), @@ -682,8 +672,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Fujitsu N3510 */ .callback = dmi_matched, - .ident = "Fujitsu N3510", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "N3510"), @@ -691,8 +681,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fujitsu_n3510 }, { + /* Acer Aspire 1500 */ .callback = dmi_matched, - .ident = "Acer Aspire 1500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"), @@ -700,8 +690,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_1500 }, { + /* Acer Aspire 1600 */ .callback = dmi_matched, - .ident = "Acer Aspire 1600", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"), @@ -709,8 +699,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_1600 }, { + /* Acer Aspire 3020 */ .callback = dmi_matched, - .ident = "Acer Aspire 3020", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"), @@ -718,8 +708,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_5020 }, { + /* Acer Aspire 5020 */ .callback = dmi_matched, - .ident = "Acer Aspire 5020", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"), @@ -727,8 +717,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_5020 }, { + /* Acer TravelMate 2100 */ .callback = dmi_matched, - .ident = "Acer TravelMate 2100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"), @@ -736,8 +726,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_5020 }, { + /* Acer TravelMate 2410 */ .callback = dmi_matched, - .ident = "Acer TravelMate 2410", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"), @@ -745,8 +735,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_2410 }, { + /* Acer TravelMate C300 */ .callback = dmi_matched, - .ident = "Acer TravelMate C300", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"), @@ -754,8 +744,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_300 }, { + /* Acer TravelMate C100 */ .callback = dmi_matched, - .ident = "Acer TravelMate C100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"), @@ -763,8 +753,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_300 }, { + /* Acer TravelMate C110 */ .callback = dmi_matched, - .ident = "Acer TravelMate C110", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"), @@ -772,8 +762,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_110 }, { + /* Acer TravelMate 380 */ .callback = dmi_matched, - .ident = "Acer TravelMate 380", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"), @@ -781,8 +771,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_380 }, { + /* Acer TravelMate 370 */ .callback = dmi_matched, - .ident = "Acer TravelMate 370", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"), @@ -790,8 +780,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */ }, { + /* Acer TravelMate 220 */ .callback = dmi_matched, - .ident = "Acer TravelMate 220", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"), @@ -799,8 +789,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_220 }, { + /* Acer TravelMate 260 */ .callback = dmi_matched, - .ident = "Acer TravelMate 260", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"), @@ -808,8 +798,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_220 }, { + /* Acer TravelMate 230 */ .callback = dmi_matched, - .ident = "Acer TravelMate 230", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"), @@ -818,8 +808,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_230 }, { + /* Acer TravelMate 280 */ .callback = dmi_matched, - .ident = "Acer TravelMate 280", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"), @@ -827,8 +817,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_230 }, { + /* Acer TravelMate 240 */ .callback = dmi_matched, - .ident = "Acer TravelMate 240", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"), @@ -836,8 +826,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_240 }, { + /* Acer TravelMate 250 */ .callback = dmi_matched, - .ident = "Acer TravelMate 250", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"), @@ -845,8 +835,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_240 }, { + /* Acer TravelMate 2424NWXCi */ .callback = dmi_matched, - .ident = "Acer TravelMate 2424NWXCi", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"), @@ -854,8 +844,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_240 }, { + /* Acer TravelMate 350 */ .callback = dmi_matched, - .ident = "Acer TravelMate 350", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"), @@ -863,8 +853,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_350 }, { + /* Acer TravelMate 360 */ .callback = dmi_matched, - .ident = "Acer TravelMate 360", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), @@ -872,8 +862,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_360 }, { + /* Acer TravelMate 610 */ .callback = dmi_matched, - .ident = "Acer TravelMate 610", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ACER"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"), @@ -881,8 +871,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_610 }, { + /* Acer TravelMate 620 */ .callback = dmi_matched, - .ident = "Acer TravelMate 620", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"), @@ -890,8 +880,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_630 }, { + /* Acer TravelMate 630 */ .callback = dmi_matched, - .ident = "Acer TravelMate 630", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"), @@ -899,8 +889,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_630 }, { + /* AOpen 1559AS */ .callback = dmi_matched, - .ident = "AOpen 1559AS", .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "E2U"), DMI_MATCH(DMI_BOARD_NAME, "E2U"), @@ -908,8 +898,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_aopen_1559as }, { + /* Medion MD 9783 */ .callback = dmi_matched, - .ident = "Medion MD 9783", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"), @@ -917,8 +907,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_ms2111 }, { + /* Medion MD 40100 */ .callback = dmi_matched, - .ident = "Medion MD 40100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"), @@ -926,8 +916,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md40100 }, { + /* Medion MD 2900 */ .callback = dmi_matched, - .ident = "Medion MD 2900", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"), @@ -935,8 +925,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md2900 }, { + /* Medion MD 42200 */ .callback = dmi_matched, - .ident = "Medion MD 42200", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Medion"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"), @@ -944,8 +934,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Medion MD 96500 */ .callback = dmi_matched, - .ident = "Medion MD 96500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"), @@ -953,8 +943,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md96500 }, { + /* Medion MD 95400 */ .callback = dmi_matched, - .ident = "Medion MD 95400", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"), @@ -962,8 +952,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md96500 }, { + /* Fujitsu Siemens Amilo D7820 */ .callback = dmi_matched, - .ident = "Fujitsu Siemens Amilo D7820", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */ DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"), @@ -971,8 +961,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_d88x0 }, { + /* Fujitsu Siemens Amilo D88x0 */ .callback = dmi_matched, - .ident = "Fujitsu Siemens Amilo D88x0", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"), @@ -1037,21 +1027,6 @@ static unsigned long jiffies_last_press; static bool wifi_enabled; static bool bluetooth_enabled; -static void report_key(struct input_dev *dev, unsigned int keycode) -{ - input_report_key(dev, keycode, 1); - input_sync(dev); - input_report_key(dev, keycode, 0); - input_sync(dev); -} - -static void report_switch(struct input_dev *dev, unsigned int code, int value) -{ - input_report_switch(dev, code, value); - input_sync(dev); -} - - /* led management */ static void wistron_mail_led_set(struct led_classdev *led_cdev, enum led_brightness value) @@ -1128,43 +1103,13 @@ static inline void wistron_led_resume(void) led_classdev_resume(&wistron_wifi_led); } -static struct key_entry *wistron_get_entry_by_scancode(int code) -{ - struct key_entry *key; - - for (key = keymap; key->type != KE_END; key++) - if (code == key->code) - return key; - - return NULL; -} - -static struct key_entry *wistron_get_entry_by_keycode(int keycode) -{ - struct key_entry *key; - - for (key = keymap; key->type != KE_END; key++) - if (key->type == KE_KEY && keycode == key->keycode) - return key; - - return NULL; -} - static void handle_key(u8 code) { - const struct key_entry *key = wistron_get_entry_by_scancode(code); + const struct key_entry *key = + sparse_keymap_entry_from_scancode(wistron_idev->input, code); if (key) { switch (key->type) { - case KE_KEY: - report_key(wistron_idev->input, key->keycode); - break; - - case KE_SW: - report_switch(wistron_idev->input, - key->sw.code, key->sw.value); - break; - case KE_WIFI: if (have_wifi) { wifi_enabled = !wifi_enabled; @@ -1180,7 +1125,9 @@ static void handle_key(u8 code) break; default: - BUG(); + sparse_keymap_report_entry(wistron_idev->input, + key, 1, true); + break; } jiffies_last_press = jiffies; } else @@ -1220,42 +1167,39 @@ static void wistron_poll(struct input_polled_dev *dev) dev->poll_interval = POLL_INTERVAL_DEFAULT; } -static int wistron_getkeycode(struct input_dev *dev, int scancode, int *keycode) +static int __devinit wistron_setup_keymap(struct input_dev *dev, + struct key_entry *entry) { - const struct key_entry *key = wistron_get_entry_by_scancode(scancode); + switch (entry->type) { - if (key && key->type == KE_KEY) { - *keycode = key->keycode; - return 0; - } - - return -EINVAL; -} + /* if wifi or bluetooth are not available, create normal keys */ + case KE_WIFI: + if (!have_wifi) { + entry->type = KE_KEY; + entry->keycode = KEY_WLAN; + } + break; -static int wistron_setkeycode(struct input_dev *dev, int scancode, int keycode) -{ - struct key_entry *key; - int old_keycode; - - if (keycode < 0 || keycode > KEY_MAX) - return -EINVAL; - - key = wistron_get_entry_by_scancode(scancode); - if (key && key->type == KE_KEY) { - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!wistron_get_entry_by_keycode(old_keycode)) - clear_bit(old_keycode, dev->keybit); - return 0; + case KE_BLUETOOTH: + if (!have_bluetooth) { + entry->type = KE_KEY; + entry->keycode = KEY_BLUETOOTH; + } + break; + + case KE_END: + if (entry->code & FE_UNTESTED) + printk(KERN_WARNING "Untested laptop multimedia keys, " + "please report success or failure to " + "eric.piel@tremplin-utc.net\n"); + break; } - return -EINVAL; + return 0; } static int __devinit setup_input_dev(void) { - struct key_entry *key; struct input_dev *input_dev; int error; @@ -1263,7 +1207,7 @@ static int __devinit setup_input_dev(void) if (!wistron_idev) return -ENOMEM; - wistron_idev->flush = wistron_flush; + wistron_idev->open = wistron_flush; wistron_idev->poll = wistron_poll; wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT; @@ -1273,56 +1217,21 @@ static int __devinit setup_input_dev(void) input_dev->id.bustype = BUS_HOST; input_dev->dev.parent = &wistron_device->dev; - input_dev->getkeycode = wistron_getkeycode; - input_dev->setkeycode = wistron_setkeycode; - - for (key = keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, input_dev->evbit); - set_bit(key->keycode, input_dev->keybit); - break; - - case KE_SW: - set_bit(EV_SW, input_dev->evbit); - set_bit(key->sw.code, input_dev->swbit); - break; - - /* if wifi or bluetooth are not available, create normal keys */ - case KE_WIFI: - if (!have_wifi) { - key->type = KE_KEY; - key->keycode = KEY_WLAN; - key--; - } - break; - - case KE_BLUETOOTH: - if (!have_bluetooth) { - key->type = KE_KEY; - key->keycode = KEY_BLUETOOTH; - key--; - } - break; - - default: - break; - } - } - - /* reads information flags on KE_END */ - if (key->code & FE_UNTESTED) - printk(KERN_WARNING "Untested laptop multimedia keys, " - "please report success or failure to eric.piel" - "@tremplin-utc.net\n"); + error = sparse_keymap_setup(input_dev, keymap, wistron_setup_keymap); + if (error) + goto err_free_dev; error = input_register_polled_device(wistron_idev); - if (error) { - input_free_polled_device(wistron_idev); - return error; - } + if (error) + goto err_free_keymap; return 0; + + err_free_keymap: + sparse_keymap_free(input_dev); + err_free_dev: + input_free_polled_device(wistron_idev); + return error; } /* Driver core */ @@ -1371,6 +1280,7 @@ static int __devexit wistron_remove(struct platform_device *dev) { wistron_led_remove(); input_unregister_polled_device(wistron_idev); + sparse_keymap_free(wistron_idev->input); input_free_polled_device(wistron_idev); bios_detach(); diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f36110689aae..f93c2c0daf1f 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -5,6 +5,7 @@ * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> + * Copyright (c) 2009 Sebastian Kapfer <sebastian_kapfer@gmx.net> * * ALPS detection, tap switching and status querying info is taken from * tpconfig utility (by C. Scott Ananian and Bruce Kall). @@ -28,13 +29,16 @@ #define dbg(format, arg...) do {} while (0) #endif -#define ALPS_DUALPOINT 0x01 -#define ALPS_WHEEL 0x02 -#define ALPS_FW_BK_1 0x04 -#define ALPS_4BTN 0x08 -#define ALPS_OLDPROTO 0x10 -#define ALPS_PASS 0x20 -#define ALPS_FW_BK_2 0x40 +#define ALPS_OLDPROTO 0x01 /* old style input */ +#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ +#define ALPS_PASS 0x04 /* device has a pass-through port */ + +#define ALPS_WHEEL 0x08 /* hardware wheel present */ +#define ALPS_FW_BK_1 0x10 /* front & back buttons present */ +#define ALPS_FW_BK_2 0x20 /* front & back buttons present */ +#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ +#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with + 6-byte ALPS packet */ static const struct alps_model_info alps_model_data[] = { { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ @@ -55,8 +59,10 @@ static const struct alps_model_info alps_model_data[] = { { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ - { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ - { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 }, /* Dell Vostro 1400 */ + /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ + { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, + ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, + { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ }; /* @@ -66,42 +72,99 @@ static const struct alps_model_info alps_model_data[] = { */ /* - * ALPS abolute Mode - new format + * PS/2 packet format + * + * byte 0: 0 0 YSGN XSGN 1 M R L + * byte 1: X7 X6 X5 X4 X3 X2 X1 X0 + * byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + * + * Note that the device never signals overflow condition. + * + * ALPS absolute Mode - new format * * byte 0: 1 ? ? ? 1 ? ? ? * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 - * byte 2: 0 x10 x9 x8 x7 ? fin ges + * byte 2: 0 x10 x9 x8 x7 ? fin ges * byte 3: 0 y9 y8 y7 1 M R L * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 * + * Dualpoint device -- interleaved packet format + * + * byte 0: 1 1 0 0 1 1 1 1 + * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 + * byte 2: 0 x10 x9 x8 x7 0 fin ges + * byte 3: 0 0 YSGN XSGN 1 1 1 1 + * byte 4: X7 X6 X5 X4 X3 X2 X1 X0 + * byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + * byte 6: 0 y9 y8 y7 1 m r l + * byte 7: 0 y6 y5 y4 y3 y2 y1 y0 + * byte 8: 0 z6 z5 z4 z3 z2 z1 z0 + * + * CAPITALS = stick, miniscules = touchpad + * * ?'s can have different meanings on different models, * such as wheel rotation, extra buttons, stick buttons * on a dualpoint, etc. */ +static bool alps_is_valid_first_byte(const struct alps_model_info *model, + unsigned char data) +{ + return (data & model->mask0) == model->byte0; +} + +static void alps_report_buttons(struct psmouse *psmouse, + struct input_dev *dev1, struct input_dev *dev2, + int left, int right, int middle) +{ + struct alps_data *priv = psmouse->private; + const struct alps_model_info *model = priv->i; + + if (model->flags & ALPS_PS2_INTERLEAVED) { + struct input_dev *dev; + + /* + * If shared button has already been reported on the + * other device (dev2) then this event should be also + * sent through that device. + */ + dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1; + input_report_key(dev, BTN_LEFT, left); + + dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1; + input_report_key(dev, BTN_RIGHT, right); + + dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1; + input_report_key(dev, BTN_MIDDLE, middle); + + /* + * Sync the _other_ device now, we'll do the first + * device later once we report the rest of the events. + */ + input_sync(dev2); + } else { + /* + * For devices with non-interleaved packets we know what + * device buttons belong to so we can simply report them. + */ + input_report_key(dev1, BTN_LEFT, left); + input_report_key(dev1, BTN_RIGHT, right); + input_report_key(dev1, BTN_MIDDLE, middle); + } +} + static void alps_process_packet(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; + const struct alps_model_info *model = priv->i; unsigned char *packet = psmouse->packet; struct input_dev *dev = psmouse->dev; struct input_dev *dev2 = priv->dev2; int x, y, z, ges, fin, left, right, middle; int back = 0, forward = 0; - if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */ - input_report_key(dev2, BTN_LEFT, packet[0] & 1); - input_report_key(dev2, BTN_RIGHT, packet[0] & 2); - input_report_key(dev2, BTN_MIDDLE, packet[0] & 4); - input_report_rel(dev2, REL_X, - packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); - input_report_rel(dev2, REL_Y, - packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); - input_sync(dev2); - return; - } - - if (priv->i->flags & ALPS_OLDPROTO) { + if (model->flags & ALPS_OLDPROTO) { left = packet[2] & 0x10; right = packet[2] & 0x08; middle = 0; @@ -117,12 +180,12 @@ static void alps_process_packet(struct psmouse *psmouse) z = packet[5]; } - if (priv->i->flags & ALPS_FW_BK_1) { + if (model->flags & ALPS_FW_BK_1) { back = packet[0] & 0x10; forward = packet[2] & 4; } - if (priv->i->flags & ALPS_FW_BK_2) { + if (model->flags & ALPS_FW_BK_2) { back = packet[3] & 4; forward = packet[2] & 4; if ((middle = forward && back)) @@ -132,25 +195,21 @@ static void alps_process_packet(struct psmouse *psmouse) ges = packet[2] & 1; fin = packet[2] & 2; - if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) { + if ((model->flags & ALPS_DUALPOINT) && z == 127) { input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); - input_report_key(dev2, BTN_LEFT, left); - input_report_key(dev2, BTN_RIGHT, right); - input_report_key(dev2, BTN_MIDDLE, middle); + alps_report_buttons(psmouse, dev2, dev, left, right, middle); - input_sync(dev); input_sync(dev2); return; } - input_report_key(dev, BTN_LEFT, left); - input_report_key(dev, BTN_RIGHT, right); - input_report_key(dev, BTN_MIDDLE, middle); + alps_report_buttons(psmouse, dev, dev2, left, right, middle); /* Convert hardware tap to a reasonable Z value */ - if (ges && !fin) z = 40; + if (ges && !fin) + z = 40; /* * A "tap and drag" operation is reported by the hardware as a transition @@ -166,8 +225,10 @@ static void alps_process_packet(struct psmouse *psmouse) } priv->prev_fin = fin; - if (z > 30) input_report_key(dev, BTN_TOUCH, 1); - if (z < 25) input_report_key(dev, BTN_TOUCH, 0); + if (z > 30) + input_report_key(dev, BTN_TOUCH, 1); + if (z < 25) + input_report_key(dev, BTN_TOUCH, 0); if (z > 0) { input_report_abs(dev, ABS_X, x); @@ -177,36 +238,186 @@ static void alps_process_packet(struct psmouse *psmouse) input_report_abs(dev, ABS_PRESSURE, z); input_report_key(dev, BTN_TOOL_FINGER, z > 0); - if (priv->i->flags & ALPS_WHEEL) + if (model->flags & ALPS_WHEEL) input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); - if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { + if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { input_report_key(dev, BTN_FORWARD, forward); input_report_key(dev, BTN_BACK, back); } + if (model->flags & ALPS_FOUR_BUTTONS) { + input_report_key(dev, BTN_0, packet[2] & 4); + input_report_key(dev, BTN_1, packet[0] & 0x10); + input_report_key(dev, BTN_2, packet[3] & 4); + input_report_key(dev, BTN_3, packet[0] & 0x20); + } + input_sync(dev); } +static void alps_report_bare_ps2_packet(struct psmouse *psmouse, + unsigned char packet[], + bool report_buttons) +{ + struct alps_data *priv = psmouse->private; + struct input_dev *dev2 = priv->dev2; + + if (report_buttons) + alps_report_buttons(psmouse, dev2, psmouse->dev, + packet[0] & 1, packet[0] & 2, packet[0] & 4); + + input_report_rel(dev2, REL_X, + packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); + input_report_rel(dev2, REL_Y, + packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); + + input_sync(dev2); +} + +static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) +{ + struct alps_data *priv = psmouse->private; + + if (psmouse->pktcnt < 6) + return PSMOUSE_GOOD_DATA; + + if (psmouse->pktcnt == 6) { + /* + * Start a timer to flush the packet if it ends up last + * 6-byte packet in the stream. Timer needs to fire + * psmouse core times out itself. 20 ms should be enough + * to decide if we are getting more data or not. + */ + mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20)); + return PSMOUSE_GOOD_DATA; + } + + del_timer(&priv->timer); + + if (psmouse->packet[6] & 0x80) { + + /* + * Highest bit is set - that means we either had + * complete ALPS packet and this is start of the + * next packet or we got garbage. + */ + + if (((psmouse->packet[3] | + psmouse->packet[4] | + psmouse->packet[5]) & 0x80) || + (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { + dbg("refusing packet %x %x %x %x " + "(suspected interleaved ps/2)\n", + psmouse->packet[3], psmouse->packet[4], + psmouse->packet[5], psmouse->packet[6]); + return PSMOUSE_BAD_DATA; + } + + alps_process_packet(psmouse); + + /* Continue with the next packet */ + psmouse->packet[0] = psmouse->packet[6]; + psmouse->pktcnt = 1; + + } else { + + /* + * High bit is 0 - that means that we indeed got a PS/2 + * packet in the middle of ALPS packet. + * + * There is also possibility that we got 6-byte ALPS + * packet followed by 3-byte packet from trackpoint. We + * can not distinguish between these 2 scenarios but + * becase the latter is unlikely to happen in course of + * normal operation (user would need to press all + * buttons on the pad and start moving trackpoint + * without touching the pad surface) we assume former. + * Even if we are wrong the wost thing that would happen + * the cursor would jump but we should not get protocol + * desynchronization. + */ + + alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], + false); + + /* + * Continue with the standard ALPS protocol handling, + * but make sure we won't process it as an interleaved + * packet again, which may happen if all buttons are + * pressed. To avoid this let's reset the 4th bit which + * is normally 1. + */ + psmouse->packet[3] = psmouse->packet[6] & 0xf7; + psmouse->pktcnt = 4; + } + + return PSMOUSE_GOOD_DATA; +} + +static void alps_flush_packet(unsigned long data) +{ + struct psmouse *psmouse = (struct psmouse *)data; + + serio_pause_rx(psmouse->ps2dev.serio); + + if (psmouse->pktcnt == 6) { + + /* + * We did not any more data in reasonable amount of time. + * Validate the last 3 bytes and process as a standard + * ALPS packet. + */ + if ((psmouse->packet[3] | + psmouse->packet[4] | + psmouse->packet[5]) & 0x80) { + dbg("refusing packet %x %x %x " + "(suspected interleaved ps/2)\n", + psmouse->packet[3], psmouse->packet[4], + psmouse->packet[5]); + } else { + alps_process_packet(psmouse); + } + psmouse->pktcnt = 0; + } + + serio_continue_rx(psmouse->ps2dev.serio); +} + static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; + const struct alps_model_info *model = priv->i; if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ if (psmouse->pktcnt == 3) { - alps_process_packet(psmouse); + alps_report_bare_ps2_packet(psmouse, psmouse->packet, + true); return PSMOUSE_FULL_PACKET; } return PSMOUSE_GOOD_DATA; } - if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0) + /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ + + if ((model->flags & ALPS_PS2_INTERLEAVED) && + psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { + return alps_handle_interleaved_ps2(psmouse); + } + + if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { + dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", + psmouse->packet[0], model->mask0, model->byte0); return PSMOUSE_BAD_DATA; + } /* Bytes 2 - 6 should have 0 in the highest bit */ if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && - (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) + (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { + dbg("refusing packet[%i] = %x\n", + psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]); return PSMOUSE_BAD_DATA; + } if (psmouse->pktcnt == 6) { alps_process_packet(psmouse); @@ -393,15 +604,12 @@ static int alps_poll(struct psmouse *psmouse) return 0; } -static int alps_hw_init(struct psmouse *psmouse, int *version) +static int alps_hw_init(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; + const struct alps_model_info *model = priv->i; - priv->i = alps_get_model(psmouse, version); - if (!priv->i) - return -1; - - if ((priv->i->flags & ALPS_PASS) && + if ((model->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, true)) { return -1; } @@ -416,7 +624,7 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) return -1; } - if ((priv->i->flags & ALPS_PASS) && + if ((model->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, false)) { return -1; } @@ -432,12 +640,15 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) static int alps_reconnect(struct psmouse *psmouse) { + const struct alps_model_info *model; + psmouse_reset(psmouse); - if (alps_hw_init(psmouse, NULL)) + model = alps_get_model(psmouse, NULL); + if (!model) return -1; - return 0; + return alps_hw_init(psmouse); } static void alps_disconnect(struct psmouse *psmouse) @@ -445,6 +656,7 @@ static void alps_disconnect(struct psmouse *psmouse) struct alps_data *priv = psmouse->private; psmouse_reset(psmouse); + del_timer_sync(&priv->timer); input_unregister_device(priv->dev2); kfree(priv); } @@ -452,6 +664,7 @@ static void alps_disconnect(struct psmouse *psmouse) int alps_init(struct psmouse *psmouse) { struct alps_data *priv; + const struct alps_model_info *model; struct input_dev *dev1 = psmouse->dev, *dev2; int version; @@ -461,35 +674,63 @@ int alps_init(struct psmouse *psmouse) goto init_fail; priv->dev2 = dev2; + setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); + psmouse->private = priv; - if (alps_hw_init(psmouse, &version)) + model = alps_get_model(psmouse, &version); + if (!model) + goto init_fail; + + priv->i = model; + + if (alps_hw_init(psmouse)) goto init_fail; + /* + * Undo part of setup done for us by psmouse core since touchpad + * is not a relative device. + */ + __clear_bit(EV_REL, dev1->evbit); + __clear_bit(REL_X, dev1->relbit); + __clear_bit(REL_Y, dev1->relbit); + + /* + * Now set up our capabilities. + */ dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); - dev1->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); + dev1->keybit[BIT_WORD(BTN_LEFT)] |= + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); - if (priv->i->flags & ALPS_WHEEL) { + if (model->flags & ALPS_WHEEL) { dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); } - if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { + if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); } + if (model->flags & ALPS_FOUR_BUTTONS) { + dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); + dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); + dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); + dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); + } else { + dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); + } + snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); dev2->phys = priv->phys; - dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; + dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; dev2->id.bustype = BUS_I8042; dev2->id.vendor = 0x0002; dev2->id.product = PSMOUSE_ALPS; @@ -497,9 +738,9 @@ int alps_init(struct psmouse *psmouse) dev2->dev.parent = &psmouse->ps2dev.serio->dev; dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - dev2->relbit[BIT_WORD(REL_X)] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y); - dev2->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); + dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); + dev2->keybit[BIT_WORD(BTN_LEFT)] = + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); if (input_register_device(priv->dev2)) goto init_fail; diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index bc87936fee1a..904ed8b3c8be 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -23,6 +23,7 @@ struct alps_data { char phys[32]; /* Phys */ const struct alps_model_info *i;/* Info */ int prev_fin; /* Finger bit from previous packet */ + struct timer_list timer; }; #ifdef CONFIG_MOUSE_PS2_ALPS diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index fda35e615abf..b27684f267bf 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -420,6 +420,7 @@ static void elantech_set_input_params(struct psmouse *psmouse) __set_bit(EV_KEY, dev->evbit); __set_bit(EV_ABS, dev->evbit); + __clear_bit(EV_REL, dev->evbit); __set_bit(BTN_LEFT, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index de1e553028b7..b146237266d8 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -430,19 +430,6 @@ static int hgpk_register(struct psmouse *psmouse) struct input_dev *dev = psmouse->dev; int err; - /* unset the things that psmouse-base sets which we don't have */ - __clear_bit(BTN_MIDDLE, dev->keybit); - - /* set the things we do have */ - __set_bit(EV_KEY, dev->evbit); - __set_bit(EV_REL, dev->evbit); - - __set_bit(REL_X, dev->relbit); - __set_bit(REL_Y, dev->relbit); - - __set_bit(BTN_LEFT, dev->keybit); - __set_bit(BTN_RIGHT, dev->keybit); - /* register handlers */ psmouse->protocol_handler = hgpk_process_byte; psmouse->poll = hgpk_poll; diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 82811558ec33..2e6bdfea0165 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -25,11 +25,13 @@ struct lifebook_data { char phys[32]; }; +static bool lifebook_present; + static const char *desired_serio_phys; -static int lifebook_set_serio_phys(const struct dmi_system_id *d) +static int lifebook_limit_serio3(const struct dmi_system_id *d) { - desired_serio_phys = d->driver_data; + desired_serio_phys = "isa0060/serio3"; return 0; } @@ -41,53 +43,53 @@ static int lifebook_set_6byte_proto(const struct dmi_system_id *d) return 0; } -static const struct dmi_system_id lifebook_dmi_table[] = { +static const struct dmi_system_id __initconst lifebook_dmi_table[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) { - .ident = "FLORA-ie 55mi", + /* FLORA-ie 55mi */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"), }, }, { - .ident = "LifeBook B", + /* LifeBook B */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"), }, }, { - .ident = "Lifebook B", + /* Lifebook B */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"), }, }, { - .ident = "Lifebook B-2130", + /* Lifebook B-2130 */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "ZEPHYR"), }, }, { - .ident = "Lifebook B213x/B2150", + /* Lifebook B213x/B2150 */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"), }, }, { - .ident = "Zephyr", + /* Zephyr */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"), }, }, { - .ident = "CF-18", + /* Panasonic CF-18 */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), }, - .callback = lifebook_set_serio_phys, - .driver_data = "isa0060/serio3", + .callback = lifebook_limit_serio3, }, { - .ident = "Panasonic CF-28", + /* Panasonic CF-28 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"), @@ -95,7 +97,7 @@ static const struct dmi_system_id lifebook_dmi_table[] = { .callback = lifebook_set_6byte_proto, }, { - .ident = "Panasonic CF-29", + /* Panasonic CF-29 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), @@ -103,21 +105,27 @@ static const struct dmi_system_id lifebook_dmi_table[] = { .callback = lifebook_set_6byte_proto, }, { - .ident = "CF-72", + /* Panasonic CF-72 */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"), }, .callback = lifebook_set_6byte_proto, }, { - .ident = "Lifebook B142", + /* Lifebook B142 */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"), }, }, { } +#endif }; +void __init lifebook_module_init(void) +{ + lifebook_present = dmi_check_system(lifebook_dmi_table); +} + static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) { struct lifebook_data *priv = psmouse->private; @@ -198,10 +206,10 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) return -1; /* - Enable absolute output -- ps2_command fails always but if - you leave this call out the touchsreen will never send - absolute coordinates - */ + * Enable absolute output -- ps2_command fails always but if + * you leave this call out the touchsreen will never send + * absolute coordinates + */ param = lifebook_use_6byte_proto ? 0x08 : 0x07; ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); @@ -243,7 +251,7 @@ static void lifebook_disconnect(struct psmouse *psmouse) int lifebook_detect(struct psmouse *psmouse, bool set_properties) { - if (!dmi_check_system(lifebook_dmi_table)) + if (!lifebook_present) return -1; if (desired_serio_phys && @@ -283,8 +291,8 @@ static int lifebook_create_relative_device(struct psmouse *psmouse) dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); - dev2->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_RIGHT); + dev2->keybit[BIT_WORD(BTN_LEFT)] = + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); error = input_register_device(priv->dev2); if (error) @@ -309,6 +317,7 @@ int lifebook_init(struct psmouse *psmouse) dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); dev1->relbit[0] = 0; + dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0; dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0); input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0); diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h index 407cb226bc0a..4c4326c6f504 100644 --- a/drivers/input/mouse/lifebook.h +++ b/drivers/input/mouse/lifebook.h @@ -12,9 +12,13 @@ #define _LIFEBOOK_H #ifdef CONFIG_MOUSE_PS2_LIFEBOOK +void lifebook_module_init(void); int lifebook_detect(struct psmouse *psmouse, bool set_properties); int lifebook_init(struct psmouse *psmouse); #else +inline void lifebook_module_init(void) +{ +} inline int lifebook_detect(struct psmouse *psmouse, bool set_properties) { return -ENOSYS; diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index ab5dc5f5fd83..543c240a85f2 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -404,8 +404,8 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) } } - if (buttons < 3) - __clear_bit(BTN_MIDDLE, psmouse->dev->keybit); + if (buttons >= 3) + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); if (model_info) ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 07c53798301a..fd0bc094616a 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -425,6 +425,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties) return -1; if (set_properties) { + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_EXTRA, psmouse->dev->keybit); __set_bit(BTN_SIDE, psmouse->dev->keybit); __set_bit(REL_WHEEL, psmouse->dev->relbit); @@ -460,8 +461,10 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties) __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(REL_WHEEL, psmouse->dev->relbit); - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Wheel Mouse"; + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Wheel Mouse"; psmouse->pktsize = 4; } @@ -504,8 +507,10 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) __set_bit(BTN_SIDE, psmouse->dev->keybit); __set_bit(BTN_EXTRA, psmouse->dev->keybit); - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Explorer Mouse"; + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Explorer Mouse"; psmouse->pktsize = 4; } @@ -536,6 +541,7 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties) return -1; if (set_properties) { + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_EXTRA, psmouse->dev->keybit); psmouse->vendor = "Kensington"; @@ -551,8 +557,16 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties) static int ps2bare_detect(struct psmouse *psmouse, bool set_properties) { if (set_properties) { - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Mouse"; + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Mouse"; + +/* + * We have no way of figuring true number of buttons so let's + * assume that the device has 3. + */ + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); } return 0; @@ -567,6 +581,8 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties) if (set_properties) { psmouse->vendor = "Cortron"; psmouse->name = "PS/2 Trackball"; + + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_SIDE, psmouse->dev->keybit); } @@ -1184,15 +1200,16 @@ static void psmouse_disconnect(struct serio *serio) mutex_unlock(&psmouse_mutex); } -static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto) +static int psmouse_switch_protocol(struct psmouse *psmouse, + const struct psmouse_protocol *proto) { struct input_dev *input_dev = psmouse->dev; input_dev->dev.parent = &psmouse->ps2dev.serio->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); + input_dev->keybit[BIT_WORD(BTN_MOUSE)] = + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); psmouse->set_rate = psmouse_set_rate; @@ -1209,8 +1226,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse return -1; psmouse->type = proto->type; - } - else + } else psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, true); @@ -1680,6 +1696,9 @@ static int __init psmouse_init(void) { int err; + lifebook_module_init(); + synaptics_module_init(); + kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); if (!kpsmoused_wq) { printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index f84cbd97c884..77b9fd0b3fbf 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -836,6 +836,7 @@ int fsp_init(struct psmouse *psmouse) priv->flags |= FSPDRV_FLAG_EN_OPC; /* Set up various supported input event bits */ + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_BACK, psmouse->dev->keybit); __set_bit(BTN_FORWARD, psmouse->dev->keybit); __set_bit(REL_WHEEL, psmouse->dev->relbit); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index f4a61252bcc9..05689e732191 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -24,6 +24,7 @@ */ #include <linux/module.h> +#include <linux/dmi.h> #include <linux/input.h> #include <linux/serio.h> #include <linux/libps2.h> @@ -629,25 +630,26 @@ static int synaptics_reconnect(struct psmouse *psmouse) return 0; } -#if defined(__i386__) -#include <linux/dmi.h> -static const struct dmi_system_id toshiba_dmi_table[] = { +static bool impaired_toshiba_kbc; + +static const struct dmi_system_id __initconst toshiba_dmi_table[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) { - .ident = "Toshiba Satellite", + /* Toshiba Satellite */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"), }, }, { - .ident = "Toshiba Dynabook", + /* Toshiba Dynabook */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"), }, }, { - .ident = "Toshiba Portege M300", + /* Toshiba Portege M300 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"), @@ -655,7 +657,7 @@ static const struct dmi_system_id toshiba_dmi_table[] = { }, { - .ident = "Toshiba Portege M300", + /* Toshiba Portege M300 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"), @@ -664,8 +666,13 @@ static const struct dmi_system_id toshiba_dmi_table[] = { }, { } -}; #endif +}; + +void __init synaptics_module_init(void) +{ + impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); +} int synaptics_init(struct psmouse *psmouse) { @@ -718,18 +725,16 @@ int synaptics_init(struct psmouse *psmouse) if (SYN_CAP_PASS_THROUGH(priv->capabilities)) synaptics_pt_create(psmouse); -#if defined(__i386__) /* * Toshiba's KBC seems to have trouble handling data from * Synaptics as full rate, switch to lower rate which is roughly * thye same as rate of standard PS/2 mouse. */ - if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) { + if (psmouse->rate >= 80 && impaired_toshiba_kbc) { printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", dmi_get_system_info(DMI_PRODUCT_NAME)); psmouse->rate = 40; } -#endif return 0; @@ -740,6 +745,10 @@ int synaptics_init(struct psmouse *psmouse) #else /* CONFIG_MOUSE_PS2_SYNAPTICS */ +void __init synaptics_module_init(void) +{ +} + int synaptics_init(struct psmouse *psmouse) { return -ENOSYS; diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 871f6fe377f9..838e7f2c9b30 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -105,6 +105,7 @@ struct synaptics_data { int scroll; }; +void synaptics_module_init(void); int synaptics_detect(struct psmouse *psmouse, bool set_properties); int synaptics_init(struct psmouse *psmouse); void synaptics_reset(struct psmouse *psmouse); diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 7283c78044af..9867dfe2a638 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -420,8 +420,8 @@ static void synaptics_i2c_check_params(struct synaptics_i2c *touch) } /* Control the Device polling rate / Work Handler sleep time */ -unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch, - bool have_data) +static unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch, + bool have_data) { unsigned long delay, nodata_count_thres; @@ -520,7 +520,7 @@ static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch) __set_bit(BTN_LEFT, input->keybit); } -struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client) +static struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client) { struct synaptics_i2c *touch; diff --git a/drivers/input/mouse/touchkit_ps2.c b/drivers/input/mouse/touchkit_ps2.c index 0308a0faa94d..909431c31ab4 100644 --- a/drivers/input/mouse/touchkit_ps2.c +++ b/drivers/input/mouse/touchkit_ps2.c @@ -86,7 +86,8 @@ int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties) if (set_properties) { dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - __set_bit(BTN_TOUCH, dev->keybit); + dev->keybit[BIT_WORD(BTN_MOUSE)] = 0; + dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0); input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0); diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index e354362f2971..63d4a67830f2 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -284,7 +284,6 @@ static int trackpoint_reconnect(struct psmouse *psmouse) int trackpoint_detect(struct psmouse *psmouse, bool set_properties) { - struct trackpoint_data *priv; struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char firmware_id; unsigned char button_info; @@ -301,8 +300,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) button_info = 0; } - psmouse->private = priv = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL); - if (!priv) + psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL); + if (!psmouse->private) return -1; psmouse->vendor = "IBM"; @@ -311,7 +310,10 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) psmouse->reconnect = trackpoint_reconnect; psmouse->disconnect = trackpoint_disconnect; - trackpoint_defaults(priv); + if ((button_info & 0x0f) >= 3) + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + + trackpoint_defaults(psmouse->private); trackpoint_sync(psmouse); error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); @@ -319,7 +321,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) printk(KERN_ERR "trackpoint.c: failed to create sysfs attributes, error: %d\n", error); - kfree(priv); + kfree(psmouse->private); + psmouse->private = NULL; return -1; } diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index 70111443678e..bf2c0c80d6cc 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -86,27 +86,28 @@ #define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet" -MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); -MODULE_DESCRIPTION (DRIVER_DESC); -MODULE_LICENSE ("GPL"); +MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); #undef VSXXXAA_DEBUG #ifdef VSXXXAA_DEBUG -#define DBG(x...) printk (x) +#define DBG(x...) printk(x) #else #define DBG(x...) do {} while (0) #endif #define VSXXXAA_INTRO_MASK 0x80 #define VSXXXAA_INTRO_HEAD 0x80 -#define IS_HDR_BYTE(x) (((x) & VSXXXAA_INTRO_MASK) \ - == VSXXXAA_INTRO_HEAD) +#define IS_HDR_BYTE(x) \ + (((x) & VSXXXAA_INTRO_MASK) == VSXXXAA_INTRO_HEAD) #define VSXXXAA_PACKET_MASK 0xe0 #define VSXXXAA_PACKET_REL 0x80 #define VSXXXAA_PACKET_ABS 0xc0 #define VSXXXAA_PACKET_POR 0xa0 -#define MATCH_PACKET_TYPE(data, type) (((data) & VSXXXAA_PACKET_MASK) == (type)) +#define MATCH_PACKET_TYPE(data, type) \ + (((data) & VSXXXAA_PACKET_MASK) == (type)) @@ -123,52 +124,50 @@ struct vsxxxaa { char phys[32]; }; -static void -vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num) +static void vsxxxaa_drop_bytes(struct vsxxxaa *mouse, int num) { - if (num >= mouse->count) + if (num >= mouse->count) { mouse->count = 0; - else { - memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num); + } else { + memmove(mouse->buf, mouse->buf + num - 1, BUFLEN - num); mouse->count -= num; } } -static void -vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte) +static void vsxxxaa_queue_byte(struct vsxxxaa *mouse, unsigned char byte) { if (mouse->count == BUFLEN) { - printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", - mouse->name, mouse->phys); - vsxxxaa_drop_bytes (mouse, 1); + printk(KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", + mouse->name, mouse->phys); + vsxxxaa_drop_bytes(mouse, 1); } - DBG (KERN_INFO "Queueing byte 0x%02x\n", byte); + + DBG(KERN_INFO "Queueing byte 0x%02x\n", byte); mouse->buf[mouse->count++] = byte; } -static void -vsxxxaa_detection_done (struct vsxxxaa *mouse) +static void vsxxxaa_detection_done(struct vsxxxaa *mouse) { switch (mouse->type) { - case 0x02: - strlcpy (mouse->name, "DEC VSXXX-AA/-GA mouse", - sizeof (mouse->name)); - break; - - case 0x04: - strlcpy (mouse->name, "DEC VSXXX-AB digitizer", - sizeof (mouse->name)); - break; - - default: - snprintf (mouse->name, sizeof (mouse->name), - "unknown DEC pointer device (type = 0x%02x)", - mouse->type); - break; + case 0x02: + strlcpy(mouse->name, "DEC VSXXX-AA/-GA mouse", + sizeof(mouse->name)); + break; + + case 0x04: + strlcpy(mouse->name, "DEC VSXXX-AB digitizer", + sizeof(mouse->name)); + break; + + default: + snprintf(mouse->name, sizeof(mouse->name), + "unknown DEC pointer device (type = 0x%02x)", + mouse->type); + break; } - printk (KERN_INFO + printk(KERN_INFO "Found %s version 0x%02x from country 0x%02x on port %s\n", mouse->name, mouse->version, mouse->country, mouse->phys); } @@ -176,42 +175,38 @@ vsxxxaa_detection_done (struct vsxxxaa *mouse) /* * Returns number of bytes to be dropped, 0 if packet is okay. */ -static int -vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len) +static int vsxxxaa_check_packet(struct vsxxxaa *mouse, int packet_len) { int i; /* First byte must be a header byte */ - if (!IS_HDR_BYTE (mouse->buf[0])) { - DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]); + if (!IS_HDR_BYTE(mouse->buf[0])) { + DBG("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]); return 1; } /* Check all following bytes */ - if (packet_len > 1) { - for (i = 1; i < packet_len; i++) { - if (IS_HDR_BYTE (mouse->buf[i])) { - printk (KERN_ERR "Need to drop %d bytes " - "of a broken packet.\n", - i - 1); - DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n", - packet_len, i, mouse->buf[i]); - return i - 1; - } + for (i = 1; i < packet_len; i++) { + if (IS_HDR_BYTE(mouse->buf[i])) { + printk(KERN_ERR + "Need to drop %d bytes of a broken packet.\n", + i - 1); + DBG(KERN_INFO "check: len=%d, b[%d]=0x%02x\n", + packet_len, i, mouse->buf[i]); + return i - 1; } } return 0; } -static __inline__ int -vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len) +static inline int vsxxxaa_smells_like_packet(struct vsxxxaa *mouse, + unsigned char type, size_t len) { - return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type); + return mouse->count >= len && MATCH_PACKET_TYPE(mouse->buf[0], type); } -static void -vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse) +static void vsxxxaa_handle_REL_packet(struct vsxxxaa *mouse) { struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; @@ -232,43 +227,42 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse) * 0, bit 4 of byte 0 is direction. */ dx = buf[1] & 0x7f; - dx *= ((buf[0] >> 4) & 0x01)? 1: -1; + dx *= ((buf[0] >> 4) & 0x01) ? 1 : -1; /* * Low 7 bit of byte 2 are abs(dy), bit 7 is * 0, bit 3 of byte 0 is direction. */ dy = buf[2] & 0x7f; - dy *= ((buf[0] >> 3) & 0x01)? -1: 1; + dy *= ((buf[0] >> 3) & 0x01) ? -1 : 1; /* * Get button state. It's the low three bits * (for three buttons) of byte 0. */ - left = (buf[0] & 0x04)? 1: 0; - middle = (buf[0] & 0x02)? 1: 0; - right = (buf[0] & 0x01)? 1: 0; + left = buf[0] & 0x04; + middle = buf[0] & 0x02; + right = buf[0] & 0x01; - vsxxxaa_drop_bytes (mouse, 3); + vsxxxaa_drop_bytes(mouse, 3); - DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n", - mouse->name, mouse->phys, dx, dy, - left? "L": "l", middle? "M": "m", right? "R": "r"); + DBG(KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n", + mouse->name, mouse->phys, dx, dy, + left ? "L" : "l", middle ? "M" : "m", right ? "R" : "r"); /* * Report what we've found so far... */ - input_report_key (dev, BTN_LEFT, left); - input_report_key (dev, BTN_MIDDLE, middle); - input_report_key (dev, BTN_RIGHT, right); - input_report_key (dev, BTN_TOUCH, 0); - input_report_rel (dev, REL_X, dx); - input_report_rel (dev, REL_Y, dy); - input_sync (dev); + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_MIDDLE, middle); + input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_TOUCH, 0); + input_report_rel(dev, REL_X, dx); + input_report_rel(dev, REL_Y, dy); + input_sync(dev); } -static void -vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse) +static void vsxxxaa_handle_ABS_packet(struct vsxxxaa *mouse) { struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; @@ -296,32 +290,31 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse) /* * Get button state. It's bits <4..1> of byte 0. */ - left = (buf[0] & 0x02)? 1: 0; - middle = (buf[0] & 0x04)? 1: 0; - right = (buf[0] & 0x08)? 1: 0; - touch = (buf[0] & 0x10)? 1: 0; + left = buf[0] & 0x02; + middle = buf[0] & 0x04; + right = buf[0] & 0x08; + touch = buf[0] & 0x10; - vsxxxaa_drop_bytes (mouse, 5); + vsxxxaa_drop_bytes(mouse, 5); - DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n", - mouse->name, mouse->phys, x, y, - left? "L": "l", middle? "M": "m", - right? "R": "r", touch? "T": "t"); + DBG(KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n", + mouse->name, mouse->phys, x, y, + left ? "L" : "l", middle ? "M" : "m", + right ? "R" : "r", touch ? "T" : "t"); /* * Report what we've found so far... */ - input_report_key (dev, BTN_LEFT, left); - input_report_key (dev, BTN_MIDDLE, middle); - input_report_key (dev, BTN_RIGHT, right); - input_report_key (dev, BTN_TOUCH, touch); - input_report_abs (dev, ABS_X, x); - input_report_abs (dev, ABS_Y, y); - input_sync (dev); + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_MIDDLE, middle); + input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_TOUCH, touch); + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_sync(dev); } -static void -vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) +static void vsxxxaa_handle_POR_packet(struct vsxxxaa *mouse) { struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; @@ -356,24 +349,24 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) * (for three buttons) of byte 0. Maybe even the bit <3> * has some meaning if a tablet is attached. */ - left = (buf[0] & 0x04)? 1: 0; - middle = (buf[0] & 0x02)? 1: 0; - right = (buf[0] & 0x01)? 1: 0; + left = buf[0] & 0x04; + middle = buf[0] & 0x02; + right = buf[0] & 0x01; - vsxxxaa_drop_bytes (mouse, 4); - vsxxxaa_detection_done (mouse); + vsxxxaa_drop_bytes(mouse, 4); + vsxxxaa_detection_done(mouse); if (error <= 0x1f) { /* No (serious) error. Report buttons */ - input_report_key (dev, BTN_LEFT, left); - input_report_key (dev, BTN_MIDDLE, middle); - input_report_key (dev, BTN_RIGHT, right); - input_report_key (dev, BTN_TOUCH, 0); - input_sync (dev); + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_MIDDLE, middle); + input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_TOUCH, 0); + input_sync(dev); if (error != 0) - printk (KERN_INFO "Your %s on %s reports error=0x%02x\n", - mouse->name, mouse->phys, error); + printk(KERN_INFO "Your %s on %s reports error=0x%02x\n", + mouse->name, mouse->phys, error); } @@ -381,18 +374,18 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) * If the mouse was hot-plugged, we need to force differential mode * now... However, give it a second to recover from it's reset. */ - printk (KERN_NOTICE "%s on %s: Forceing standard packet format, " - "incremental streaming mode and 72 samples/sec\n", - mouse->name, mouse->phys); - serio_write (mouse->serio, 'S'); /* Standard format */ - mdelay (50); - serio_write (mouse->serio, 'R'); /* Incremental */ - mdelay (50); - serio_write (mouse->serio, 'L'); /* 72 samples/sec */ + printk(KERN_NOTICE + "%s on %s: Forcing standard packet format, " + "incremental streaming mode and 72 samples/sec\n", + mouse->name, mouse->phys); + serio_write(mouse->serio, 'S'); /* Standard format */ + mdelay(50); + serio_write(mouse->serio, 'R'); /* Incremental */ + mdelay(50); + serio_write(mouse->serio, 'L'); /* 72 samples/sec */ } -static void -vsxxxaa_parse_buffer (struct vsxxxaa *mouse) +static void vsxxxaa_parse_buffer(struct vsxxxaa *mouse) { unsigned char *buf = mouse->buf; int stray_bytes; @@ -409,122 +402,107 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse) * activity on the mouse. */ while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) { - printk (KERN_ERR "%s on %s: Dropping a byte to regain " - "sync with mouse data stream...\n", - mouse->name, mouse->phys); - vsxxxaa_drop_bytes (mouse, 1); + printk(KERN_ERR "%s on %s: Dropping a byte to regain " + "sync with mouse data stream...\n", + mouse->name, mouse->phys); + vsxxxaa_drop_bytes(mouse, 1); } /* * Check for packets we know about. */ - if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) { + if (vsxxxaa_smells_like_packet(mouse, VSXXXAA_PACKET_REL, 3)) { /* Check for broken packet */ - stray_bytes = vsxxxaa_check_packet (mouse, 3); - if (stray_bytes > 0) { - printk (KERN_ERR "Dropping %d bytes now...\n", - stray_bytes); - vsxxxaa_drop_bytes (mouse, stray_bytes); - continue; - } - - vsxxxaa_handle_REL_packet (mouse); - continue; /* More to parse? */ - } + stray_bytes = vsxxxaa_check_packet(mouse, 3); + if (!stray_bytes) + vsxxxaa_handle_REL_packet(mouse); - if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) { + } else if (vsxxxaa_smells_like_packet(mouse, + VSXXXAA_PACKET_ABS, 5)) { /* Check for broken packet */ - stray_bytes = vsxxxaa_check_packet (mouse, 5); - if (stray_bytes > 0) { - printk (KERN_ERR "Dropping %d bytes now...\n", - stray_bytes); - vsxxxaa_drop_bytes (mouse, stray_bytes); - continue; - } - - vsxxxaa_handle_ABS_packet (mouse); - continue; /* More to parse? */ - } + stray_bytes = vsxxxaa_check_packet(mouse, 5); + if (!stray_bytes) + vsxxxaa_handle_ABS_packet(mouse); - if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) { + } else if (vsxxxaa_smells_like_packet(mouse, + VSXXXAA_PACKET_POR, 4)) { /* Check for broken packet */ - stray_bytes = vsxxxaa_check_packet (mouse, 4); - if (stray_bytes > 0) { - printk (KERN_ERR "Dropping %d bytes now...\n", - stray_bytes); - vsxxxaa_drop_bytes (mouse, stray_bytes); - continue; - } - - vsxxxaa_handle_POR_packet (mouse); - continue; /* More to parse? */ + stray_bytes = vsxxxaa_check_packet(mouse, 4); + if (!stray_bytes) + vsxxxaa_handle_POR_packet(mouse); + + } else { + break; /* No REL, ABS or POR packet found */ + } + + if (stray_bytes > 0) { + printk(KERN_ERR "Dropping %d bytes now...\n", + stray_bytes); + vsxxxaa_drop_bytes(mouse, stray_bytes); } - break; /* No REL, ABS or POR packet found */ } while (1); } -static irqreturn_t -vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags) +static irqreturn_t vsxxxaa_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) { - struct vsxxxaa *mouse = serio_get_drvdata (serio); + struct vsxxxaa *mouse = serio_get_drvdata(serio); - vsxxxaa_queue_byte (mouse, data); - vsxxxaa_parse_buffer (mouse); + vsxxxaa_queue_byte(mouse, data); + vsxxxaa_parse_buffer(mouse); return IRQ_HANDLED; } -static void -vsxxxaa_disconnect (struct serio *serio) +static void vsxxxaa_disconnect(struct serio *serio) { - struct vsxxxaa *mouse = serio_get_drvdata (serio); + struct vsxxxaa *mouse = serio_get_drvdata(serio); - serio_close (serio); - serio_set_drvdata (serio, NULL); - input_unregister_device (mouse->dev); - kfree (mouse); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_unregister_device(mouse->dev); + kfree(mouse); } -static int -vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) +static int vsxxxaa_connect(struct serio *serio, struct serio_driver *drv) { struct vsxxxaa *mouse; struct input_dev *input_dev; int err = -ENOMEM; - mouse = kzalloc (sizeof (struct vsxxxaa), GFP_KERNEL); - input_dev = input_allocate_device (); + mouse = kzalloc(sizeof(struct vsxxxaa), GFP_KERNEL); + input_dev = input_allocate_device(); if (!mouse || !input_dev) goto fail1; mouse->dev = input_dev; mouse->serio = serio; - strlcat (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer", - sizeof (mouse->name)); - snprintf (mouse->phys, sizeof (mouse->phys), "%s/input0", serio->phys); + strlcat(mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer", + sizeof(mouse->name)); + snprintf(mouse->phys, sizeof(mouse->phys), "%s/input0", serio->phys); input_dev->name = mouse->name; input_dev->phys = mouse->phys; input_dev->id.bustype = BUS_RS232; input_dev->dev.parent = &serio->dev; - set_bit (EV_KEY, input_dev->evbit); /* We have buttons */ - set_bit (EV_REL, input_dev->evbit); - set_bit (EV_ABS, input_dev->evbit); - set_bit (BTN_LEFT, input_dev->keybit); /* We have 3 buttons */ - set_bit (BTN_MIDDLE, input_dev->keybit); - set_bit (BTN_RIGHT, input_dev->keybit); - set_bit (BTN_TOUCH, input_dev->keybit); /* ...and Tablet */ - set_bit (REL_X, input_dev->relbit); - set_bit (REL_Y, input_dev->relbit); - input_set_abs_params (input_dev, ABS_X, 0, 1023, 0, 0); - input_set_abs_params (input_dev, ABS_Y, 0, 1023, 0, 0); - - serio_set_drvdata (serio, mouse); - - err = serio_open (serio, drv); + __set_bit(EV_KEY, input_dev->evbit); /* We have buttons */ + __set_bit(EV_REL, input_dev->evbit); + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(BTN_LEFT, input_dev->keybit); /* We have 3 buttons */ + __set_bit(BTN_MIDDLE, input_dev->keybit); + __set_bit(BTN_RIGHT, input_dev->keybit); + __set_bit(BTN_TOUCH, input_dev->keybit); /* ...and Tablet */ + __set_bit(REL_X, input_dev->relbit); + __set_bit(REL_Y, input_dev->relbit); + input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0); + + serio_set_drvdata(serio, mouse); + + err = serio_open(serio, drv); if (err) goto fail2; @@ -532,18 +510,18 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) * Request selftest. Standard packet format and differential * mode will be requested after the device ID'ed successfully. */ - serio_write (serio, 'T'); /* Test */ + serio_write(serio, 'T'); /* Test */ - err = input_register_device (input_dev); + err = input_register_device(input_dev); if (err) goto fail3; return 0; - fail3: serio_close (serio); - fail2: serio_set_drvdata (serio, NULL); - fail1: input_free_device (input_dev); - kfree (mouse); + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(mouse); return err; } @@ -570,18 +548,16 @@ static struct serio_driver vsxxxaa_drv = { .disconnect = vsxxxaa_disconnect, }; -static int __init -vsxxxaa_init (void) +static int __init vsxxxaa_init(void) { return serio_register_driver(&vsxxxaa_drv); } -static void __exit -vsxxxaa_exit (void) +static void __exit vsxxxaa_exit(void) { serio_unregister_driver(&vsxxxaa_drv); } -module_init (vsxxxaa_init); -module_exit (vsxxxaa_exit); +module_init(vsxxxaa_init); +module_exit(vsxxxaa_exit); diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index aa533ceffe34..7e319d65ec57 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -201,4 +201,12 @@ config SERIO_XILINX_XPS_PS2 To compile this driver as a module, choose M here: the module will be called xilinx_ps2. +config SERIO_ALTERA_PS2 + tristate "Altera UP PS/2 controller" + help + Say Y here if you have Altera University Program PS/2 ports. + + To compile this driver as a module, choose M here: the + module will be called altera_ps2. + endif diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 9b6c8135955f..bf945f789d05 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o obj-$(CONFIG_SERIO_LIBPS2) += libps2.o obj-$(CONFIG_SERIO_RAW) += serio_raw.o obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o +obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c new file mode 100644 index 000000000000..320b7ca48bf8 --- /dev/null +++ b/drivers/input/serio/altera_ps2.c @@ -0,0 +1,203 @@ +/* + * Altera University Program PS2 controller driver + * + * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw> + * + * Based on sa1111ps2.c, which is: + * Copyright (C) 2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/serio.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#define DRV_NAME "altera_ps2" + +struct ps2if { + struct serio *io; + struct resource *iomem_res; + void __iomem *base; + unsigned irq; +}; + +/* + * Read all bytes waiting in the PS2 port. There should be + * at the most one, but we loop for safety. + */ +static irqreturn_t altera_ps2_rxint(int irq, void *dev_id) +{ + struct ps2if *ps2if = dev_id; + unsigned int status; + int handled = IRQ_NONE; + + while ((status = readl(ps2if->base)) & 0xffff0000) { + serio_interrupt(ps2if->io, status & 0xff, 0); + handled = IRQ_HANDLED; + } + + return handled; +} + +/* + * Write a byte to the PS2 port. + */ +static int altera_ps2_write(struct serio *io, unsigned char val) +{ + struct ps2if *ps2if = io->port_data; + + writel(val, ps2if->base); + return 0; +} + +static int altera_ps2_open(struct serio *io) +{ + struct ps2if *ps2if = io->port_data; + + /* clear fifo */ + while (readl(ps2if->base) & 0xffff0000) + /* empty */; + + writel(1, ps2if->base + 4); /* enable rx irq */ + return 0; +} + +static void altera_ps2_close(struct serio *io) +{ + struct ps2if *ps2if = io->port_data; + + writel(0, ps2if->base); /* disable rx irq */ +} + +/* + * Add one device to this driver. + */ +static int __devinit altera_ps2_probe(struct platform_device *pdev) +{ + struct ps2if *ps2if; + struct serio *serio; + int error, irq; + + ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { + error = -ENOMEM; + goto err_free_mem; + } + + serio->id.type = SERIO_8042; + serio->write = altera_ps2_write; + serio->open = altera_ps2_open; + serio->close = altera_ps2_close; + strlcpy(serio->name, dev_name(&pdev->dev), sizeof(serio->name)); + strlcpy(serio->phys, dev_name(&pdev->dev), sizeof(serio->phys)); + serio->port_data = ps2if; + serio->dev.parent = &pdev->dev; + ps2if->io = serio; + + ps2if->iomem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (ps2if->iomem_res == NULL) { + error = -ENOENT; + goto err_free_mem; + } + + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + error = -ENXIO; + goto err_free_mem; + } + ps2if->irq = irq; + + if (!request_mem_region(ps2if->iomem_res->start, + resource_size(ps2if->iomem_res), pdev->name)) { + error = -EBUSY; + goto err_free_mem; + } + + ps2if->base = ioremap(ps2if->iomem_res->start, + resource_size(ps2if->iomem_res)); + if (!ps2if->base) { + error = -ENOMEM; + goto err_free_res; + } + + error = request_irq(ps2if->irq, altera_ps2_rxint, 0, pdev->name, ps2if); + if (error) { + dev_err(&pdev->dev, "could not allocate IRQ %d: %d\n", + ps2if->irq, error); + goto err_unmap; + } + + dev_info(&pdev->dev, "base %p, irq %d\n", ps2if->base, ps2if->irq); + + serio_register_port(ps2if->io); + platform_set_drvdata(pdev, ps2if); + + return 0; + + err_unmap: + iounmap(ps2if->base); + err_free_res: + release_mem_region(ps2if->iomem_res->start, + resource_size(ps2if->iomem_res)); + err_free_mem: + kfree(ps2if); + kfree(serio); + return error; +} + +/* + * Remove one device from this driver. + */ +static int __devexit altera_ps2_remove(struct platform_device *pdev) +{ + struct ps2if *ps2if = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + serio_unregister_port(ps2if->io); + free_irq(ps2if->irq, ps2if); + iounmap(ps2if->base); + release_mem_region(ps2if->iomem_res->start, + resource_size(ps2if->iomem_res)); + kfree(ps2if); + + return 0; +} + +/* + * Our device driver structure + */ +static struct platform_driver altera_ps2_driver = { + .probe = altera_ps2_probe, + .remove = __devexit_p(altera_ps2_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init altera_ps2_init(void) +{ + return platform_driver_register(&altera_ps2_driver); +} + +static void __exit altera_ps2_exit(void) +{ + platform_driver_unregister(&altera_ps2_driver); +} + +module_init(altera_ps2_init); +module_exit(altera_ps2_exit); + +MODULE_DESCRIPTION("Altera University Program PS2 controller driver"); +MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 89b394183a75..92563a681d65 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -107,7 +107,7 @@ static void amba_kmi_close(struct serio *io) clk_disable(kmi->clk); } -static int amba_kmi_probe(struct amba_device *dev, struct amba_id *id) +static int __devinit amba_kmi_probe(struct amba_device *dev, struct amba_id *id) { struct amba_kmi_port *kmi; struct serio *io; @@ -134,7 +134,7 @@ static int amba_kmi_probe(struct amba_device *dev, struct amba_id *id) io->port_data = kmi; io->dev.parent = &dev->dev; - kmi->io = io; + kmi->io = io; kmi->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!kmi->base) { ret = -ENOMEM; @@ -162,7 +162,7 @@ static int amba_kmi_probe(struct amba_device *dev, struct amba_id *id) return ret; } -static int amba_kmi_remove(struct amba_device *dev) +static int __devexit amba_kmi_remove(struct amba_device *dev) { struct amba_kmi_port *kmi = amba_get_drvdata(dev); @@ -197,10 +197,11 @@ static struct amba_id amba_kmi_idtable[] = { static struct amba_driver ambakmi_driver = { .drv = { .name = "kmi-pl050", + .owner = THIS_MODULE, }, .id_table = amba_kmi_idtable, .probe = amba_kmi_probe, - .remove = amba_kmi_remove, + .remove = __devexit_p(amba_kmi_remove), .resume = amba_kmi_resume, }; diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c index a6fb7a3dcc46..b54452a8c771 100644 --- a/drivers/input/serio/at32psif.c +++ b/drivers/input/serio/at32psif.c @@ -137,7 +137,7 @@ static int psif_write(struct serio *io, unsigned char val) spin_lock_irqsave(&psif->lock, flags); while (!(psif_readl(psif, SR) & PSIF_BIT(TXEMPTY)) && timeout--) - msleep(10); + udelay(50); if (timeout >= 0) { psif_writel(psif, THR, val); @@ -352,6 +352,7 @@ static struct platform_driver psif_driver = { .remove = __exit_p(psif_remove), .driver = { .name = "atmel_psif", + .owner = THIS_MODULE, }, .suspend = psif_suspend, .resume = psif_resume, diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index bd0f92d9f40f..06addfa7cc47 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -6,7 +6,7 @@ * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org> * * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c - * Copyright (c) 1999 Alex deVries <alex@onefishtwo.ca> + * Copyright (c) 1999 Alex deVries <alex@onefishtwo.ca> * Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org> * Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr> * Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr> @@ -326,7 +326,7 @@ static void gscps2_close(struct serio *port) * @return: success/error report */ -static int __init gscps2_probe(struct parisc_device *dev) +static int __devinit gscps2_probe(struct parisc_device *dev) { struct gscps2port *ps2port; struct serio *serio; @@ -443,7 +443,7 @@ static struct parisc_driver parisc_ps2_driver = { .name = "gsc_ps2", .id_table = gscps2_device_tbl, .probe = gscps2_probe, - .remove = gscps2_remove, + .remove = __devexit_p(gscps2_remove), }; static int __init gscps2_init(void) diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index 7ba9f2b2c041..6cd03ebaf5fb 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -993,10 +993,8 @@ int hil_mlc_unregister(hil_mlc *mlc) static int __init hil_mlc_init(void) { - init_timer(&hil_mlcs_kicker); - hil_mlcs_kicker.expires = jiffies + HZ; - hil_mlcs_kicker.function = &hil_mlcs_timer; - add_timer(&hil_mlcs_kicker); + setup_timer(&hil_mlcs_kicker, &hil_mlcs_timer, 0); + mod_timer(&hil_mlcs_kicker, jiffies + HZ); tasklet_enable(&hil_mlcs_tasklet); @@ -1005,7 +1003,7 @@ static int __init hil_mlc_init(void) static void __exit hil_mlc_exit(void) { - del_timer(&hil_mlcs_kicker); + del_timer_sync(&hil_mlcs_kicker); tasklet_disable(&hil_mlcs_tasklet); tasklet_kill(&hil_mlcs_tasklet); diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 1c9410d1822c..bcc2d30ec245 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -955,7 +955,7 @@ static int __init hp_sdc_init_hppa(struct parisc_device *d) INIT_DELAYED_WORK(&moduleloader_work, request_module_delayed); ret = hp_sdc_init(); - /* after sucessfull initialization give SDC some time to settle + /* after successfull initialization give SDC some time to settle * and then load the hp_sdc_mlc upper layer driver */ if (!ret) schedule_delayed_work(&moduleloader_work, diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c index 820e51673b26..7d2b820ef58d 100644 --- a/drivers/input/serio/hp_sdc_mlc.c +++ b/drivers/input/serio/hp_sdc_mlc.c @@ -125,7 +125,7 @@ static void hp_sdc_mlc_isr (int irq, void *dev_id, break; default: - printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data); + printk(KERN_WARNING PREFIX "Unknown HIL Error status (%x)!\n", data); break; } diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 2bcf1ace27c0..64b688daf48a 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -67,10 +67,12 @@ static inline void i8042_write_command(int val) #include <linux/dmi.h> -static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { { - /* AUX LOOP command does not raise AUX IRQ */ - .ident = "Arima-Rioworks HDAMB", + /* + * Arima-Rioworks HDAMB - + * AUX LOOP command does not raise AUX IRQ + */ .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"), DMI_MATCH(DMI_BOARD_NAME, "HDAMB"), @@ -78,7 +80,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "ASUS G1S", + /* ASUS G1S */ .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_BOARD_NAME, "G1S"), @@ -86,8 +88,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - /* AUX LOOP command does not raise AUX IRQ */ - .ident = "ASUS P65UP5", + /* ASUS P65UP5 - AUX LOOP command does not raise AUX IRQ */ .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"), @@ -95,7 +96,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Compaq Proliant 8500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), @@ -103,7 +103,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Compaq Proliant DL760", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), @@ -111,7 +110,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "OQO Model 01", + /* OQO Model 01 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "OQO"), DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), @@ -119,8 +118,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - /* AUX LOOP does not work properly */ - .ident = "ULI EV4873", + /* ULI EV4873 - AUX LOOP does not work properly */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ULI"), DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"), @@ -128,7 +126,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Microsoft Virtual Machine", + /* Microsoft Virtual Machine */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), @@ -136,7 +134,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Medion MAM 2070", + /* Medion MAM 2070 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"), @@ -144,7 +142,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Blue FB5601", + /* Blue FB5601 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "blue"), DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"), @@ -152,7 +150,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Gigabyte M912", + /* Gigabyte M912 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_PRODUCT_NAME, "M912"), @@ -160,7 +158,14 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "HP DV9700", + /* Gigabyte M1022M netbook */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co.,Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "M1022E"), + DMI_MATCH(DMI_BOARD_VERSION, "1.02"), + }, + }, + { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), @@ -177,72 +182,72 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { * ... apparently some Toshibas don't like MUX mode either and * die horrible death on reboot. */ -static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { { - .ident = "Fujitsu Lifebook P7010/P7010D", + /* Fujitsu Lifebook P7010/P7010D */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "P7010"), }, }, { - .ident = "Fujitsu Lifebook P7010", + /* Fujitsu Lifebook P7010 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"), }, }, { - .ident = "Fujitsu Lifebook P5020D", + /* Fujitsu Lifebook P5020D */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"), }, }, { - .ident = "Fujitsu Lifebook S2000", + /* Fujitsu Lifebook S2000 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), }, }, { - .ident = "Fujitsu Lifebook S6230", + /* Fujitsu Lifebook S6230 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), }, }, { - .ident = "Fujitsu T70H", + /* Fujitsu T70H */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), }, }, { - .ident = "Fujitsu-Siemens Lifebook T3010", + /* Fujitsu-Siemens Lifebook T3010 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), }, }, { - .ident = "Fujitsu-Siemens Lifebook E4010", + /* Fujitsu-Siemens Lifebook E4010 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), }, }, { - .ident = "Fujitsu-Siemens Amilo Pro 2010", + /* Fujitsu-Siemens Amilo Pro 2010 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"), }, }, { - .ident = "Fujitsu-Siemens Amilo Pro 2030", + /* Fujitsu-Siemens Amilo Pro 2030 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), @@ -253,7 +258,7 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { * No data is coming from the touchscreen unless KBC * is in legacy mode. */ - .ident = "Panasonic CF-29", + /* Panasonic CF-29 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), @@ -261,10 +266,10 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, { /* - * Errors on MUX ports are reported without raising AUXDATA + * HP Pavilion DV4017EA - + * errors on MUX ports are reported without raising AUXDATA * causing "spurious NAK" messages. */ - .ident = "HP Pavilion DV4017EA", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"), @@ -272,9 +277,9 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, { /* - * Like DV4017EA does not raise AUXERR for errors on MUX ports. + * HP Pavilion ZT1000 - + * like DV4017EA does not raise AUXERR for errors on MUX ports. */ - .ident = "HP Pavilion ZT1000", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"), @@ -283,44 +288,41 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, { /* - * Like DV4017EA does not raise AUXERR for errors on MUX ports. + * HP Pavilion DV4270ca - + * like DV4017EA does not raise AUXERR for errors on MUX ports. */ - .ident = "HP Pavilion DV4270ca", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"), }, }, { - .ident = "Toshiba P10", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), }, }, { - .ident = "Toshiba Equium A110", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), }, }, { - .ident = "Alienware Sentia", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), }, }, { - .ident = "Sharp Actius MM20", + /* Sharp Actius MM20 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SHARP"), DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"), }, }, { - .ident = "Sony Vaio FS-115b", + /* Sony Vaio FS-115b */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), @@ -328,73 +330,72 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, { /* - * Reset and GET ID commands issued via KBD port are + * Sony Vaio FZ-240E - + * reset and GET ID commands issued via KBD port are * sometimes being delivered to AUX3. */ - .ident = "Sony Vaio FZ-240E", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"), }, }, { - .ident = "Amoi M636/A737", + /* Amoi M636/A737 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."), DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), }, }, { - .ident = "Lenovo 3000 n100", + /* Lenovo 3000 n100 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "076804U"), }, }, { - .ident = "Acer Aspire 1360", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), }, }, { - .ident = "Gericom Bellagio", + /* Gericom Bellagio */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), }, }, { - .ident = "IBM 2656", + /* IBM 2656 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), DMI_MATCH(DMI_PRODUCT_NAME, "2656"), }, }, { - .ident = "Dell XPS M1530", + /* Dell XPS M1530 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"), }, }, { - .ident = "Compal HEL80I", + /* Compal HEL80I */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"), DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), }, }, { - .ident = "Dell Vostro 1510", + /* Dell Vostro 1510 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), }, }, { - .ident = "Acer Aspire 5536", + /* Acer Aspire 5536 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"), @@ -404,65 +405,65 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { { } }; -static struct dmi_system_id __initdata i8042_dmi_reset_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { { - .ident = "MSI Wind U-100", + /* MSI Wind U-100 */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "U-100"), DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), }, }, { - .ident = "LG Electronics X110", + /* LG Electronics X110 */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "X110"), DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."), }, }, { - .ident = "Acer Aspire One 150", + /* Acer Aspire One 150 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), }, }, { - .ident = "Advent 4211", + /* Advent 4211 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"), DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"), }, }, { - .ident = "Medion Akoya Mini E1210", + /* Medion Akoya Mini E1210 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), DMI_MATCH(DMI_PRODUCT_NAME, "E1210"), }, }, { - .ident = "Mivvy M310", + /* Mivvy M310 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"), DMI_MATCH(DMI_PRODUCT_NAME, "N10"), }, }, { - .ident = "Dell Vostro 1320", + /* Dell Vostro 1320 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"), }, }, { - .ident = "Dell Vostro 1520", + /* Dell Vostro 1520 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"), }, }, { - .ident = "Dell Vostro 1720", + /* Dell Vostro 1720 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"), @@ -472,16 +473,16 @@ static struct dmi_system_id __initdata i8042_dmi_reset_table[] = { }; #ifdef CONFIG_PNP -static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_nopnp_table[] = { { - .ident = "Intel MBO Desktop D845PESV", + /* Intel MBO Desktop D845PESV */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "D845PESV"), DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), }, }, { - .ident = "MSI Wind U-100", + /* MSI Wind U-100 */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "U-100"), DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), @@ -490,27 +491,23 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { { } }; -static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = { { - .ident = "Portable", .matches = { DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ }, }, { - .ident = "Laptop", .matches = { DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */ }, }, { - .ident = "Notebook", .matches = { DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ }, }, { - .ident = "Sub-Notebook", .matches = { DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ }, @@ -525,58 +522,58 @@ static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = { * Originally, this was just confined to older laptops, but a few Acer laptops * have turned up in 2007 that also need this again. */ -static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = { { - .ident = "Acer Aspire 5630", + /* Acer Aspire 5630 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), }, }, { - .ident = "Acer Aspire 5650", + /* Acer Aspire 5650 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), }, }, { - .ident = "Acer Aspire 5680", + /* Acer Aspire 5680 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), }, }, { - .ident = "Acer Aspire 5720", + /* Acer Aspire 5720 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"), }, }, { - .ident = "Acer Aspire 9110", + /* Acer Aspire 9110 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), }, }, { - .ident = "Acer TravelMate 660", + /* Acer TravelMate 660 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), }, }, { - .ident = "Acer TravelMate 2490", + /* Acer TravelMate 2490 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), }, }, { - .ident = "Acer TravelMate 4280", + /* Acer TravelMate 4280 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"), diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 1df02d25aca5..d84a36e545f6 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -126,6 +126,8 @@ static unsigned char i8042_suppress_kbd_ack; static struct platform_device *i8042_platform_device; static irqreturn_t i8042_interrupt(int irq, void *dev_id); +static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, + struct serio *serio); void i8042_lock_chip(void) { @@ -139,6 +141,48 @@ void i8042_unlock_chip(void) } EXPORT_SYMBOL(i8042_unlock_chip); +int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, + struct serio *serio)) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&i8042_lock, flags); + + if (i8042_platform_filter) { + ret = -EBUSY; + goto out; + } + + i8042_platform_filter = filter; + +out: + spin_unlock_irqrestore(&i8042_lock, flags); + return ret; +} +EXPORT_SYMBOL(i8042_install_filter); + +int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, + struct serio *port)) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&i8042_lock, flags); + + if (i8042_platform_filter != filter) { + ret = -EINVAL; + goto out; + } + + i8042_platform_filter = NULL; + +out: + spin_unlock_irqrestore(&i8042_lock, flags); + return ret; +} +EXPORT_SYMBOL(i8042_remove_filter); + /* * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to * be ready for reading values from it / writing values to it. @@ -369,6 +413,31 @@ static void i8042_stop(struct serio *serio) } /* + * i8042_filter() filters out unwanted bytes from the input data stream. + * It is called from i8042_interrupt and thus is running with interrupts + * off and i8042_lock held. + */ +static bool i8042_filter(unsigned char data, unsigned char str, + struct serio *serio) +{ + if (unlikely(i8042_suppress_kbd_ack)) { + if ((~str & I8042_STR_AUXDATA) && + (data == 0xfa || data == 0xfe)) { + i8042_suppress_kbd_ack--; + dbg("Extra keyboard ACK - filtered out\n"); + return true; + } + } + + if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) { + dbg("Filtered out by platfrom filter\n"); + return true; + } + + return false; +} + +/* * i8042_interrupt() is the most important function in this driver - * it handles the interrupts from the i8042, and sends incoming bytes * to the upper layers. @@ -377,13 +446,16 @@ static void i8042_stop(struct serio *serio) static irqreturn_t i8042_interrupt(int irq, void *dev_id) { struct i8042_port *port; + struct serio *serio; unsigned long flags; unsigned char str, data; unsigned int dfl; unsigned int port_no; + bool filtered; int ret = 1; spin_lock_irqsave(&i8042_lock, flags); + str = i8042_read_status(); if (unlikely(~str & I8042_STR_OBF)) { spin_unlock_irqrestore(&i8042_lock, flags); @@ -391,8 +463,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) ret = 0; goto out; } + data = i8042_read_data(); - spin_unlock_irqrestore(&i8042_lock, flags); if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { static unsigned long last_transmit; @@ -441,21 +513,19 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) } port = &i8042_ports[port_no]; + serio = port->exists ? port->serio : NULL; dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", data, port_no, irq, dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); - if (unlikely(i8042_suppress_kbd_ack)) - if (port_no == I8042_KBD_PORT_NO && - (data == 0xfa || data == 0xfe)) { - i8042_suppress_kbd_ack--; - goto out; - } + filtered = i8042_filter(data, str, serio); + + spin_unlock_irqrestore(&i8042_lock, flags); - if (likely(port->exists)) - serio_interrupt(port->serio, data, dfl); + if (likely(port->exists && !filtered)) + serio_interrupt(serio, data, dfl); out: return IRQ_RETVAL(ret); diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index f412c69478a8..d55874e5d1c2 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -180,8 +180,8 @@ static void __devinit ps2_clear_input(struct ps2if *ps2if) } } -static inline unsigned int -ps2_test_one(struct ps2if *ps2if, unsigned int mask) +static unsigned int __devinit ps2_test_one(struct ps2if *ps2if, + unsigned int mask) { unsigned int val; @@ -197,7 +197,7 @@ ps2_test_one(struct ps2if *ps2if, unsigned int mask) * Test the keyboard interface. We basically check to make sure that * we can drive each line to the keyboard independently of each other. */ -static int __init ps2_test(struct ps2if *ps2if) +static int __devinit ps2_test(struct ps2if *ps2if) { unsigned int stat; int ret = 0; @@ -312,7 +312,7 @@ static int __devinit ps2_probe(struct sa1111_dev *dev) /* * Remove one device from this driver. */ -static int ps2_remove(struct sa1111_dev *dev) +static int __devexit ps2_remove(struct sa1111_dev *dev) { struct ps2if *ps2if = sa1111_get_drvdata(dev); @@ -335,7 +335,7 @@ static struct sa1111_driver ps2_driver = { }, .devid = SA1111_DEVID_PS2, .probe = ps2_probe, - .remove = ps2_remove, + .remove = __devexit_p(ps2_remove), }; static int __init ps2_init(void) diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c new file mode 100644 index 000000000000..fbd3987af57f --- /dev/null +++ b/drivers/input/sparse-keymap.c @@ -0,0 +1,250 @@ +/* + * Generic support for sparse keymaps + * + * Copyright (c) 2009 Dmitry Torokhov + * + * Derived from wistron button driver: + * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> + * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> + * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include <linux/input.h> +#include <linux/input/sparse-keymap.h> + +MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); +MODULE_DESCRIPTION("Generic support for sparse keymaps"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); + +/** + * sparse_keymap_entry_from_scancode - perform sparse keymap lookup + * @dev: Input device using sparse keymap + * @code: Scan code + * + * This function is used to perform &struct key_entry lookup in an + * input device using sparse keymap. + */ +struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev, + unsigned int code) +{ + struct key_entry *key; + + for (key = dev->keycode; key->type != KE_END; key++) + if (code == key->code) + return key; + + return NULL; +} +EXPORT_SYMBOL(sparse_keymap_entry_from_scancode); + +/** + * sparse_keymap_entry_from_keycode - perform sparse keymap lookup + * @dev: Input device using sparse keymap + * @keycode: Key code + * + * This function is used to perform &struct key_entry lookup in an + * input device using sparse keymap. + */ +struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, + unsigned int keycode) +{ + struct key_entry *key; + + for (key = dev->keycode; key->type != KE_END; key++) + if (key->type == KE_KEY && keycode == key->keycode) + return key; + + return NULL; +} +EXPORT_SYMBOL(sparse_keymap_entry_from_keycode); + +static int sparse_keymap_getkeycode(struct input_dev *dev, + int scancode, int *keycode) +{ + const struct key_entry *key = + sparse_keymap_entry_from_scancode(dev, scancode); + + if (key && key->type == KE_KEY) { + *keycode = key->keycode; + return 0; + } + + return -EINVAL; +} + +static int sparse_keymap_setkeycode(struct input_dev *dev, + int scancode, int keycode) +{ + struct key_entry *key; + int old_keycode; + + if (keycode < 0 || keycode > KEY_MAX) + return -EINVAL; + + key = sparse_keymap_entry_from_scancode(dev, scancode); + if (key && key->type == KE_KEY) { + old_keycode = key->keycode; + key->keycode = keycode; + set_bit(keycode, dev->keybit); + if (!sparse_keymap_entry_from_keycode(dev, old_keycode)) + clear_bit(old_keycode, dev->keybit); + return 0; + } + + return -EINVAL; +} + +/** + * sparse_keymap_setup - set up sparse keymap for an input device + * @dev: Input device + * @keymap: Keymap in form of array of &key_entry structures ending + * with %KE_END type entry + * @setup: Function that can be used to adjust keymap entries + * depending on device's deeds, may be %NULL + * + * The function calculates size and allocates copy of the original + * keymap after which sets up input device event bits appropriately. + * Before destroying input device allocated keymap should be freed + * with a call to sparse_keymap_free(). + */ +int sparse_keymap_setup(struct input_dev *dev, + const struct key_entry *keymap, + int (*setup)(struct input_dev *, struct key_entry *)) +{ + size_t map_size = 1; /* to account for the last KE_END entry */ + const struct key_entry *e; + struct key_entry *map, *entry; + int i; + int error; + + for (e = keymap; e->type != KE_END; e++) + map_size++; + + map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL); + if (!map) + return -ENOMEM; + + memcpy(map, keymap, map_size * sizeof (struct key_entry)); + + for (i = 0; i < map_size; i++) { + entry = &map[i]; + + if (setup) { + error = setup(dev, entry); + if (error) + goto err_out; + } + + switch (entry->type) { + case KE_KEY: + __set_bit(EV_KEY, dev->evbit); + __set_bit(entry->keycode, dev->keybit); + break; + + case KE_SW: + __set_bit(EV_SW, dev->evbit); + __set_bit(entry->sw.code, dev->swbit); + break; + } + } + + dev->keycode = map; + dev->keycodemax = map_size; + dev->getkeycode = sparse_keymap_getkeycode; + dev->setkeycode = sparse_keymap_setkeycode; + + return 0; + + err_out: + kfree(keymap); + return error; + +} +EXPORT_SYMBOL(sparse_keymap_setup); + +/** + * sparse_keymap_free - free memory allocated for sparse keymap + * @dev: Input device using sparse keymap + * + * This function is used to free memory allocated by sparse keymap + * in an input device that was set up by sparse_keymap_setup(). + */ +void sparse_keymap_free(struct input_dev *dev) +{ + kfree(dev->keycode); + dev->keycode = NULL; + dev->keycodemax = 0; + dev->getkeycode = NULL; + dev->setkeycode = NULL; +} +EXPORT_SYMBOL(sparse_keymap_free); + +/** + * sparse_keymap_report_entry - report event corresponding to given key entry + * @dev: Input device for which event should be reported + * @ke: key entry describing event + * @value: Value that should be reported (ignored by %KE_SW entries) + * @autorelease: Signals whether release event should be emitted for %KE_KEY + * entries right after reporting press event, ignored by all other + * entries + * + * This function is used to report input event described by given + * &struct key_entry. + */ +void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke, + unsigned int value, bool autorelease) +{ + switch (ke->type) { + case KE_KEY: + input_report_key(dev, ke->keycode, value); + input_sync(dev); + if (value && autorelease) { + input_report_key(dev, ke->keycode, 0); + input_sync(dev); + } + break; + + case KE_SW: + value = ke->sw.value; + /* fall through */ + + case KE_VSW: + input_report_switch(dev, ke->sw.code, value); + break; + } +} +EXPORT_SYMBOL(sparse_keymap_report_entry); + +/** + * sparse_keymap_report_event - report event corresponding to given scancode + * @dev: Input device using sparse keymap + * @code: Scan code + * @value: Value that should be reported (ignored by %KE_SW entries) + * @autorelease: Signals whether release event should be emitted for %KE_KEY + * entries right after reporting press event, ignored by all other + * entries + * + * This function is used to perform lookup in an input device using sparse + * keymap and report corresponding event. Returns %true if lookup was + * successful and %false otherwise. + */ +bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code, + unsigned int value, bool autorelease) +{ + const struct key_entry *ke = + sparse_keymap_entry_from_scancode(dev, code); + + if (ke) { + sparse_keymap_report_entry(dev, ke, value, autorelease); + return true; + } + + return false; +} +EXPORT_SYMBOL(sparse_keymap_report_event); + diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 9114ae1c7488..16310f368dab 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -1,7 +1,7 @@ /* * drivers/input/tablet/wacom.h * - * USB Wacom Graphire and Wacom Intuos tablet support + * USB Wacom tablet support * * Copyright (c) 2000-2004 Vojtech Pavlik <vojtech@ucw.cz> * Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk> @@ -69,6 +69,9 @@ * v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A) * v1.50 (pc) - Fixed a TabletPC touch bug in 2.6.28 * v1.51 (pc) - Added support for Intuos4 + * v1.52 (pc) - Query Wacom data upon system resume + * - add defines for features->type + * - add new devices (0x9F, 0xE2, and 0XE3) */ /* @@ -89,9 +92,9 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.51" +#define DRIVER_VERSION "v1.52" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" -#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" +#define DRIVER_DESC "USB Wacom tablet driver" #define DRIVER_LICENSE "GPL" MODULE_AUTHOR(DRIVER_AUTHOR); @@ -133,6 +136,8 @@ extern void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_w extern void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern __u16 wacom_le16_to_cpu(unsigned char *data); diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index ea30c983a33e..072f33b3b2b0 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -1,7 +1,7 @@ /* * drivers/input/tablet/wacom_sys.c * - * USB Wacom Graphire and Wacom Intuos tablet support - system specific code + * USB Wacom tablet support - system specific code */ /* @@ -209,6 +209,7 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) | + BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) | BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2); input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0); } @@ -256,6 +257,7 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) | + BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) | BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) | BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) | BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2); @@ -269,7 +271,8 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { - input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_STYLUS2); + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | + BIT_MASK(BTN_STYLUS) | BIT_MASK(BTN_STYLUS2); } void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac) @@ -277,12 +280,32 @@ void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER); } +void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + if (wacom_wac->features->device_type == BTN_TOOL_DOUBLETAP || + wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) { + input_set_abs_params(input_dev, ABS_RX, 0, wacom_wac->features->x_phy, 0, 0); + input_set_abs_params(input_dev, ABS_RY, 0, wacom_wac->features->y_phy, 0, 0); + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP); + } +} + +void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + if (wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) { + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP); + input_dev->evbit[0] |= BIT_MASK(EV_MSC); + input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL); + } +} + static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, - struct wacom_wac *wacom_wac) + struct wacom_features *features) { struct usb_device *dev = interface_to_usbdev(intf); - struct wacom_features *features = wacom_wac->features; - char limit = 0, result = 0; + char limit = 0; + /* result has to be defined as int for some devices */ + int result = 0; int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0; unsigned char *report; @@ -328,13 +351,24 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi case HID_USAGE_X: if (usage == WCM_DESKTOP) { if (finger) { - features->touch_x_max = - features->touch_y_max = - wacom_le16_to_cpu(&report[i + 3]); + features->device_type = BTN_TOOL_DOUBLETAP; + if (features->type == TABLETPC2FG) { + /* need to reset back */ + features->pktlen = WACOM_PKGLEN_TPC2FG; + features->device_type = BTN_TOOL_TRIPLETAP; + } features->x_max = + wacom_le16_to_cpu(&report[i + 3]); + features->x_phy = wacom_le16_to_cpu(&report[i + 6]); - i += 7; + features->unit = report[i + 9]; + features->unitExpo = report[i + 11]; + i += 12; } else if (pen) { + /* penabled only accepts exact bytes of data */ + if (features->type == TABLETPC2FG) + features->pktlen = WACOM_PKGLEN_PENABLED; + features->device_type = BTN_TOOL_PEN; features->x_max = wacom_le16_to_cpu(&report[i + 3]); i += 4; @@ -350,10 +384,35 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi break; case HID_USAGE_Y: - if (usage == WCM_DESKTOP) - features->y_max = - wacom_le16_to_cpu(&report[i + 3]); - i += 4; + if (usage == WCM_DESKTOP) { + if (finger) { + features->device_type = BTN_TOOL_DOUBLETAP; + if (features->type == TABLETPC2FG) { + /* need to reset back */ + features->pktlen = WACOM_PKGLEN_TPC2FG; + features->device_type = BTN_TOOL_TRIPLETAP; + features->y_max = + wacom_le16_to_cpu(&report[i + 3]); + features->y_phy = + wacom_le16_to_cpu(&report[i + 6]); + i += 7; + } else { + features->y_max = + features->x_max; + features->y_phy = + wacom_le16_to_cpu(&report[i + 3]); + i += 4; + } + } else if (pen) { + /* penabled only accepts exact bytes of data */ + if (features->type == TABLETPC2FG) + features->pktlen = WACOM_PKGLEN_PENABLED; + features->device_type = BTN_TOOL_PEN; + features->y_max = + wacom_le16_to_cpu(&report[i + 3]); + i += 4; + } + } break; case HID_USAGE_FINGER: @@ -376,7 +435,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi break; case HID_COLLECTION: - /* reset UsagePage ans Finger */ + /* reset UsagePage and Finger */ finger = usage = 0; break; } @@ -388,43 +447,92 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi return result; } -static int wacom_query_tablet_data(struct usb_interface *intf) +static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) { unsigned char *rep_data; - int limit = 0; - int error; + int limit = 0, report_id = 2; + int error = -ENOMEM; rep_data = kmalloc(2, GFP_KERNEL); if (!rep_data) - return -ENOMEM; - - do { - rep_data[0] = 2; - rep_data[1] = 2; - error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, - 2, rep_data, 2); - if (error >= 0) - error = usb_get_report(intf, - WAC_HID_FEATURE_REPORT, 2, - rep_data, 2); - } while ((error < 0 || rep_data[1] != 2) && limit++ < 5); + return error; + + /* ask to report tablet data if it is 2FGT or not a Tablet PC */ + if (features->device_type == BTN_TOOL_TRIPLETAP) { + do { + rep_data[0] = 3; + rep_data[1] = 4; + report_id = 3; + error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, + report_id, rep_data, 2); + if (error >= 0) + error = usb_get_report(intf, + WAC_HID_FEATURE_REPORT, report_id, + rep_data, 3); + } while ((error < 0 || rep_data[1] != 4) && limit++ < 5); + } else if (features->type != TABLETPC && features->type != TABLETPC2FG) { + do { + rep_data[0] = 2; + rep_data[1] = 2; + error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, + report_id, rep_data, 2); + if (error >= 0) + error = usb_get_report(intf, + WAC_HID_FEATURE_REPORT, report_id, + rep_data, 2); + } while ((error < 0 || rep_data[1] != 2) && limit++ < 5); + } kfree(rep_data); return error < 0 ? error : 0; } +static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, + struct wacom_features *features) +{ + int error = 0; + struct usb_host_interface *interface = intf->cur_altsetting; + struct hid_descriptor *hid_desc; + + /* default device to penabled */ + features->device_type = BTN_TOOL_PEN; + + /* only Tablet PCs need to retrieve the info */ + if ((features->type != TABLETPC) && (features->type != TABLETPC2FG)) + goto out; + + if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) { + if (usb_get_extra_descriptor(&interface->endpoint[0], + HID_DEVICET_REPORT, &hid_desc)) { + printk("wacom: can not retrieve extra class descriptor\n"); + error = 1; + goto out; + } + } + error = wacom_parse_hid(intf, hid_desc, features); + if (error) + goto out; + + /* touch device found but size is not defined. use default */ + if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) { + features->x_max = 1023; + features->y_max = 1023; + } + + out: + return error; +} + static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); - struct usb_host_interface *interface = intf->cur_altsetting; struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; struct wacom_wac *wacom_wac; struct wacom_features *features; struct input_dev *input_dev; int error = -ENOMEM; - struct hid_descriptor *hid_desc; wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL); @@ -432,7 +540,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i if (!wacom || !input_dev || !wacom_wac) goto fail1; - wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma); + wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX, GFP_KERNEL, &wacom->data_dma); if (!wacom_wac->data) goto fail1; @@ -448,7 +556,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); wacom_wac->features = features = get_wacom_feature(id); - BUG_ON(features->pktlen > 10); + BUG_ON(features->pktlen > WACOM_PKGLEN_MAX); input_dev->name = wacom_wac->features->name; wacom->wacom_wac = wacom_wac; @@ -463,47 +571,24 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i endpoint = &intf->cur_altsetting->endpoint[0].desc; - /* Initialize touch_x_max and touch_y_max in case it is not defined */ - if (wacom_wac->features->type == TABLETPC) { - features->touch_x_max = 1023; - features->touch_y_max = 1023; - } else { - features->touch_x_max = 0; - features->touch_y_max = 0; - } - - /* TabletPC need to retrieve the physical and logical maximum from report descriptor */ - if (wacom_wac->features->type == TABLETPC) { - if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) { - if (usb_get_extra_descriptor(&interface->endpoint[0], - HID_DEVICET_REPORT, &hid_desc)) { - printk("wacom: can not retrive extra class descriptor\n"); - goto fail2; - } - } - error = wacom_parse_hid(intf, hid_desc, wacom_wac); - if (error) - goto fail2; - } + /* Retrieve the physical and logical size for OEM devices */ + error = wacom_retrieve_hid_descriptor(intf, features); + if (error) + goto fail2; input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | - BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS); + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, 0, features->x_max, 4, 0); input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, 4, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 0); - if (features->type == TABLETPC) { - input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP); - input_set_abs_params(input_dev, ABS_RX, 0, features->touch_x_max, 4, 0); - input_set_abs_params(input_dev, ABS_RY, 0, features->touch_y_max, 4, 0); - } input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); wacom_init_input_dev(input_dev, wacom_wac); usb_fill_int_urb(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), - wacom_wac->data, wacom_wac->features->pktlen, + wacom_wac->data, features->pktlen, wacom_sys_irq, wacom, endpoint->bInterval); wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -512,18 +597,14 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i if (error) goto fail3; - /* - * Ask the tablet to report tablet data if it is not a Tablet PC. - * Note that if query fails it is not a hard failure. - */ - if (wacom_wac->features->type != TABLETPC) - wacom_query_tablet_data(intf); + /* Note that if query fails it is not a hard failure */ + wacom_query_tablet_data(intf, features); usb_set_intfdata(intf, wacom); return 0; fail3: usb_free_urb(wacom->irq); - fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma); + fail2: usb_buffer_free(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); fail1: input_free_device(input_dev); kfree(wacom); kfree(wacom_wac); @@ -539,7 +620,7 @@ static void wacom_disconnect(struct usb_interface *intf) usb_kill_urb(wacom->irq); input_unregister_device(wacom->dev); usb_free_urb(wacom->irq); - usb_buffer_free(interface_to_usbdev(intf), 10, + usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX, wacom->wacom_wac->data, wacom->data_dma); kfree(wacom->wacom_wac); kfree(wacom); @@ -559,12 +640,16 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message) static int wacom_resume(struct usb_interface *intf) { struct wacom *wacom = usb_get_intfdata(intf); + struct wacom_features *features = wacom->wacom_wac->features; int rv; mutex_lock(&wacom->lock); - if (wacom->open) + if (wacom->open) { rv = usb_submit_urb(wacom->irq, GFP_NOIO); - else + /* switch to wacom mode if needed */ + if (!wacom_retrieve_hid_descriptor(intf, features)) + wacom_query_tablet_data(intf, features); + } else rv = 0; mutex_unlock(&wacom->lock); diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index c896d6a21b7e..1056f149fe31 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1,7 +1,7 @@ /* * drivers/input/tablet/wacom_wac.c * - * USB Wacom Graphire and Wacom Intuos tablet support - Wacom specific code + * USB Wacom tablet support - Wacom specific code * */ @@ -58,16 +58,15 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) unsigned char *data = wacom->data; int prox, pressure; - if (data[0] != 2) { + if (data[0] != WACOM_REPORT_PENABLED) { dbg("wacom_pl_irq: received unknown report #%d", data[0]); return 0; } prox = data[1] & 0x40; - wacom->id[0] = ERASER_DEVICE_ID; if (prox) { - + wacom->id[0] = ERASER_DEVICE_ID; pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); if (wacom->features->pressure_max > 255) pressure = (pressure << 1) | ((data[4] >> 6) & 1); @@ -128,7 +127,7 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo) { unsigned char *data = wacom->data; - if (data[0] != 2) { + if (data[0] != WACOM_REPORT_PENABLED) { printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]); return 0; } @@ -155,14 +154,16 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) { unsigned char *data = wacom->data; int x, y, rw; + static int penData = 0; - if (data[0] != 2) { + if (data[0] != WACOM_REPORT_PENABLED) { dbg("wacom_graphire_irq: received unknown report #%d", data[0]); return 0; } if (data[1] & 0x80) { /* in prox and not a pad data */ + penData = 1; switch ((data[1] >> 5) & 3) { @@ -232,7 +233,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) switch (wacom->features->type) { case WACOM_G4: if (data[7] & 0xf8) { - wacom_input_sync(wcombo); /* sync last event */ + if (penData) { + wacom_input_sync(wcombo); /* sync last event */ + if (!wacom->id[0]) + penData = 0; + } wacom->id[1] = PAD_DEVICE_ID; wacom_report_key(wcombo, BTN_0, (data[7] & 0x40)); wacom_report_key(wcombo, BTN_4, (data[7] & 0x80)); @@ -242,10 +247,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); } else if (wacom->id[1]) { - wacom_input_sync(wcombo); /* sync last event */ + if (penData) { + wacom_input_sync(wcombo); /* sync last event */ + if (!wacom->id[0]) + penData = 0; + } wacom->id[1] = 0; wacom_report_key(wcombo, BTN_0, (data[7] & 0x40)); wacom_report_key(wcombo, BTN_4, (data[7] & 0x80)); + wacom_report_rel(wcombo, REL_WHEEL, 0); wacom_report_key(wcombo, BTN_TOOL_FINGER, 0); wacom_report_abs(wcombo, ABS_MISC, 0); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); @@ -253,7 +263,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) break; case WACOM_MO: if ((data[7] & 0xf8) || (data[8] & 0xff)) { - wacom_input_sync(wcombo); /* sync last event */ + if (penData) { + wacom_input_sync(wcombo); /* sync last event */ + if (!wacom->id[0]) + penData = 0; + } wacom->id[1] = PAD_DEVICE_ID; wacom_report_key(wcombo, BTN_0, (data[7] & 0x08)); wacom_report_key(wcombo, BTN_1, (data[7] & 0x20)); @@ -264,7 +278,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); } else if (wacom->id[1]) { - wacom_input_sync(wcombo); /* sync last event */ + if (penData) { + wacom_input_sync(wcombo); /* sync last event */ + if (!wacom->id[0]) + penData = 0; + } wacom->id[1] = 0; wacom_report_key(wcombo, BTN_0, (data[7] & 0x08)); wacom_report_key(wcombo, BTN_1, (data[7] & 0x20)); @@ -432,7 +450,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) unsigned int t; int idx = 0, result; - if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) { + if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_INTUOSREAD + && data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD) { dbg("wacom_intuos_irq: received unknown report #%d", data[0]); return 0; } @@ -442,7 +461,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) idx = data[1] & 0x01; /* pad packets. Works as a second tool and is always in prox */ - if (data[0] == 12) { + if (data[0] == WACOM_REPORT_INTUOSPAD) { /* initiate the pad as a device */ if (wacom->tool[1] != BTN_TOOL_FINGER) wacom->tool[1] = BTN_TOOL_FINGER; @@ -608,95 +627,163 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) return 1; } + +static void wacom_tpc_finger_in(struct wacom_wac *wacom, void *wcombo, char *data, int idx) +{ + wacom_report_abs(wcombo, ABS_X, + (data[2 + idx * 2] & 0xff) | ((data[3 + idx * 2] & 0x7f) << 8)); + wacom_report_abs(wcombo, ABS_Y, + (data[6 + idx * 2] & 0xff) | ((data[7 + idx * 2] & 0x7f) << 8)); + wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); + wacom_report_key(wcombo, wacom->tool[idx], 1); + if (idx) + wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); + else + wacom_report_key(wcombo, BTN_TOUCH, 1); +} + +static void wacom_tpc_touch_out(struct wacom_wac *wacom, void *wcombo, int idx) +{ + wacom_report_abs(wcombo, ABS_X, 0); + wacom_report_abs(wcombo, ABS_Y, 0); + wacom_report_abs(wcombo, ABS_MISC, 0); + wacom_report_key(wcombo, wacom->tool[idx], 0); + if (idx) + wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); + else + wacom_report_key(wcombo, BTN_TOUCH, 0); + return; +} + +static void wacom_tpc_touch_in(struct wacom_wac *wacom, void *wcombo) +{ + char *data = wacom->data; + struct urb *urb = ((struct wacom_combo *)wcombo)->urb; + static int firstFinger = 0; + static int secondFinger = 0; + + wacom->tool[0] = BTN_TOOL_DOUBLETAP; + wacom->id[0] = TOUCH_DEVICE_ID; + wacom->tool[1] = BTN_TOOL_TRIPLETAP; + + if (urb->actual_length != WACOM_PKGLEN_TPC1FG) { + switch (data[0]) { + case WACOM_REPORT_TPC1FG: + wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2])); + wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4])); + wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6])); + wacom_report_key(wcombo, BTN_TOUCH, wacom_le16_to_cpu(&data[6])); + wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); + wacom_report_key(wcombo, wacom->tool[0], 1); + break; + case WACOM_REPORT_TPC2FG: + /* keep this byte to send proper out-prox event */ + wacom->id[1] = data[1] & 0x03; + + if (data[1] & 0x01) { + wacom_tpc_finger_in(wacom, wcombo, data, 0); + firstFinger = 1; + } else if (firstFinger) { + wacom_tpc_touch_out(wacom, wcombo, 0); + } + + if (data[1] & 0x02) { + /* sync first finger data */ + if (firstFinger) + wacom_input_sync(wcombo); + + wacom_tpc_finger_in(wacom, wcombo, data, 1); + secondFinger = 1; + } else if (secondFinger) { + /* sync first finger data */ + if (firstFinger) + wacom_input_sync(wcombo); + + wacom_tpc_touch_out(wacom, wcombo, 1); + secondFinger = 0; + } + if (!(data[1] & 0x01)) + firstFinger = 0; + break; + } + } else { + wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1])); + wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3])); + wacom_report_key(wcombo, BTN_TOUCH, 1); + wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); + wacom_report_key(wcombo, wacom->tool[0], 1); + } + return; +} + static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) { char *data = wacom->data; - int prox = 0, pressure; + int prox = 0, pressure, idx = -1; static int stylusInProx, touchInProx = 1, touchOut; struct urb *urb = ((struct wacom_combo *)wcombo)->urb; dbg("wacom_tpc_irq: received report #%d", data[0]); - if (urb->actual_length == 5 || data[0] == 6) { /* Touch data */ - if (urb->actual_length == 5) { /* with touch */ - prox = data[0] & 0x03; + if (urb->actual_length == WACOM_PKGLEN_TPC1FG || /* single touch */ + data[0] == WACOM_REPORT_TPC1FG || /* single touch */ + data[0] == WACOM_REPORT_TPC2FG) { /* 2FG touch */ + if (urb->actual_length == WACOM_PKGLEN_TPC1FG) { /* with touch */ + prox = data[0] & 0x01; } else { /* with capacity */ - prox = data[1] & 0x03; + if (data[0] == WACOM_REPORT_TPC1FG) + /* single touch */ + prox = data[1] & 0x01; + else + /* 2FG touch data */ + prox = data[1] & 0x03; } if (!stylusInProx) { /* stylus not in prox */ if (prox) { if (touchInProx) { - wacom->tool[1] = BTN_TOOL_DOUBLETAP; - wacom->id[0] = TOUCH_DEVICE_ID; - if (urb->actual_length != 5) { - wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2])); - wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4])); - wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6])); - wacom_report_key(wcombo, BTN_TOUCH, wacom_le16_to_cpu(&data[6])); - } else { - wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1])); - wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3])); - wacom_report_key(wcombo, BTN_TOUCH, 1); - } - wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); - wacom_report_key(wcombo, wacom->tool[1], prox & 0x01); + wacom_tpc_touch_in(wacom, wcombo); touchOut = 1; return 1; } } else { - wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); - wacom_report_key(wcombo, wacom->tool[1], prox & 0x01); - wacom_report_key(wcombo, BTN_TOUCH, 0); + /* 2FGT out-prox */ + if (data[0] == WACOM_REPORT_TPC2FG) { + idx = (wacom->id[1] & 0x01) - 1; + if (idx == 0) { + wacom_tpc_touch_out(wacom, wcombo, idx); + /* sync first finger event */ + if (wacom->id[1] & 0x02) + wacom_input_sync(wcombo); + } + idx = (wacom->id[1] & 0x02) - 1; + if (idx == 1) + wacom_tpc_touch_out(wacom, wcombo, idx); + } else /* one finger touch */ + wacom_tpc_touch_out(wacom, wcombo, 0); touchOut = 0; touchInProx = 1; return 1; } } else if (touchOut || !prox) { /* force touch out-prox */ - wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID); - wacom_report_key(wcombo, wacom->tool[1], 0); - wacom_report_key(wcombo, BTN_TOUCH, 0); + wacom_tpc_touch_out(wacom, wcombo, 0); touchOut = 0; touchInProx = 1; return 1; } - } else if (data[0] == 2) { /* Penabled */ + } else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */ prox = data[1] & 0x20; touchInProx = 0; - wacom->id[0] = ERASER_DEVICE_ID; - - /* - * if going from out of proximity into proximity select between the eraser - * and the pen based on the state of the stylus2 button, choose eraser if - * pressed else choose pen. if not a proximity change from out to in, send - * an out of proximity for previous tool then a in for new tool. - */ if (prox) { /* in prox */ - if (!wacom->tool[0]) { + if (!wacom->id[0]) { /* Going into proximity select tool */ - wacom->tool[1] = (data[1] & 0x08) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - if (wacom->tool[1] == BTN_TOOL_PEN) + wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; + if (wacom->tool[0] == BTN_TOOL_PEN) wacom->id[0] = STYLUS_DEVICE_ID; - } else if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[1] & 0x08)) { - /* - * was entered with stylus2 pressed - * report out proximity for previous tool - */ - wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); - wacom_report_key(wcombo, wacom->tool[1], 0); - wacom_input_sync(wcombo); - - /* set new tool */ - wacom->tool[1] = BTN_TOOL_PEN; - wacom->id[0] = STYLUS_DEVICE_ID; - return 0; - } - if (wacom->tool[1] != BTN_TOOL_RUBBER) { - /* Unknown tool selected default to pen tool */ - wacom->tool[1] = BTN_TOOL_PEN; - wacom->id[0] = STYLUS_DEVICE_ID; + else + wacom->id[0] = ERASER_DEVICE_ID; } wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02); wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10); @@ -706,17 +793,21 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) if (pressure < 0) pressure = wacom->features->pressure_max + pressure + 1; wacom_report_abs(wcombo, ABS_PRESSURE, pressure); - wacom_report_key(wcombo, BTN_TOUCH, pressure); + wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05); } else { + wacom_report_abs(wcombo, ABS_X, 0); + wacom_report_abs(wcombo, ABS_Y, 0); wacom_report_abs(wcombo, ABS_PRESSURE, 0); wacom_report_key(wcombo, BTN_STYLUS, 0); wacom_report_key(wcombo, BTN_STYLUS2, 0); wacom_report_key(wcombo, BTN_TOUCH, 0); + wacom->id[0] = 0; + /* pen is out so touch can be enabled now */ + touchInProx = 1; } - wacom_report_key(wcombo, wacom->tool[1], prox); + wacom_report_key(wcombo, wacom->tool[0], prox); wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); stylusInProx = prox; - wacom->tool[0] = prox; return 1; } return 0; @@ -751,6 +842,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) return wacom_intuos_irq(wacom_wac, wcombo); case TABLETPC: + case TABLETPC2FG: return wacom_tpc_irq(wacom_wac, wcombo); default: @@ -791,9 +883,17 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w input_dev_i4s(input_dev, wacom_wac); input_dev_i(input_dev, wacom_wac); break; + case TABLETPC2FG: + input_dev_tpc2fg(input_dev, wacom_wac); + /* fall through */ + case TABLETPC: + input_dev_tpc(input_dev, wacom_wac); + if (wacom_wac->features->device_type != BTN_TOOL_PEN) + break; /* no need to process stylus stuff */ + + /* fall through */ case PL: case PTU: - case TABLETPC: input_dev_pl(input_dev, wacom_wac); /* fall through */ case PENPARTNER: @@ -804,66 +904,69 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w } static struct wacom_features wacom_features[] = { - { "Wacom Penpartner", 7, 5040, 3780, 255, 0, PENPARTNER }, - { "Wacom Graphire", 8, 10206, 7422, 511, 63, GRAPHIRE }, - { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 63, GRAPHIRE }, - { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 63, GRAPHIRE }, - { "Wacom Graphire3", 8, 10208, 7424, 511, 63, GRAPHIRE }, - { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE }, - { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 }, - { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 }, - { "Wacom BambooFun 4x5", 9, 14760, 9225, 511, 63, WACOM_MO }, - { "Wacom BambooFun 6x8", 9, 21648, 13530, 511, 63, WACOM_MO }, - { "Wacom Bamboo1 Medium",8, 16704, 12064, 511, 63, GRAPHIRE }, - { "Wacom Volito", 8, 5104, 3712, 511, 63, GRAPHIRE }, - { "Wacom PenStation2", 8, 3250, 2320, 255, 63, GRAPHIRE }, - { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE }, - { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE }, - { "Wacom PenPartner2", 8, 3250, 2320, 511, 63, GRAPHIRE }, - { "Wacom Bamboo", 9, 14760, 9225, 511, 63, WACOM_MO }, - { "Wacom Bamboo1", 8, 5104, 3712, 511, 63, GRAPHIRE }, - { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 31, INTUOS }, - { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, - { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 31, INTUOS }, - { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 31, INTUOS }, - { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 31, INTUOS }, - { "Wacom PL400", 8, 5408, 4056, 255, 0, PL }, - { "Wacom PL500", 8, 6144, 4608, 255, 0, PL }, - { "Wacom PL600", 8, 6126, 4604, 255, 0, PL }, - { "Wacom PL600SX", 8, 6260, 5016, 255, 0, PL }, - { "Wacom PL550", 8, 6144, 4608, 511, 0, PL }, - { "Wacom PL800", 8, 7220, 5780, 511, 0, PL }, - { "Wacom PL700", 8, 6758, 5406, 511, 0, PL }, - { "Wacom PL510", 8, 6282, 4762, 511, 0, PL }, - { "Wacom DTU710", 8, 34080, 27660, 511, 0, PL }, - { "Wacom DTF521", 8, 6282, 4762, 511, 0, PL }, - { "Wacom DTF720", 8, 6858, 5506, 511, 0, PL }, - { "Wacom DTF720a", 8, 6858, 5506, 511, 0, PL }, - { "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU }, - { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 31, INTUOS }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, - { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 31, INTUOS }, - { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS }, - { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, INTUOS }, - { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S }, - { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 }, - { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 }, - { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L }, - { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L }, - { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, - { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S }, - { "Wacom Intuos4 4x6", 10, 31496, 19685, 2047, 63, INTUOS4S }, - { "Wacom Intuos4 6x9", 10, 44704, 27940, 2047, 63, INTUOS4 }, - { "Wacom Intuos4 8x13", 10, 65024, 40640, 2047, 63, INTUOS4L }, - { "Wacom Intuos4 12x19", 10, 97536, 60960, 2047, 63, INTUOS4L }, - { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, - { "Wacom Cintiq 20WSX", 10, 86680, 54180, 1023, 63, WACOM_BEE }, - { "Wacom Cintiq 12WX", 10, 53020, 33440, 1023, 63, WACOM_BEE }, - { "Wacom DTU1931", 8, 37832, 30305, 511, 0, PL }, - { "Wacom ISDv4 90", 8, 26202, 16325, 255, 0, TABLETPC }, - { "Wacom ISDv4 93", 8, 26202, 16325, 255, 0, TABLETPC }, - { "Wacom ISDv4 9A", 8, 26202, 16325, 255, 0, TABLETPC }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, + { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER }, + { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }, + { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }, + { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE }, + { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE }, + { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }, + { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 }, + { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 }, + { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }, + { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO }, + { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }, + { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }, + { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE }, + { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }, + { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE }, + { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE }, + { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }, + { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }, + { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }, + { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }, + { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }, + { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }, + { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }, + { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL }, + { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL }, + { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL }, + { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL }, + { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL }, + { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL }, + { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL }, + { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }, + { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL }, + { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }, + { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }, + { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }, + { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU }, + { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }, + { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }, + { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }, + { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }, + { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }, + { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S }, + { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L }, + { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L }, + { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S }, + { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S }, + { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 }, + { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L }, + { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L }, + { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ }, + { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE }, + { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE }, + { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL }, + { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }, + { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }, + { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }, + { "Wacom ISDv4 9F", WACOM_PKGLEN_PENABLED, 26202, 16325, 255, 0, TABLETPC }, + { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }, + { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }, + { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }, { } }; @@ -927,6 +1030,9 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9F) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE2) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE3) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { } }; diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index c10235aba7e5..ee01e1902785 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -9,12 +9,33 @@ #ifndef WACOM_WAC_H #define WACOM_WAC_H +/* maximum packet length for USB devices */ +#define WACOM_PKGLEN_MAX 32 + +/* packet length for individual models */ +#define WACOM_PKGLEN_PENPRTN 7 +#define WACOM_PKGLEN_GRAPHIRE 8 +#define WACOM_PKGLEN_BBFUN 9 +#define WACOM_PKGLEN_INTUOS 10 +#define WACOM_PKGLEN_PENABLED 8 +#define WACOM_PKGLEN_TPC1FG 5 +#define WACOM_PKGLEN_TPC2FG 14 + +/* device IDs */ #define STYLUS_DEVICE_ID 0x02 #define TOUCH_DEVICE_ID 0x03 #define CURSOR_DEVICE_ID 0x06 #define ERASER_DEVICE_ID 0x0A #define PAD_DEVICE_ID 0x0F +/* wacom data packet report IDs */ +#define WACOM_REPORT_PENABLED 2 +#define WACOM_REPORT_INTUOSREAD 5 +#define WACOM_REPORT_INTUOSWRITE 6 +#define WACOM_REPORT_INTUOSPAD 12 +#define WACOM_REPORT_TPC1FG 6 +#define WACOM_REPORT_TPC2FG 13 + enum { PENPARTNER = 0, GRAPHIRE, @@ -32,6 +53,7 @@ enum { WACOM_BEE, WACOM_MO, TABLETPC, + TABLETPC2FG, MAX_TYPE }; @@ -43,8 +65,11 @@ struct wacom_features { int pressure_max; int distance_max; int type; - int touch_x_max; - int touch_y_max; + int device_type; + int x_phy; + int y_phy; + unsigned char unit; + unsigned char unitExpo; }; struct wacom_wac { diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 8cc453c85ea7..dfafc76da4fb 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -111,6 +111,18 @@ config TOUCHSCREEN_DA9034 Say Y here to enable the support for the touchscreen found on Dialog Semiconductor DA9034 PMIC. +config TOUCHSCREEN_DYNAPRO + tristate "Dynapro serial touchscreen" + select SERIO + help + Say Y here if you have a Dynapro serial touchscreen connected to + your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called dynapro. + config TOUCHSCREEN_EETI tristate "EETI touchscreen panel support" depends on I2C @@ -133,6 +145,18 @@ config TOUCHSCREEN_FUJITSU To compile this driver as a module, choose M here: the module will be called fujitsu-ts. +config TOUCHSCREEN_S3C2410 + tristate "Samsung S3C2410 touchscreen input driver" + depends on ARCH_S3C2410 + select S3C24XX_ADC + help + Say Y here if you have the s3c2410 touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s3c2410_ts. + config TOUCHSCREEN_GUNZE tristate "Gunze AHL-51S touchscreen" select SERIO @@ -297,7 +321,7 @@ config TOUCHSCREEN_TOUCHWIN config TOUCHSCREEN_ATMEL_TSADCC tristate "Atmel Touchscreen Interface" - depends on ARCH_AT91SAM9RL + depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 help Say Y here if you have a 4-wire touchscreen connected to the ADC Controller on your Atmel SoC (such as the AT91SAM9RL). @@ -418,6 +442,7 @@ config TOUCHSCREEN_USB_COMPOSITE - IdealTEK URTC1000 - GoTop Super_Q2/GogoPen/PenPower tablets - JASTEC USB Touch Controller/DigiTech DTR-02U + - Zytronic controllers Have a look at <http://linux.chapter7.ch/touchkit/> for a usage description and the required user-space stuff. @@ -425,6 +450,18 @@ config TOUCHSCREEN_USB_COMPOSITE To compile this driver as a module, choose M here: the module will be called usbtouchscreen. +config TOUCHSCREEN_MC13783 + tristate "Freescale MC13783 touchscreen input driver" + depends on MFD_MC13783 + help + Say Y here if you have an Freescale MC13783 PMIC on your + board and want to use its touchscreen + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called mc13783_ts. + config TOUCHSCREEN_USB_EGALAX default y bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED @@ -490,6 +527,16 @@ config TOUCHSCREEN_USB_E2I bool "e2i Touchscreen controller (e.g. from Mimo 740)" depends on TOUCHSCREEN_USB_COMPOSITE +config TOUCHSCREEN_USB_ZYTRONIC + default y + bool "Zytronic controller" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + +config TOUCHSCREEN_USB_ETT_TC5UH + default y + bool "ET&T TC5UH touchscreen controler support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + config TOUCHSCREEN_TOUCHIT213 tristate "Sahara TouchIT-213 touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 15fa62cffc77..d61a3b4def9a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -12,11 +12,13 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o +obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o +obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o @@ -25,7 +27,9 @@ obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o +obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o +obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o @@ -41,4 +45,3 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o -obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 09c810999b92..52d2ca147d8f 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -29,10 +29,9 @@ #include <linux/spi/ads7846.h> #include <asm/irq.h> - /* * This code has been heavily tested on a Nokia 770, and lightly - * tested on other ads7846 devices (OSK/Mistral, Lubbock). + * tested on other ads7846 devices (OSK/Mistral, Lubbock, Spitz). * TSC2046 is just newer ads7846 silicon. * Support for ads7843 tested on Atmel at91sam926x-EK. * Support for ads7845 has only been stubbed in. @@ -43,7 +42,7 @@ * have to maintain our own SW IRQ disabled status. This should be * removed as soon as the affected platform's IRQ handling is fixed. * - * app note sbaa036 talks in more detail about accurate sampling... + * App note sbaa036 talks in more detail about accurate sampling... * that ought to help in situations like LCDs inducing noise (which * can also be helped by using synch signals) and more generally. * This driver tries to utilize the measures described in the app @@ -566,10 +565,8 @@ static void ads7846_rx(void *ads) * once more the measurement */ if (packet->tc.ignore || Rt > ts->pressure_max) { -#ifdef VERBOSE - pr_debug("%s: ignored %d pressure %d\n", - dev_name(&ts->spi->dev), packet->tc.ignore, Rt); -#endif + dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n", + packet->tc.ignore, Rt); hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_MODE_REL); return; @@ -598,9 +595,7 @@ static void ads7846_rx(void *ads) if (!ts->pendown) { input_report_key(input, BTN_TOUCH, 1); ts->pendown = 1; -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "DOWN\n"); -#endif + dev_vdbg(&ts->spi->dev, "DOWN\n"); } if (ts->swap_xy) @@ -608,12 +603,10 @@ static void ads7846_rx(void *ads) input_report_abs(input, ABS_X, x); input_report_abs(input, ABS_Y, y); - input_report_abs(input, ABS_PRESSURE, Rt); + input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt); input_sync(input); -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt); -#endif + dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt); } hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), @@ -723,9 +716,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) input_sync(input); ts->pendown = 0; -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "UP\n"); -#endif + dev_vdbg(&ts->spi->dev, "UP\n"); } /* measurement cycle ended */ diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c index 35377f583e28..a12242f77e23 100644 --- a/drivers/input/touchscreen/atmel-wm97xx.c +++ b/drivers/input/touchscreen/atmel-wm97xx.c @@ -59,7 +59,7 @@ #define ATMEL_WM97XX_AC97C_IRQ (29) #define ATMEL_WM97XX_GPIO_DEFAULT (32+16) /* Pin 16 on port B. */ #else -#error Unkown CPU, this driver only supports AT32AP700X CPUs. +#error Unknown CPU, this driver only supports AT32AP700X CPUs. #endif struct continuous { diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 9c7fce4d74d0..3d9b5166ebe9 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -22,6 +22,8 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <mach/board.h> +#include <mach/cpu.h> /* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ @@ -36,7 +38,9 @@ #define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */ #define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */ #define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ +#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */ #define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ +#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */ #define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */ #define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */ #define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */ @@ -84,7 +88,13 @@ #define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */ #define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */ -#define ADC_CLOCK 1000000 +#define ATMEL_TSADCC_XPOS 0x50 +#define ATMEL_TSADCC_Z1DAT 0x54 +#define ATMEL_TSADCC_Z2DAT 0x58 + +#define PRESCALER_VAL(x) ((x) >> 8) + +#define ADC_DEFAULT_CLOCK 100000 struct atmel_tsadcc { struct input_dev *input; @@ -172,6 +182,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) struct atmel_tsadcc *ts_dev; struct input_dev *input_dev; struct resource *res; + struct at91_tsadcc_data *pdata = pdev->dev.platform_data; int err = 0; unsigned int prsc; unsigned int reg; @@ -242,31 +253,49 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) input_dev->phys = ts_dev->phys; input_dev->dev.parent = &pdev->dev; - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - + __set_bit(EV_ABS, input_dev->evbit); input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0); + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); + /* clk_enable() always returns 0, no need to check it */ clk_enable(ts_dev->clk); prsc = clk_get_rate(ts_dev->clk); dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); - prsc = prsc / ADC_CLOCK / 2 - 1; + if (!pdata) + goto err_fail; + + if (!pdata->adc_clock) + pdata->adc_clock = ADC_DEFAULT_CLOCK; + + prsc = (prsc / (2 * pdata->adc_clock)) - 1; + + /* saturate if this value is too high */ + if (cpu_is_at91sam9rl()) { + if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL)) + prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL); + } else { + if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL)) + prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL); + } + + dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc); reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE | ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */ ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */ - ((prsc << 8) & ATMEL_TSADCC_PRESCAL) | /* PRESCAL */ - ((0x13 << 16) & ATMEL_TSADCC_STARTUP) | /* STARTUP */ - ((0x0F << 28) & ATMEL_TSADCC_PENDBC); /* PENDBC */ + (prsc << 8) | + ((0x26 << 16) & ATMEL_TSADCC_STARTUP) | + ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC); atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST); atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); - atmel_tsadcc_write(ATMEL_TSADCC_TSR, (0x3 << 24) & ATMEL_TSADCC_TSSHTIM); + atmel_tsadcc_write(ATMEL_TSADCC_TSR, + (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM); atmel_tsadcc_read(ATMEL_TSADCC_SR); atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c new file mode 100644 index 000000000000..455353908bdf --- /dev/null +++ b/drivers/input/touchscreen/dynapro.c @@ -0,0 +1,206 @@ +/* + * Dynapro serial touchscreen driver + * + * Copyright (c) 2009 Tias Guns + * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and + * Richard Lemon + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * 2009/09/19 Tias Guns <tias@ulyssis.org> + * Copied inexio.c and edited for Dynapro protocol (from retired Xorg module) + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/serio.h> +#include <linux/init.h> + +#define DRIVER_DESC "Dynapro serial touchscreen driver" + +MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define DYNAPRO_FORMAT_TOUCH_BIT 0x40 +#define DYNAPRO_FORMAT_LENGTH 3 +#define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80 + +#define DYNAPRO_MIN_XC 0 +#define DYNAPRO_MAX_XC 0x3ff +#define DYNAPRO_MIN_YC 0 +#define DYNAPRO_MAX_YC 0x3ff + +#define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4)) +#define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7)) +#define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0]) + +/* + * Per-touchscreen data. + */ + +struct dynapro { + struct input_dev *dev; + struct serio *serio; + int idx; + unsigned char data[DYNAPRO_FORMAT_LENGTH]; + char phys[32]; +}; + +static void dynapro_process_data(struct dynapro *pdynapro) +{ + struct input_dev *dev = pdynapro->dev; + + if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) { + input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data)); + input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data)); + input_report_key(dev, BTN_TOUCH, + DYNAPRO_GET_TOUCHED(pdynapro->data)); + input_sync(dev); + + pdynapro->idx = 0; + } +} + +static irqreturn_t dynapro_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) +{ + struct dynapro *pdynapro = serio_get_drvdata(serio); + + pdynapro->data[pdynapro->idx] = data; + + if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0]) + dynapro_process_data(pdynapro); + else + dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n", + pdynapro->data[0]); + + return IRQ_HANDLED; +} + +static void dynapro_disconnect(struct serio *serio) +{ + struct dynapro *pdynapro = serio_get_drvdata(serio); + + input_get_device(pdynapro->dev); + input_unregister_device(pdynapro->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(pdynapro->dev); + kfree(pdynapro); +} + +/* + * dynapro_connect() is the routine that is called when someone adds a + * new serio device that supports dynapro protocol and registers it as + * an input device. This is usually accomplished using inputattach. + */ + +static int dynapro_connect(struct serio *serio, struct serio_driver *drv) +{ + struct dynapro *pdynapro; + struct input_dev *input_dev; + int err; + + pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!pdynapro || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + pdynapro->serio = serio; + pdynapro->dev = input_dev; + snprintf(pdynapro->phys, sizeof(pdynapro->phys), + "%s/input0", serio->phys); + + input_dev->name = "Dynapro Serial TouchScreen"; + input_dev->phys = pdynapro->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_DYNAPRO; + input_dev->id.product = 0; + input_dev->id.version = 0x0001; + input_dev->dev.parent = &serio->dev; + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_abs_params(pdynapro->dev, ABS_X, + DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0); + input_set_abs_params(pdynapro->dev, ABS_Y, + DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0); + + serio_set_drvdata(serio, pdynapro); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(pdynapro->dev); + if (err) + goto fail3; + + return 0; + + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(pdynapro); + return err; +} + +/* + * The serio driver structure. + */ + +static struct serio_device_id dynapro_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_DYNAPRO, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, dynapro_serio_ids); + +static struct serio_driver dynapro_drv = { + .driver = { + .name = "dynapro", + }, + .description = DRIVER_DESC, + .id_table = dynapro_serio_ids, + .interrupt = dynapro_interrupt, + .connect = dynapro_connect, + .disconnect = dynapro_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +static int __init dynapro_init(void) +{ + return serio_register_driver(&dynapro_drv); +} + +static void __exit dynapro_exit(void) +{ + serio_unregister_driver(&dynapro_drv); +} + +module_init(dynapro_init); +module_exit(dynapro_exit); diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index 8fc3b08deb3b..6cdcf2a6e036 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -14,7 +14,7 @@ * * Notes: * This is a wm97xx extended touch driver to capture touch - * data in a continuous manner on the Intel XScale archictecture + * data in a continuous manner on the Intel XScale architecture * * Features: * - codecs supported:- WM9705, WM9712, WM9713 @@ -131,7 +131,7 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm) /* When the AC97 queue has been drained we need to allow time * to buffer up samples otherwise we end up spinning polling * for samples. The controller can't have a suitably low - * threashold set to use the notifications it gives. + * threshold set to use the notifications it gives. */ schedule_timeout_uninterruptible(1); diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c new file mode 100644 index 000000000000..be115b3b65eb --- /dev/null +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -0,0 +1,258 @@ +/* + * Driver for the Freescale Semiconductor MC13783 touchscreen. + * + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2009 Sascha Hauer, Pengutronix + * + * Initial development of this code was funded by + * Phytec Messtechnik GmbH, http://www.phytec.de/ + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/platform_device.h> +#include <linux/mfd/mc13783.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/input.h> +#include <linux/sched.h> +#include <linux/init.h> + +#define MC13783_TS_NAME "mc13783-ts" + +#define DEFAULT_SAMPLE_TOLERANCE 300 + +static unsigned int sample_tolerance = DEFAULT_SAMPLE_TOLERANCE; +module_param(sample_tolerance, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(sample_tolerance, + "If the minimal and maximal value read out for one axis (out " + "of three) differ by this value (default: " + __stringify(DEFAULT_SAMPLE_TOLERANCE) ") or more, the reading " + "is supposed to be wrong and is discarded. Set to 0 to " + "disable this check."); + +struct mc13783_ts_priv { + struct input_dev *idev; + struct mc13783 *mc13783; + struct delayed_work work; + struct workqueue_struct *workq; + unsigned int sample[4]; +}; + +static irqreturn_t mc13783_ts_handler(int irq, void *data) +{ + struct mc13783_ts_priv *priv = data; + + mc13783_ackirq(priv->mc13783, irq); + + /* + * Kick off reading coordinates. Note that if work happens already + * be queued for future execution (it rearms itself) it will not + * be rescheduled for immediate execution here. However the rearm + * delay is HZ / 50 which is acceptable. + */ + queue_delayed_work(priv->workq, &priv->work, 0); + + return IRQ_HANDLED; +} + +#define sort3(a0, a1, a2) ({ \ + if (a0 > a1) \ + swap(a0, a1); \ + if (a1 > a2) \ + swap(a1, a2); \ + if (a0 > a1) \ + swap(a0, a1); \ + }) + +static void mc13783_ts_report_sample(struct mc13783_ts_priv *priv) +{ + struct input_dev *idev = priv->idev; + int x0, x1, x2, y0, y1, y2; + int cr0, cr1; + + /* + * the values are 10-bit wide only, but the two least significant + * bits are for future 12 bit use and reading yields 0 + */ + x0 = priv->sample[0] & 0xfff; + x1 = priv->sample[1] & 0xfff; + x2 = priv->sample[2] & 0xfff; + y0 = priv->sample[3] & 0xfff; + y1 = (priv->sample[0] >> 12) & 0xfff; + y2 = (priv->sample[1] >> 12) & 0xfff; + cr0 = (priv->sample[2] >> 12) & 0xfff; + cr1 = (priv->sample[3] >> 12) & 0xfff; + + dev_dbg(&idev->dev, + "x: (% 4d,% 4d,% 4d) y: (% 4d, % 4d,% 4d) cr: (% 4d, % 4d)\n", + x0, x1, x2, y0, y1, y2, cr0, cr1); + + sort3(x0, x1, x2); + sort3(y0, y1, y2); + + cr0 = (cr0 + cr1) / 2; + + if (!cr0 || !sample_tolerance || + (x2 - x0 < sample_tolerance && + y2 - y0 < sample_tolerance)) { + /* report the median coordinate and average pressure */ + if (cr0) { + input_report_abs(idev, ABS_X, x1); + input_report_abs(idev, ABS_Y, y1); + + dev_dbg(&idev->dev, "report (%d, %d, %d)\n", + x1, y1, 0x1000 - cr0); + queue_delayed_work(priv->workq, &priv->work, HZ / 50); + } else + dev_dbg(&idev->dev, "report release\n"); + + input_report_abs(idev, ABS_PRESSURE, + cr0 ? 0x1000 - cr0 : cr0); + input_report_key(idev, BTN_TOUCH, cr0); + input_sync(idev); + } else + dev_dbg(&idev->dev, "discard event\n"); +} + +static void mc13783_ts_work(struct work_struct *work) +{ + struct mc13783_ts_priv *priv = + container_of(work, struct mc13783_ts_priv, work.work); + unsigned int mode = MC13783_ADC_MODE_TS; + unsigned int channel = 12; + + if (mc13783_adc_do_conversion(priv->mc13783, + mode, channel, priv->sample) == 0) + mc13783_ts_report_sample(priv); +} + +static int mc13783_ts_open(struct input_dev *dev) +{ + struct mc13783_ts_priv *priv = input_get_drvdata(dev); + int ret; + + mc13783_lock(priv->mc13783); + + mc13783_ackirq(priv->mc13783, MC13783_IRQ_TS); + + ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_TS, + mc13783_ts_handler, MC13783_TS_NAME, priv); + if (ret) + goto out; + + ret = mc13783_reg_rmw(priv->mc13783, MC13783_ADC0, + MC13783_ADC0_TSMOD_MASK, MC13783_ADC0_TSMOD0); + if (ret) + mc13783_irq_free(priv->mc13783, MC13783_IRQ_TS, priv); +out: + mc13783_unlock(priv->mc13783); + return ret; +} + +static void mc13783_ts_close(struct input_dev *dev) +{ + struct mc13783_ts_priv *priv = input_get_drvdata(dev); + + mc13783_lock(priv->mc13783); + mc13783_reg_rmw(priv->mc13783, MC13783_ADC0, + MC13783_ADC0_TSMOD_MASK, 0); + mc13783_irq_free(priv->mc13783, MC13783_IRQ_TS, priv); + mc13783_unlock(priv->mc13783); + + cancel_delayed_work_sync(&priv->work); +} + +static int __init mc13783_ts_probe(struct platform_device *pdev) +{ + struct mc13783_ts_priv *priv; + struct input_dev *idev; + int ret = -ENOMEM; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + idev = input_allocate_device(); + if (!priv || !idev) + goto err_free_mem; + + INIT_DELAYED_WORK(&priv->work, mc13783_ts_work); + priv->mc13783 = dev_get_drvdata(pdev->dev.parent); + priv->idev = idev; + + /* + * We need separate workqueue because mc13783_adc_do_conversion + * uses keventd and thus would deadlock. + */ + priv->workq = create_singlethread_workqueue("mc13783_ts"); + if (!priv->workq) + goto err_free_mem; + + idev->name = MC13783_TS_NAME; + idev->dev.parent = &pdev->dev; + + idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_abs_params(idev, ABS_X, 0, 0xfff, 0, 0); + input_set_abs_params(idev, ABS_Y, 0, 0xfff, 0, 0); + input_set_abs_params(idev, ABS_PRESSURE, 0, 0xfff, 0, 0); + + idev->open = mc13783_ts_open; + idev->close = mc13783_ts_close; + + input_set_drvdata(idev, priv); + + ret = input_register_device(priv->idev); + if (ret) { + dev_err(&pdev->dev, + "register input device failed with %d\n", ret); + goto err_destroy_wq; + } + + platform_set_drvdata(pdev, priv); + return 0; + +err_destroy_wq: + destroy_workqueue(priv->workq); +err_free_mem: + input_free_device(idev); + kfree(priv); + return ret; +} + +static int __devexit mc13783_ts_remove(struct platform_device *pdev) +{ + struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + destroy_workqueue(priv->workq); + input_unregister_device(priv->idev); + kfree(priv); + + return 0; +} + +static struct platform_driver mc13783_ts_driver = { + .remove = __devexit_p(mc13783_ts_remove), + .driver = { + .owner = THIS_MODULE, + .name = MC13783_TS_NAME, + }, +}; + +static int __init mc13783_ts_init(void) +{ + return platform_driver_probe(&mc13783_ts_driver, &mc13783_ts_probe); +} +module_init(mc13783_ts_init); + +static void __exit mc13783_ts_exit(void) +{ + platform_driver_unregister(&mc13783_ts_driver); +} +module_exit(mc13783_ts_exit); + +MODULE_DESCRIPTION("MC13783 input touchscreen driver"); +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" MC13783_TS_NAME); diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index 67fcd33595de..b79097e3028a 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -233,7 +233,7 @@ static int pcap_ts_resume(struct device *dev) return 0; } -static struct dev_pm_ops pcap_ts_pm_ops = { +static const struct dev_pm_ops pcap_ts_pm_ops = { .suspend = pcap_ts_suspend, .resume = pcap_ts_resume, }; diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c new file mode 100644 index 000000000000..6386b441ef85 --- /dev/null +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -0,0 +1,457 @@ +/* + * Samsung S3C24XX touchscreen driver + * + * This program is free software; you can redistribute it and/or modify + * it under the term of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright 2004 Arnaud Patard <arnaud.patard@rtp-net.org> + * Copyright 2008 Ben Dooks <ben-linux@fluff.org> + * Copyright 2009 Simtec Electronics <linux@simtec.co.uk> + * + * Additional work by Herbert Pƶtzl <herbert@13thfloor.at> and + * Harald Welte <laforge@openmoko.org> + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/adc.h> +#include <plat/regs-adc.h> + +#include <mach/regs-gpio.h> +#include <mach/ts.h> + +#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0)) + +#define INT_DOWN (0) +#define INT_UP (1 << 8) + +#define WAIT4INT (S3C2410_ADCTSC_YM_SEN | \ + S3C2410_ADCTSC_YP_SEN | \ + S3C2410_ADCTSC_XP_SEN | \ + S3C2410_ADCTSC_XY_PST(3)) + +#define AUTOPST (S3C2410_ADCTSC_YM_SEN | \ + S3C2410_ADCTSC_YP_SEN | \ + S3C2410_ADCTSC_XP_SEN | \ + S3C2410_ADCTSC_AUTO_PST | \ + S3C2410_ADCTSC_XY_PST(0)) + +/* Per-touchscreen data. */ + +/** + * struct s3c2410ts - driver touchscreen state. + * @client: The ADC client we registered with the core driver. + * @dev: The device we are bound to. + * @input: The input device we registered with the input subsystem. + * @clock: The clock for the adc. + * @io: Pointer to the IO base. + * @xp: The accumulated X position data. + * @yp: The accumulated Y position data. + * @irq_tc: The interrupt number for pen up/down interrupt + * @count: The number of samples collected. + * @shift: The log2 of the maximum count to read in one go. + */ +struct s3c2410ts { + struct s3c_adc_client *client; + struct device *dev; + struct input_dev *input; + struct clk *clock; + void __iomem *io; + unsigned long xp; + unsigned long yp; + int irq_tc; + int count; + int shift; +}; + +static struct s3c2410ts ts; + +/** + * s3c2410_ts_connect - configure gpio for s3c2410 systems + * + * Configure the GPIO for the S3C2410 system, where we have external FETs + * connected to the device (later systems such as the S3C2440 integrate + * these into the device). +*/ +static inline void s3c2410_ts_connect(void) +{ + s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON); + s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON); + s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON); + s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON); +} + +/** + * get_down - return the down state of the pen + * @data0: The data read from ADCDAT0 register. + * @data1: The data read from ADCDAT1 register. + * + * Return non-zero if both readings show that the pen is down. + */ +static inline bool get_down(unsigned long data0, unsigned long data1) +{ + /* returns true if both data values show stylus down */ + return (!(data0 & S3C2410_ADCDAT0_UPDOWN) && + !(data1 & S3C2410_ADCDAT0_UPDOWN)); +} + +static void touch_timer_fire(unsigned long data) +{ + unsigned long data0; + unsigned long data1; + bool down; + + data0 = readl(ts.io + S3C2410_ADCDAT0); + data1 = readl(ts.io + S3C2410_ADCDAT1); + + down = get_down(data0, data1); + + if (ts.count == (1 << ts.shift)) { + ts.xp >>= ts.shift; + ts.yp >>= ts.shift; + + dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n", + __func__, ts.xp, ts.yp, ts.count); + + input_report_abs(ts.input, ABS_X, ts.xp); + input_report_abs(ts.input, ABS_Y, ts.yp); + + input_report_key(ts.input, BTN_TOUCH, 1); + input_sync(ts.input); + + ts.xp = 0; + ts.yp = 0; + ts.count = 0; + } + + if (down) { + s3c_adc_start(ts.client, 0, 1 << ts.shift); + } else { + ts.count = 0; + + input_report_key(ts.input, BTN_TOUCH, 0); + input_sync(ts.input); + + writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); + } +} + +static DEFINE_TIMER(touch_timer, touch_timer_fire, 0, 0); + +/** + * stylus_irq - touchscreen stylus event interrupt + * @irq: The interrupt number + * @dev_id: The device ID. + * + * Called when the IRQ_TC is fired for a pen up or down event. + */ +static irqreturn_t stylus_irq(int irq, void *dev_id) +{ + unsigned long data0; + unsigned long data1; + bool down; + + data0 = readl(ts.io + S3C2410_ADCDAT0); + data1 = readl(ts.io + S3C2410_ADCDAT1); + + down = get_down(data0, data1); + + /* TODO we should never get an interrupt with down set while + * the timer is running, but maybe we ought to verify that the + * timer isn't running anyways. */ + + if (down) + s3c_adc_start(ts.client, 0, 1 << ts.shift); + else + dev_info(ts.dev, "%s: count=%d\n", __func__, ts.count); + + return IRQ_HANDLED; +} + +/** + * s3c24xx_ts_conversion - ADC conversion callback + * @client: The client that was registered with the ADC core. + * @data0: The reading from ADCDAT0. + * @data1: The reading from ADCDAT1. + * @left: The number of samples left. + * + * Called when a conversion has finished. + */ +static void s3c24xx_ts_conversion(struct s3c_adc_client *client, + unsigned data0, unsigned data1, + unsigned *left) +{ + dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1); + + ts.xp += data0; + ts.yp += data1; + + ts.count++; + + /* From tests, it seems that it is unlikely to get a pen-up + * event during the conversion process which means we can + * ignore any pen-up events with less than the requisite + * count done. + * + * In several thousand conversions, no pen-ups where detected + * before count completed. + */ +} + +/** + * s3c24xx_ts_select - ADC selection callback. + * @client: The client that was registered with the ADC core. + * @select: The reason for select. + * + * Called when the ADC core selects (or deslects) us as a client. + */ +static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select) +{ + if (select) { + writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, + ts.io + S3C2410_ADCTSC); + } else { + mod_timer(&touch_timer, jiffies+1); + writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC); + } +} + +/** + * s3c2410ts_probe - device core probe entry point + * @pdev: The device we are being bound to. + * + * Initialise, find and allocate any resources we need to run and then + * register with the ADC and input systems. + */ +static int __devinit s3c2410ts_probe(struct platform_device *pdev) +{ + struct s3c2410_ts_mach_info *info; + struct device *dev = &pdev->dev; + struct input_dev *input_dev; + struct resource *res; + int ret = -EINVAL; + + /* Initialise input stuff */ + memset(&ts, 0, sizeof(struct s3c2410ts)); + + ts.dev = dev; + + info = pdev->dev.platform_data; + if (!info) { + dev_err(dev, "no platform data, cannot attach\n"); + return -EINVAL; + } + + dev_dbg(dev, "initialising touchscreen\n"); + + ts.clock = clk_get(dev, "adc"); + if (IS_ERR(ts.clock)) { + dev_err(dev, "cannot get adc clock source\n"); + return -ENOENT; + } + + clk_enable(ts.clock); + dev_dbg(dev, "got and enabled clocks\n"); + + ts.irq_tc = ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "no resource for interrupt\n"); + goto err_clk; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no resource for registers\n"); + ret = -ENOENT; + goto err_clk; + } + + ts.io = ioremap(res->start, resource_size(res)); + if (ts.io == NULL) { + dev_err(dev, "cannot map registers\n"); + ret = -ENOMEM; + goto err_clk; + } + + /* Configure the touchscreen external FETs on the S3C2410 */ + if (!platform_get_device_id(pdev)->driver_data) + s3c2410_ts_connect(); + + ts.client = s3c_adc_register(pdev, s3c24xx_ts_select, + s3c24xx_ts_conversion, 1); + if (IS_ERR(ts.client)) { + dev_err(dev, "failed to register adc client\n"); + ret = PTR_ERR(ts.client); + goto err_iomap; + } + + /* Initialise registers */ + if ((info->delay & 0xffff) > 0) + writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); + + writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(dev, "Unable to allocate the input device !!\n"); + ret = -ENOMEM; + goto err_iomap; + } + + ts.input = input_dev; + ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0); + input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0); + + ts.input->name = "S3C24XX TouchScreen"; + ts.input->id.bustype = BUS_HOST; + ts.input->id.vendor = 0xDEAD; + ts.input->id.product = 0xBEEF; + ts.input->id.version = 0x0102; + + ts.shift = info->oversampling_shift; + + ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED, + "s3c2410_ts_pen", ts.input); + if (ret) { + dev_err(dev, "cannot get TC interrupt\n"); + goto err_inputdev; + } + + dev_info(dev, "driver attached, registering input device\n"); + + /* All went ok, so register to the input system */ + ret = input_register_device(ts.input); + if (ret < 0) { + dev_err(dev, "failed to register input device\n"); + ret = -EIO; + goto err_tcirq; + } + + return 0; + + err_tcirq: + free_irq(ts.irq_tc, ts.input); + err_inputdev: + input_unregister_device(ts.input); + err_iomap: + iounmap(ts.io); + err_clk: + del_timer_sync(&touch_timer); + clk_put(ts.clock); + return ret; +} + +/** + * s3c2410ts_remove - device core removal entry point + * @pdev: The device we are being removed from. + * + * Free up our state ready to be removed. + */ +static int __devexit s3c2410ts_remove(struct platform_device *pdev) +{ + free_irq(ts.irq_tc, ts.input); + del_timer_sync(&touch_timer); + + clk_disable(ts.clock); + clk_put(ts.clock); + + input_unregister_device(ts.input); + iounmap(ts.io); + + return 0; +} + +#ifdef CONFIG_PM +static int s3c2410ts_suspend(struct device *dev) +{ + writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC); + disable_irq(ts.irq_tc); + clk_disable(ts.clock); + + return 0; +} + +static int s3c2410ts_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s3c2410_ts_mach_info *info = pdev->dev.platform_data; + + clk_enable(ts.clock); + + /* Initialise registers */ + if ((info->delay & 0xffff) > 0) + writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); + + writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); + + return 0; +} + +static struct dev_pm_ops s3c_ts_pmops = { + .suspend = s3c2410ts_suspend, + .resume = s3c2410ts_resume, +}; +#endif + +static struct platform_device_id s3cts_driver_ids[] = { + { "s3c2410-ts", 0 }, + { "s3c2440-ts", 1 }, + { } +}; +MODULE_DEVICE_TABLE(platform, s3cts_driver_ids); + +static struct platform_driver s3c_ts_driver = { + .driver = { + .name = "s3c24xx-ts", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &s3c_ts_pmops, +#endif + }, + .id_table = s3cts_driver_ids, + .probe = s3c2410ts_probe, + .remove = __devexit_p(s3c2410ts_remove), +}; + +static int __init s3c2410ts_init(void) +{ + return platform_driver_register(&s3c_ts_driver); +} + +static void __exit s3c2410ts_exit(void) +{ + platform_driver_unregister(&s3c_ts_driver); +} + +module_init(s3c2410ts_init); +module_exit(s3c2410ts_exit); + +MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, " + "Ben Dooks <ben@simtec.co.uk>, " + "Simtec Electronics <linux@simtec.co.uk>"); +MODULE_DESCRIPTION("S3C24XX Touchscreen driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 095f84b1f56e..89dcbe7b4b02 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -355,10 +355,13 @@ static int ucb1400_ts_probe(struct platform_device *dev) goto err; } - error = ucb1400_ts_detect_irq(ucb); - if (error) { - printk(KERN_ERR "UCB1400: IRQ probe failed\n"); - goto err_free_devs; + /* Only in case the IRQ line wasn't supplied, try detecting it */ + if (ucb->irq < 0) { + error = ucb1400_ts_detect_irq(ucb); + if (error) { + printk(KERN_ERR "UCB1400: IRQ probe failed\n"); + goto err_free_devs; + } } init_waitqueue_head(&ucb->ts_wait); diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 68ece5801a58..09a5e7341bd5 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -14,6 +14,7 @@ * - General Touch * - GoTop Super_Q2/GogoPen/PenPower tablets * - JASTEC USB touch controller/DigiTech DTR-02U + * - Zytronic capacitive touchscreen * * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch> * Copyright (C) by Todd E. Johnson (mtouchusb.c) @@ -73,6 +74,15 @@ struct usbtouch_device_info { int min_press, max_press; int rept_size; + /* + * Always service the USB devices irq not just when the input device is + * open. This is useful when devices have a watchdog which prevents us + * from periodically polling the device. Leave this unset unless your + * touchscreen device requires it, as it does consume more of the USB + * bandwidth. + */ + bool irq_always; + void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len); /* @@ -121,6 +131,8 @@ enum { DEVTYPE_GOTOP, DEVTYPE_JASTEC, DEVTYPE_E2I, + DEVTYPE_ZYTRONIC, + DEVTYPE_TC5UH, }; #define USB_DEVICE_HID_CLASS(vend, prod) \ @@ -201,6 +213,15 @@ static struct usb_device_id usbtouch_devices[] = { #ifdef CONFIG_TOUCHSCREEN_USB_E2I {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I}, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC + {USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC}, +#endif + +#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH + {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH}, +#endif + {} }; @@ -538,6 +559,19 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) } #endif +/***************************************************************************** + * ET&T TC5UH part + */ +#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH +static int tc5uh_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1]; + dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3]; + dev->touch = pkt[0] & 0x01; + + return 1; +} +#endif /***************************************************************************** * IdealTEK URTC1000 Part @@ -621,6 +655,39 @@ static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt) } #endif +/***************************************************************************** + * Zytronic Part + */ +#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC +static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + switch (pkt[0]) { + case 0x3A: /* command response */ + dbg("%s: Command response %d", __func__, pkt[1]); + break; + + case 0xC0: /* down */ + dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7); + dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7); + dev->touch = 1; + dbg("%s: down %d,%d", __func__, dev->x, dev->y); + return 1; + + case 0x80: /* up */ + dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7); + dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7); + dev->touch = 0; + dbg("%s: up %d,%d", __func__, dev->x, dev->y); + return 1; + + default: + dbg("%s: Unknown return %d", __func__, pkt[0]); + break; + } + + return 0; +} +#endif /***************************************************************************** * the different device descriptors @@ -783,6 +850,29 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .read_data = e2i_read_data, }, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC + [DEVTYPE_ZYTRONIC] = { + .min_xc = 0x0, + .max_xc = 0x03ff, + .min_yc = 0x0, + .max_yc = 0x03ff, + .rept_size = 5, + .read_data = zytronic_read_data, + .irq_always = true, + }, +#endif + +#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH + [DEVTYPE_TC5UH] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .rept_size = 5, + .read_data = tc5uh_read_data, + }, +#endif }; @@ -933,8 +1023,10 @@ static int usbtouch_open(struct input_dev *input) usbtouch->irq->dev = usbtouch->udev; - if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) - return -EIO; + if (!usbtouch->type->irq_always) { + if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) + return -EIO; + } return 0; } @@ -943,7 +1035,8 @@ static void usbtouch_close(struct input_dev *input) { struct usbtouch_usb *usbtouch = input_get_drvdata(input); - usb_kill_urb(usbtouch->irq); + if (!usbtouch->type->irq_always) + usb_kill_urb(usbtouch->irq); } @@ -1066,6 +1159,9 @@ static int usbtouch_probe(struct usb_interface *intf, usb_set_intfdata(intf, usbtouch); + if (usbtouch->type->irq_always) + usb_submit_urb(usbtouch->irq, GFP_KERNEL); + return 0; out_free_buffers: @@ -1087,7 +1183,7 @@ static void usbtouch_disconnect(struct usb_interface *intf) dbg("%s - usbtouch is initialized, cleaning up", __func__); usb_set_intfdata(intf, NULL); - usb_kill_urb(usbtouch->irq); + /* this will stop IO via close */ input_unregister_device(usbtouch->input); usb_free_urb(usbtouch->irq); usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c index 41e4359c277c..eca54dbdf493 100644 --- a/drivers/input/touchscreen/zylonite-wm97xx.c +++ b/drivers/input/touchscreen/zylonite-wm97xx.c @@ -96,7 +96,7 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm) /* When the AC97 queue has been drained we need to allow time * to buffer up samples otherwise we end up spinning polling * for samples. The controller can't have a suitably low - * threashold set to use the notifications it gives. + * threshold set to use the notifications it gives. */ msleep(1); diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index b115726dc088..c721c0a23eb8 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -21,7 +21,10 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/input.h> + #include <asm/xen/hypervisor.h> + +#include <xen/xen.h> #include <xen/events.h> #include <xen/page.h> #include <xen/interface/io/fbif.h> |