diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-01-31 21:16:22 -0800 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-01-31 21:16:22 -0800 |
commit | a1f3d4bba8ea395a39d34ade6017afee8be16031 (patch) | |
tree | 874d843d35622f17aa6c3e048e42cf0d679bcb75 /drivers/input | |
parent | 723d928417bffff6467da155d8ebbbe016464012 (diff) | |
parent | ebf53826e105f488f4f628703a108e98940d1dc5 (diff) | |
download | linux-a1f3d4bba8ea395a39d34ade6017afee8be16031.tar.gz linux-a1f3d4bba8ea395a39d34ade6017afee8be16031.tar.bz2 linux-a1f3d4bba8ea395a39d34ade6017afee8be16031.zip |
Merge commit 'v2.6.38-rc3' into next
Diffstat (limited to 'drivers/input')
33 files changed, 1806 insertions, 1781 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 07c2cd43109c..1903c0f5b925 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -6,7 +6,7 @@ menu "Input device support" depends on !S390 config INPUT - tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED + tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT default y help Say Y here if you have any input device (mouse, keyboard, tablet, @@ -67,7 +67,7 @@ config INPUT_SPARSEKMAP comment "Userland interfaces" config INPUT_MOUSEDEV - tristate "Mouse interface" if EMBEDDED + tristate "Mouse interface" if EXPERT default y help Say Y here if you want your mouse to be accessible as char devices @@ -150,7 +150,7 @@ config INPUT_EVBUG module will be called evbug. config INPUT_APMPOWER - tristate "Input Power Event -> APM Bridge" if EMBEDDED + tristate "Input Power Event -> APM Bridge" if EXPERT depends on INPUT && APM_EMULATION help Say Y here if you want suspend key events to trigger a user diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index f8635b7b4295..c8471a2552e7 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -535,76 +535,73 @@ static int handle_eviocgbit(struct input_dev *dev, } #undef OLD_KEY_MAX -static int evdev_handle_get_keycode(struct input_dev *dev, - void __user *p, size_t size) +static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p) { - struct input_keymap_entry ke; + struct input_keymap_entry ke = { + .len = sizeof(unsigned int), + .flags = 0, + }; + int __user *ip = (int __user *)p; int error; - memset(&ke, 0, sizeof(ke)); - - if (size == sizeof(unsigned int[2])) { - /* legacy case */ - int __user *ip = (int __user *)p; + /* legacy case */ + if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) + return -EFAULT; - if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) - return -EFAULT; + error = input_get_keycode(dev, &ke); + if (error) + return error; - ke.len = sizeof(unsigned int); - ke.flags = 0; + if (put_user(ke.keycode, ip + 1)) + return -EFAULT; - error = input_get_keycode(dev, &ke); - if (error) - return error; + return 0; +} - if (put_user(ke.keycode, ip + 1)) - return -EFAULT; +static int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p) +{ + struct input_keymap_entry ke; + int error; - } else { - size = min(size, sizeof(ke)); + if (copy_from_user(&ke, p, sizeof(ke))) + return -EFAULT; - if (copy_from_user(&ke, p, size)) - return -EFAULT; + error = input_get_keycode(dev, &ke); + if (error) + return error; - error = input_get_keycode(dev, &ke); - if (error) - return error; + if (copy_to_user(p, &ke, sizeof(ke))) + return -EFAULT; - if (copy_to_user(p, &ke, size)) - return -EFAULT; - } return 0; } -static int evdev_handle_set_keycode(struct input_dev *dev, - void __user *p, size_t size) +static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p) { - struct input_keymap_entry ke; - - memset(&ke, 0, sizeof(ke)); + struct input_keymap_entry ke = { + .len = sizeof(unsigned int), + .flags = 0, + }; + int __user *ip = (int __user *)p; - if (size == sizeof(unsigned int[2])) { - /* legacy case */ - int __user *ip = (int __user *)p; + if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) + return -EFAULT; - if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) - return -EFAULT; + if (get_user(ke.keycode, ip + 1)) + return -EFAULT; - if (get_user(ke.keycode, ip + 1)) - return -EFAULT; + return input_set_keycode(dev, &ke); +} - ke.len = sizeof(unsigned int); - ke.flags = 0; +static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p) +{ + struct input_keymap_entry ke; - } else { - size = min(size, sizeof(ke)); + if (copy_from_user(&ke, p, sizeof(ke))) + return -EFAULT; - if (copy_from_user(&ke, p, size)) - return -EFAULT; - - if (ke.len > sizeof(ke.scancode)) - return -EINVAL; - } + if (ke.len > sizeof(ke.scancode)) + return -EINVAL; return input_set_keycode(dev, &ke); } @@ -670,6 +667,18 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, return evdev_grab(evdev, client); else return evdev_ungrab(evdev, client); + + case EVIOCGKEYCODE: + return evdev_handle_get_keycode(dev, p); + + case EVIOCSKEYCODE: + return evdev_handle_set_keycode(dev, p); + + case EVIOCGKEYCODE_V2: + return evdev_handle_get_keycode_v2(dev, p); + + case EVIOCSKEYCODE_V2: + return evdev_handle_set_keycode_v2(dev, p); } size = _IOC_SIZE(cmd); @@ -713,12 +722,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, return -EFAULT; return error; - - case EVIOC_MASK_SIZE(EVIOCGKEYCODE): - return evdev_handle_get_keycode(dev, p, size); - - case EVIOC_MASK_SIZE(EVIOCSKEYCODE): - return evdev_handle_set_keycode(dev, p, size); } /* Multi-number variable-length handlers */ diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index dbf741c95835..23cf8fc933ec 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -121,7 +121,7 @@ static int gameport_measure_speed(struct gameport *gameport) } gameport_close(gameport); - return (cpu_data(raw_smp_processor_id()).loops_per_jiffy * + return (this_cpu_read(cpu_info.loops_per_jiffy) * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx); #else diff --git a/drivers/input/input.c b/drivers/input/input.c index 9408dba2cd31..7985114beac7 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -26,7 +26,6 @@ #include <linux/device.h> #include <linux/mutex.h> #include <linux/rcupdate.h> -#include <linux/smp_lock.h> #include "input-compat.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); @@ -755,7 +754,7 @@ static int input_default_setkeycode(struct input_dev *dev, if (index >= dev->keycodemax) return -EINVAL; - if (dev->keycodesize < sizeof(dev->keycode) && + if (dev->keycodesize < sizeof(ke->keycode) && (ke->keycode >> (dev->keycodesize * 8))) return -EINVAL; diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index d53b9e900234..27b6a3ce18ca 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -245,6 +245,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) goto err_free_tgfx; } + parport_put_port(pp); return tgfx; err_free_dev: diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 05ab6f41ee1e..c7a92028f450 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -2,7 +2,7 @@ # Input core configuration # menuconfig INPUT_KEYBOARD - bool "Keyboards" if EMBEDDED || !X86 + bool "Keyboards" if EXPERT || !X86 default y help Say Y here, and a list of supported keyboards will be displayed. @@ -57,7 +57,7 @@ config KEYBOARD_ATARI module will be called atakbd. config KEYBOARD_ATKBD - tristate "AT keyboard" if EMBEDDED || !X86 + tristate "AT keyboard" if EXPERT || !X86 default y select SERIO select SERIO_LIBPS2 @@ -167,6 +167,22 @@ config KEYBOARD_GPIO To compile this driver as a module, choose M here: the module will be called gpio_keys. +config KEYBOARD_GPIO_POLLED + tristate "Polled GPIO buttons" + depends on GENERIC_GPIO + select INPUT_POLLDEV + help + This driver implements support for buttons connected + to GPIO pins that are not capable of generating interrupts. + + Say Y here if your device has buttons connected + directly to such GPIO pins. Your board-specific + setup logic must also provide a platform device, + with configuration data saying which GPIOs are used. + + To compile this driver as a module, choose M here: the + module will be called gpio_keys_polled. + config KEYBOARD_TCA6416 tristate "TCA6416/TCA6408A Keypad Support" depends on I2C @@ -327,6 +343,16 @@ config KEYBOARD_NOMADIK To compile this driver as a module, choose M here: the module will be called nmk-ske-keypad. +config KEYBOARD_TEGRA + tristate "NVIDIA Tegra internal matrix keyboard controller support" + depends on ARCH_TEGRA + help + Say Y here if you want to use a matrix keyboard connected directly + to the internal keyboard controller on Tegra SoCs. + + To compile this driver as a module, choose M here: the + module will be called tegra-kbc. + config KEYBOARD_OPENCORES tristate "OpenCores Keyboard Controller" help @@ -442,6 +468,16 @@ config KEYBOARD_SPEAR To compile this driver as a module, choose M here: the module will be called spear-keboard. +config KEYBOARD_TC3589X + tristate "TC3589X Keypad support" + depends on MFD_TC3589X + help + Say Y here if you want to use the keypad controller on + TC35892/3 I/O expander. + + To compile this driver as a module, choose M here: the + module will be called tc3589x-keypad. + config KEYBOARD_TNETV107X tristate "TI TNETV107X keypad support" depends on ARCH_DAVINCI_TNETV107X diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index ee14f85a716f..468c627a2844 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.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_GPIO_POLLED) += gpio_keys_polled.o obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o @@ -40,6 +41,8 @@ obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o +obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o +obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6069abe31e42..eb3006361ee4 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -322,7 +322,7 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata) struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; - int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; + int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low; input_event(input, type, button->code, !!state); input_sync(input); @@ -410,8 +410,8 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev, if (!button->can_disable) irqflags |= IRQF_SHARED; - error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata); - if (error) { + error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata); + if (error < 0) { dev_err(dev, "Unable to claim irq %d; error %d\n", irq, error); goto fail3; diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c new file mode 100644 index 000000000000..4c17aff20657 --- /dev/null +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -0,0 +1,261 @@ +/* + * Driver for buttons on GPIO lines not capable of generating interrupts + * + * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com> + * + * This file was based on: /drivers/input/misc/cobalt_btns.c + * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * + * also was based on: /drivers/input/keyboard/gpio_keys.c + * Copyright 2005 Phil Blundell + * + * 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/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> + +#define DRV_NAME "gpio-keys-polled" + +struct gpio_keys_button_data { + int last_state; + int count; + int threshold; + int can_sleep; +}; + +struct gpio_keys_polled_dev { + struct input_polled_dev *poll_dev; + struct device *dev; + struct gpio_keys_platform_data *pdata; + struct gpio_keys_button_data data[0]; +}; + +static void gpio_keys_polled_check_state(struct input_dev *input, + struct gpio_keys_button *button, + struct gpio_keys_button_data *bdata) +{ + int state; + + if (bdata->can_sleep) + state = !!gpio_get_value_cansleep(button->gpio); + else + state = !!gpio_get_value(button->gpio); + + if (state != bdata->last_state) { + unsigned int type = button->type ?: EV_KEY; + + input_event(input, type, button->code, + !!(state ^ button->active_low)); + input_sync(input); + bdata->count = 0; + bdata->last_state = state; + } +} + +static void gpio_keys_polled_poll(struct input_polled_dev *dev) +{ + struct gpio_keys_polled_dev *bdev = dev->private; + struct gpio_keys_platform_data *pdata = bdev->pdata; + struct input_dev *input = dev->input; + int i; + + for (i = 0; i < bdev->pdata->nbuttons; i++) { + struct gpio_keys_button_data *bdata = &bdev->data[i]; + + if (bdata->count < bdata->threshold) + bdata->count++; + else + gpio_keys_polled_check_state(input, &pdata->buttons[i], + bdata); + } +} + +static void gpio_keys_polled_open(struct input_polled_dev *dev) +{ + struct gpio_keys_polled_dev *bdev = dev->private; + struct gpio_keys_platform_data *pdata = bdev->pdata; + + if (pdata->enable) + pdata->enable(bdev->dev); +} + +static void gpio_keys_polled_close(struct input_polled_dev *dev) +{ + struct gpio_keys_polled_dev *bdev = dev->private; + struct gpio_keys_platform_data *pdata = bdev->pdata; + + if (pdata->disable) + pdata->disable(bdev->dev); +} + +static int __devinit gpio_keys_polled_probe(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct gpio_keys_polled_dev *bdev; + struct input_polled_dev *poll_dev; + struct input_dev *input; + int error; + int i; + + if (!pdata || !pdata->poll_interval) + return -EINVAL; + + bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) + + pdata->nbuttons * sizeof(struct gpio_keys_button_data), + GFP_KERNEL); + if (!bdev) { + dev_err(dev, "no memory for private data\n"); + return -ENOMEM; + } + + poll_dev = input_allocate_polled_device(); + if (!poll_dev) { + dev_err(dev, "no memory for polled device\n"); + error = -ENOMEM; + goto err_free_bdev; + } + + poll_dev->private = bdev; + poll_dev->poll = gpio_keys_polled_poll; + poll_dev->poll_interval = pdata->poll_interval; + poll_dev->open = gpio_keys_polled_open; + poll_dev->close = gpio_keys_polled_close; + + input = poll_dev->input; + + input->evbit[0] = BIT(EV_KEY); + input->name = pdev->name; + input->phys = DRV_NAME"/input0"; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + struct gpio_keys_button_data *bdata = &bdev->data[i]; + unsigned int gpio = button->gpio; + unsigned int type = button->type ?: EV_KEY; + + if (button->wakeup) { + dev_err(dev, DRV_NAME " does not support wakeup\n"); + error = -EINVAL; + goto err_free_gpio; + } + + error = gpio_request(gpio, + button->desc ? button->desc : DRV_NAME); + if (error) { + dev_err(dev, "unable to claim gpio %u, err=%d\n", + gpio, error); + goto err_free_gpio; + } + + error = gpio_direction_input(gpio); + if (error) { + dev_err(dev, + "unable to set direction on gpio %u, err=%d\n", + gpio, error); + goto err_free_gpio; + } + + bdata->can_sleep = gpio_cansleep(gpio); + bdata->last_state = -1; + bdata->threshold = DIV_ROUND_UP(button->debounce_interval, + pdata->poll_interval); + + input_set_capability(input, type, button->code); + } + + bdev->poll_dev = poll_dev; + bdev->dev = dev; + bdev->pdata = pdata; + platform_set_drvdata(pdev, bdev); + + error = input_register_polled_device(poll_dev); + if (error) { + dev_err(dev, "unable to register polled device, err=%d\n", + error); + goto err_free_gpio; + } + + /* report initial state of the buttons */ + for (i = 0; i < pdata->nbuttons; i++) + gpio_keys_polled_check_state(input, &pdata->buttons[i], + &bdev->data[i]); + + return 0; + +err_free_gpio: + while (--i >= 0) + gpio_free(pdata->buttons[i].gpio); + + input_free_polled_device(poll_dev); + +err_free_bdev: + kfree(bdev); + + platform_set_drvdata(pdev, NULL); + return error; +} + +static int __devexit gpio_keys_polled_remove(struct platform_device *pdev) +{ + struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev); + struct gpio_keys_platform_data *pdata = bdev->pdata; + int i; + + input_unregister_polled_device(bdev->poll_dev); + + for (i = 0; i < pdata->nbuttons; i++) + gpio_free(pdata->buttons[i].gpio); + + input_free_polled_device(bdev->poll_dev); + + kfree(bdev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver gpio_keys_polled_driver = { + .probe = gpio_keys_polled_probe, + .remove = __devexit_p(gpio_keys_polled_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init gpio_keys_polled_init(void) +{ + return platform_driver_register(&gpio_keys_polled_driver); +} + +static void __exit gpio_keys_polled_exit(void) +{ + platform_driver_unregister(&gpio_keys_polled_driver); +} + +module_init(gpio_keys_polled_init); +module_exit(gpio_keys_polled_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_DESCRIPTION("Polled GPIO Buttons driver"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index a72e61ddca91..0e2a19cb43d8 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -65,7 +65,6 @@ struct omap_kp { static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0); -static int *keymap; static unsigned int *row_gpios; static unsigned int *col_gpios; @@ -162,20 +161,11 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state) } } -static inline int omap_kp_find_key(int col, int row) -{ - int i, key; - - key = KEY(col, row, 0); - for (i = 0; keymap[i] != 0; i++) - if ((keymap[i] & 0xff000000) == key) - return keymap[i] & 0x00ffffff; - return -1; -} - static void omap_kp_tasklet(unsigned long data) { struct omap_kp *omap_kp_data = (struct omap_kp *) data; + unsigned short *keycodes = omap_kp_data->input->keycode; + unsigned int row_shift = get_count_order(omap_kp_data->cols); unsigned char new_state[8], changed, key_down = 0; int col, row; int spurious = 0; @@ -199,7 +189,7 @@ static void omap_kp_tasklet(unsigned long data) row, (new_state[col] & (1 << row)) ? "pressed" : "released"); #else - key = omap_kp_find_key(col, row); + key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)]; if (key < 0) { printk(KERN_WARNING "omap-keypad: Spurious key event %d-%d\n", @@ -298,13 +288,18 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) struct input_dev *input_dev; struct omap_kp_platform_data *pdata = pdev->dev.platform_data; int i, col_idx, row_idx, irq_idx, ret; + unsigned int row_shift, keycodemax; - if (!pdata->rows || !pdata->cols || !pdata->keymap) { - printk(KERN_ERR "No rows, cols or keymap from pdata\n"); + if (!pdata->rows || !pdata->cols || !pdata->keymap_data) { + printk(KERN_ERR "No rows, cols or keymap_data from pdata\n"); return -EINVAL; } - omap_kp = kzalloc(sizeof(struct omap_kp), GFP_KERNEL); + row_shift = get_count_order(pdata->cols); + keycodemax = pdata->rows << row_shift; + + omap_kp = kzalloc(sizeof(struct omap_kp) + + keycodemax * sizeof(unsigned short), GFP_KERNEL); input_dev = input_allocate_device(); if (!omap_kp || !input_dev) { kfree(omap_kp); @@ -320,7 +315,9 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) if (!cpu_is_omap24xx()) omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - keymap = pdata->keymap; + input_dev->keycode = &omap_kp[1]; + input_dev->keycodesize = sizeof(unsigned short); + input_dev->keycodemax = keycodemax; if (pdata->rep) __set_bit(EV_REP, input_dev->evbit); @@ -374,8 +371,8 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) /* setup input device */ __set_bit(EV_KEY, input_dev->evbit); - for (i = 0; keymap[i] != 0; i++) - __set_bit(keymap[i] & KEY_MAX, input_dev->keybit); + matrix_keypad_build_keymap(pdata->keymap_data, row_shift, + input_dev->keycode, input_dev->keybit); input_dev->name = "omap-keypad"; input_dev->phys = "omap-keypad/input0"; input_dev->dev.parent = &pdev->dev; @@ -416,7 +413,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) return 0; err5: for (i = irq_idx - 1; i >=0; i--) - free_irq(row_gpios[i], 0); + free_irq(row_gpios[i], NULL); err4: input_unregister_device(omap_kp->input); input_dev = NULL; @@ -447,11 +444,11 @@ static int __devexit omap_kp_remove(struct platform_device *pdev) gpio_free(col_gpios[i]); for (i = 0; i < omap_kp->rows; i++) { gpio_free(row_gpios[i]); - free_irq(gpio_to_irq(row_gpios[i]), 0); + free_irq(gpio_to_irq(row_gpios[i]), NULL); } } else { omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - free_irq(omap_kp->irq, 0); + free_irq(omap_kp->irq, NULL); } del_timer_sync(&omap_kp->timer); diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c new file mode 100644 index 000000000000..dbbe761778d2 --- /dev/null +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -0,0 +1,472 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com> + * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * + * License Terms: GNU General Public License, version 2 + * + * TC35893 MFD Keypad Controller driver + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/platform_device.h> +#include <linux/input/matrix_keypad.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/mfd/tc3589x.h> + +/* Maximum supported keypad matrix row/columns size */ +#define TC3589x_MAX_KPROW 8 +#define TC3589x_MAX_KPCOL 12 + +/* keypad related Constants */ +#define TC3589x_MAX_DEBOUNCE_SETTLE 0xFF +#define DEDICATED_KEY_VAL 0xFF + +/* Pull up/down masks */ +#define TC3589x_NO_PULL_MASK 0x0 +#define TC3589x_PULL_DOWN_MASK 0x1 +#define TC3589x_PULL_UP_MASK 0x2 +#define TC3589x_PULLUP_ALL_MASK 0xAA +#define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2)) + +/* Bit masks for IOCFG register */ +#define IOCFG_BALLCFG 0x01 +#define IOCFG_IG 0x08 + +#define KP_EVCODE_COL_MASK 0x0F +#define KP_EVCODE_ROW_MASK 0x70 +#define KP_RELEASE_EVT_MASK 0x80 + +#define KP_ROW_SHIFT 4 + +#define KP_NO_VALID_KEY_MASK 0x7F + +/* bit masks for RESTCTRL register */ +#define TC3589x_KBDRST 0x2 +#define TC3589x_IRQRST 0x10 +#define TC3589x_RESET_ALL 0x1B + +/* KBDMFS register bit mask */ +#define TC3589x_KBDMFS_EN 0x1 + +/* CLKEN register bitmask */ +#define KPD_CLK_EN 0x1 + +/* RSTINTCLR register bit mask */ +#define IRQ_CLEAR 0x1 + +/* bit masks for keyboard interrupts*/ +#define TC3589x_EVT_LOSS_INT 0x8 +#define TC3589x_EVT_INT 0x4 +#define TC3589x_KBD_LOSS_INT 0x2 +#define TC3589x_KBD_INT 0x1 + +/* bit masks for keyboard interrupt clear*/ +#define TC3589x_EVT_INT_CLR 0x2 +#define TC3589x_KBD_INT_CLR 0x1 + +#define TC3589x_KBD_KEYMAP_SIZE 64 + +/** + * struct tc_keypad - data structure used by keypad driver + * @input: pointer to input device object + * @board: keypad platform device + * @krow: number of rows + * @kcol: number of coloumns + * @keymap: matrix scan code table for keycodes + */ +struct tc_keypad { + struct tc3589x *tc3589x; + struct input_dev *input; + const struct tc3589x_keypad_platform_data *board; + unsigned int krow; + unsigned int kcol; + unsigned short keymap[TC3589x_KBD_KEYMAP_SIZE]; + bool keypad_stopped; +}; + +static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) +{ + int ret; + struct tc3589x *tc3589x = keypad->tc3589x; + u8 settle_time = keypad->board->settle_time; + u8 dbounce_period = keypad->board->debounce_period; + u8 rows = keypad->board->krow & 0xf; /* mask out the nibble */ + u8 column = keypad->board->kcol & 0xf; /* mask out the nibble */ + + /* validate platform configurations */ + if (keypad->board->kcol > TC3589x_MAX_KPCOL || + keypad->board->krow > TC3589x_MAX_KPROW || + keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE || + keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE) + return -EINVAL; + + /* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */ + ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE, + (rows << KP_ROW_SHIFT) | column); + if (ret < 0) + return ret; + + /* configure dedicated key config, no dedicated key selected */ + ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_LSB, DEDICATED_KEY_VAL); + if (ret < 0) + return ret; + + ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_MSB, DEDICATED_KEY_VAL); + if (ret < 0) + return ret; + + /* Configure settle time */ + ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time); + if (ret < 0) + return ret; + + /* Configure debounce time */ + ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period); + if (ret < 0) + return ret; + + /* Start of initialise keypad GPIOs */ + ret = tc3589x_set_bits(tc3589x, TC3589x_IOCFG, 0x0, IOCFG_IG); + if (ret < 0) + return ret; + + /* Configure pull-up resistors for all row GPIOs */ + ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_LSB, + TC3589x_PULLUP_ALL_MASK); + if (ret < 0) + return ret; + + ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_MSB, + TC3589x_PULLUP_ALL_MASK); + if (ret < 0) + return ret; + + /* Configure pull-up resistors for all column GPIOs */ + ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_LSB, + TC3589x_PULLUP_ALL_MASK); + if (ret < 0) + return ret; + + ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_MSB, + TC3589x_PULLUP_ALL_MASK); + if (ret < 0) + return ret; + + ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG2_LSB, + TC3589x_PULLUP_ALL_MASK); + + return ret; +} + +#define TC35893_DATA_REGS 4 +#define TC35893_KEYCODE_FIFO_EMPTY 0x7f +#define TC35893_KEYCODE_FIFO_CLEAR 0xff +#define TC35893_KEYPAD_ROW_SHIFT 0x3 + +static irqreturn_t tc3589x_keypad_irq(int irq, void *dev) +{ + struct tc_keypad *keypad = dev; + struct tc3589x *tc3589x = keypad->tc3589x; + u8 i, row_index, col_index, kbd_code, up; + u8 code; + + for (i = 0; i < TC35893_DATA_REGS * 2; i++) { + kbd_code = tc3589x_reg_read(tc3589x, TC3589x_EVTCODE_FIFO); + + /* loop till fifo is empty and no more keys are pressed */ + if (kbd_code == TC35893_KEYCODE_FIFO_EMPTY || + kbd_code == TC35893_KEYCODE_FIFO_CLEAR) + continue; + + /* valid key is found */ + col_index = kbd_code & KP_EVCODE_COL_MASK; + row_index = (kbd_code & KP_EVCODE_ROW_MASK) >> KP_ROW_SHIFT; + code = MATRIX_SCAN_CODE(row_index, col_index, + TC35893_KEYPAD_ROW_SHIFT); + up = kbd_code & KP_RELEASE_EVT_MASK; + + input_event(keypad->input, EV_MSC, MSC_SCAN, code); + input_report_key(keypad->input, keypad->keymap[code], !up); + input_sync(keypad->input); + } + + /* clear IRQ */ + tc3589x_set_bits(tc3589x, TC3589x_KBDIC, + 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR); + /* enable IRQ */ + tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, + 0x0, TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT); + + return IRQ_HANDLED; +} + +static int tc3589x_keypad_enable(struct tc_keypad *keypad) +{ + struct tc3589x *tc3589x = keypad->tc3589x; + int ret; + + /* pull the keypad module out of reset */ + ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x0); + if (ret < 0) + return ret; + + /* configure KBDMFS */ + ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMFS, 0x0, TC3589x_KBDMFS_EN); + if (ret < 0) + return ret; + + /* enable the keypad clock */ + ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x0, KPD_CLK_EN); + if (ret < 0) + return ret; + + /* clear pending IRQs */ + ret = tc3589x_set_bits(tc3589x, TC3589x_RSTINTCLR, 0x0, 0x1); + if (ret < 0) + return ret; + + /* enable the IRQs */ + ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, 0x0, + TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT); + if (ret < 0) + return ret; + + keypad->keypad_stopped = false; + + return ret; +} + +static int tc3589x_keypad_disable(struct tc_keypad *keypad) +{ + struct tc3589x *tc3589x = keypad->tc3589x; + int ret; + + /* clear IRQ */ + ret = tc3589x_set_bits(tc3589x, TC3589x_KBDIC, + 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR); + if (ret < 0) + return ret; + + /* disable all interrupts */ + ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, + ~(TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT), 0x0); + if (ret < 0) + return ret; + + /* disable the keypad module */ + ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x1, 0x0); + if (ret < 0) + return ret; + + /* put the keypad module into reset */ + ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x1); + + keypad->keypad_stopped = true; + + return ret; +} + +static int tc3589x_keypad_open(struct input_dev *input) +{ + int error; + struct tc_keypad *keypad = input_get_drvdata(input); + + /* enable the keypad module */ + error = tc3589x_keypad_enable(keypad); + if (error < 0) { + dev_err(&input->dev, "failed to enable keypad module\n"); + return error; + } + + error = tc3589x_keypad_init_key_hardware(keypad); + if (error < 0) { + dev_err(&input->dev, "failed to configure keypad module\n"); + return error; + } + + return 0; +} + +static void tc3589x_keypad_close(struct input_dev *input) +{ + struct tc_keypad *keypad = input_get_drvdata(input); + + /* disable the keypad module */ + tc3589x_keypad_disable(keypad); +} + +static int __devinit tc3589x_keypad_probe(struct platform_device *pdev) +{ + struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); + struct tc_keypad *keypad; + struct input_dev *input; + const struct tc3589x_keypad_platform_data *plat; + int error, irq; + + plat = tc3589x->pdata->keypad; + if (!plat) { + dev_err(&pdev->dev, "invalid keypad platform data\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + keypad = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL); + input = input_allocate_device(); + if (!keypad || !input) { + dev_err(&pdev->dev, "failed to allocate keypad memory\n"); + error = -ENOMEM; + goto err_free_mem; + } + + keypad->board = plat; + keypad->input = input; + keypad->tc3589x = tc3589x; + + input->id.bustype = BUS_I2C; + input->name = pdev->name; + input->dev.parent = &pdev->dev; + + input->keycode = keypad->keymap; + input->keycodesize = sizeof(keypad->keymap[0]); + input->keycodemax = ARRAY_SIZE(keypad->keymap); + + input->open = tc3589x_keypad_open; + input->close = tc3589x_keypad_close; + + input_set_drvdata(input, keypad); + + input_set_capability(input, EV_MSC, MSC_SCAN); + + __set_bit(EV_KEY, input->evbit); + if (!plat->no_autorepeat) + __set_bit(EV_REP, input->evbit); + + matrix_keypad_build_keymap(plat->keymap_data, 0x3, + input->keycode, input->keybit); + + error = request_threaded_irq(irq, NULL, + tc3589x_keypad_irq, plat->irqtype, + "tc3589x-keypad", keypad); + if (error < 0) { + dev_err(&pdev->dev, + "Could not allocate irq %d,error %d\n", + irq, error); + goto err_free_mem; + } + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, "Could not register input device\n"); + goto err_free_irq; + } + + /* let platform decide if keypad is a wakeup source or not */ + device_init_wakeup(&pdev->dev, plat->enable_wakeup); + device_set_wakeup_capable(&pdev->dev, plat->enable_wakeup); + + platform_set_drvdata(pdev, keypad); + + return 0; + +err_free_irq: + free_irq(irq, keypad); +err_free_mem: + input_free_device(input); + kfree(keypad); + return error; +} + +static int __devexit tc3589x_keypad_remove(struct platform_device *pdev) +{ + struct tc_keypad *keypad = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + if (!keypad->keypad_stopped) + tc3589x_keypad_disable(keypad); + + free_irq(irq, keypad); + + input_unregister_device(keypad->input); + + kfree(keypad); + + return 0; +} + +#ifdef CONFIG_PM +static int tc3589x_keypad_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tc_keypad *keypad = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + /* keypad is already off; we do nothing */ + if (keypad->keypad_stopped) + return 0; + + /* if device is not a wakeup source, disable it for powersave */ + if (!device_may_wakeup(&pdev->dev)) + tc3589x_keypad_disable(keypad); + else + enable_irq_wake(irq); + + return 0; +} + +static int tc3589x_keypad_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tc_keypad *keypad = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + if (!keypad->keypad_stopped) + return 0; + + /* enable the device to resume normal operations */ + if (!device_may_wakeup(&pdev->dev)) + tc3589x_keypad_enable(keypad); + else + disable_irq_wake(irq); + + return 0; +} + +static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops, + tc3589x_keypad_suspend, tc3589x_keypad_resume); +#endif + +static struct platform_driver tc3589x_keypad_driver = { + .driver.name = "tc3589x-keypad", + .driver.owner = THIS_MODULE, +#ifdef CONFIG_PM + .driver.pm = &tc3589x_keypad_dev_pm_ops, +#endif + .probe = tc3589x_keypad_probe, + .remove = __devexit_p(tc3589x_keypad_remove), +}; + +static int __init tc3589x_keypad_init(void) +{ + return platform_driver_register(&tc3589x_keypad_driver); +} +module_init(tc3589x_keypad_init); + +static void __exit tc3589x_keypad_exit(void) +{ + return platform_driver_unregister(&tc3589x_keypad_driver); +} +module_exit(tc3589x_keypad_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Jayeeta Banerjee/Sundar Iyer"); +MODULE_DESCRIPTION("TC35893 Keypad Driver"); +MODULE_ALIAS("platform:tc3589x-keypad"); diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c new file mode 100644 index 000000000000..ac471b77c18e --- /dev/null +++ b/drivers/input/keyboard/tegra-kbc.c @@ -0,0 +1,727 @@ +/* + * Keyboard class input driver for the NVIDIA Tegra SoC internal matrix + * keyboard controller + * + * Copyright (c) 2009-2011, NVIDIA Corporation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <mach/clk.h> +#include <mach/kbc.h> + +#define KBC_MAX_DEBOUNCE_CNT 0x3ffu + +/* KBC row scan time and delay for beginning the row scan. */ +#define KBC_ROW_SCAN_TIME 16 +#define KBC_ROW_SCAN_DLY 5 + +/* KBC uses a 32KHz clock so a cycle = 1/32Khz */ +#define KBC_CYCLE_USEC 32 + +/* KBC Registers */ + +/* KBC Control Register */ +#define KBC_CONTROL_0 0x0 +#define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14) +#define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4) +#define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3) +#define KBC_CONTROL_KBC_EN (1 << 0) + +/* KBC Interrupt Register */ +#define KBC_INT_0 0x4 +#define KBC_INT_FIFO_CNT_INT_STATUS (1 << 2) + +#define KBC_ROW_CFG0_0 0x8 +#define KBC_COL_CFG0_0 0x18 +#define KBC_INIT_DLY_0 0x28 +#define KBC_RPT_DLY_0 0x2c +#define KBC_KP_ENT0_0 0x30 +#define KBC_KP_ENT1_0 0x34 +#define KBC_ROW0_MASK_0 0x38 + +#define KBC_ROW_SHIFT 3 + +struct tegra_kbc { + void __iomem *mmio; + struct input_dev *idev; + unsigned int irq; + unsigned int wake_enable_rows; + unsigned int wake_enable_cols; + spinlock_t lock; + unsigned int repoll_dly; + unsigned long cp_dly_jiffies; + const struct tegra_kbc_platform_data *pdata; + unsigned short keycode[KBC_MAX_KEY]; + unsigned short current_keys[KBC_MAX_KPENT]; + unsigned int num_pressed_keys; + struct timer_list timer; + struct clk *clk; +}; + +static const u32 tegra_kbc_default_keymap[] = { + KEY(0, 2, KEY_W), + KEY(0, 3, KEY_S), + KEY(0, 4, KEY_A), + KEY(0, 5, KEY_Z), + KEY(0, 7, KEY_FN), + + KEY(1, 7, KEY_LEFTMETA), + + KEY(2, 6, KEY_RIGHTALT), + KEY(2, 7, KEY_LEFTALT), + + KEY(3, 0, KEY_5), + KEY(3, 1, KEY_4), + KEY(3, 2, KEY_R), + KEY(3, 3, KEY_E), + KEY(3, 4, KEY_F), + KEY(3, 5, KEY_D), + KEY(3, 6, KEY_X), + + KEY(4, 0, KEY_7), + KEY(4, 1, KEY_6), + KEY(4, 2, KEY_T), + KEY(4, 3, KEY_H), + KEY(4, 4, KEY_G), + KEY(4, 5, KEY_V), + KEY(4, 6, KEY_C), + KEY(4, 7, KEY_SPACE), + + KEY(5, 0, KEY_9), + KEY(5, 1, KEY_8), + KEY(5, 2, KEY_U), + KEY(5, 3, KEY_Y), + KEY(5, 4, KEY_J), + KEY(5, 5, KEY_N), + KEY(5, 6, KEY_B), + KEY(5, 7, KEY_BACKSLASH), + + KEY(6, 0, KEY_MINUS), + KEY(6, 1, KEY_0), + KEY(6, 2, KEY_O), + KEY(6, 3, KEY_I), + KEY(6, 4, KEY_L), + KEY(6, 5, KEY_K), + KEY(6, 6, KEY_COMMA), + KEY(6, 7, KEY_M), + + KEY(7, 1, KEY_EQUAL), + KEY(7, 2, KEY_RIGHTBRACE), + KEY(7, 3, KEY_ENTER), + KEY(7, 7, KEY_MENU), + + KEY(8, 4, KEY_RIGHTSHIFT), + KEY(8, 5, KEY_LEFTSHIFT), + + KEY(9, 5, KEY_RIGHTCTRL), + KEY(9, 7, KEY_LEFTCTRL), + + KEY(11, 0, KEY_LEFTBRACE), + KEY(11, 1, KEY_P), + KEY(11, 2, KEY_APOSTROPHE), + KEY(11, 3, KEY_SEMICOLON), + KEY(11, 4, KEY_SLASH), + KEY(11, 5, KEY_DOT), + + KEY(12, 0, KEY_F10), + KEY(12, 1, KEY_F9), + KEY(12, 2, KEY_BACKSPACE), + KEY(12, 3, KEY_3), + KEY(12, 4, KEY_2), + KEY(12, 5, KEY_UP), + KEY(12, 6, KEY_PRINT), + KEY(12, 7, KEY_PAUSE), + + KEY(13, 0, KEY_INSERT), + KEY(13, 1, KEY_DELETE), + KEY(13, 3, KEY_PAGEUP), + KEY(13, 4, KEY_PAGEDOWN), + KEY(13, 5, KEY_RIGHT), + KEY(13, 6, KEY_DOWN), + KEY(13, 7, KEY_LEFT), + + KEY(14, 0, KEY_F11), + KEY(14, 1, KEY_F12), + KEY(14, 2, KEY_F8), + KEY(14, 3, KEY_Q), + KEY(14, 4, KEY_F4), + KEY(14, 5, KEY_F3), + KEY(14, 6, KEY_1), + KEY(14, 7, KEY_F7), + + KEY(15, 0, KEY_ESC), + KEY(15, 1, KEY_GRAVE), + KEY(15, 2, KEY_F5), + KEY(15, 3, KEY_TAB), + KEY(15, 4, KEY_F1), + KEY(15, 5, KEY_F2), + KEY(15, 6, KEY_CAPSLOCK), + KEY(15, 7, KEY_F6), +}; + +static const struct matrix_keymap_data tegra_kbc_default_keymap_data = { + .keymap = tegra_kbc_default_keymap, + .keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap), +}; + +static void tegra_kbc_report_released_keys(struct input_dev *input, + unsigned short old_keycodes[], + unsigned int old_num_keys, + unsigned short new_keycodes[], + unsigned int new_num_keys) +{ + unsigned int i, j; + + for (i = 0; i < old_num_keys; i++) { + for (j = 0; j < new_num_keys; j++) + if (old_keycodes[i] == new_keycodes[j]) + break; + + if (j == new_num_keys) + input_report_key(input, old_keycodes[i], 0); + } +} + +static void tegra_kbc_report_pressed_keys(struct input_dev *input, + unsigned char scancodes[], + unsigned short keycodes[], + unsigned int num_pressed_keys) +{ + unsigned int i; + + for (i = 0; i < num_pressed_keys; i++) { + input_event(input, EV_MSC, MSC_SCAN, scancodes[i]); + input_report_key(input, keycodes[i], 1); + } +} + +static void tegra_kbc_report_keys(struct tegra_kbc *kbc) +{ + unsigned char scancodes[KBC_MAX_KPENT]; + unsigned short keycodes[KBC_MAX_KPENT]; + u32 val = 0; + unsigned int i; + unsigned int num_down = 0; + unsigned long flags; + + spin_lock_irqsave(&kbc->lock, flags); + for (i = 0; i < KBC_MAX_KPENT; i++) { + if ((i % 4) == 0) + val = readl(kbc->mmio + KBC_KP_ENT0_0 + i); + + if (val & 0x80) { + unsigned int col = val & 0x07; + unsigned int row = (val >> 3) & 0x0f; + unsigned char scancode = + MATRIX_SCAN_CODE(row, col, KBC_ROW_SHIFT); + + scancodes[num_down] = scancode; + keycodes[num_down++] = kbc->keycode[scancode]; + } + + val >>= 8; + } + spin_unlock_irqrestore(&kbc->lock, flags); + + tegra_kbc_report_released_keys(kbc->idev, + kbc->current_keys, kbc->num_pressed_keys, + keycodes, num_down); + tegra_kbc_report_pressed_keys(kbc->idev, scancodes, keycodes, num_down); + input_sync(kbc->idev); + + memcpy(kbc->current_keys, keycodes, sizeof(kbc->current_keys)); + kbc->num_pressed_keys = num_down; +} + +static void tegra_kbc_keypress_timer(unsigned long data) +{ + struct tegra_kbc *kbc = (struct tegra_kbc *)data; + unsigned long flags; + u32 val; + unsigned int i; + + val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf; + if (val) { + unsigned long dly; + + tegra_kbc_report_keys(kbc); + + /* + * If more than one keys are pressed we need not wait + * for the repoll delay. + */ + dly = (val == 1) ? kbc->repoll_dly : 1; + mod_timer(&kbc->timer, jiffies + msecs_to_jiffies(dly)); + } else { + /* Release any pressed keys and exit the polling loop */ + for (i = 0; i < kbc->num_pressed_keys; i++) + input_report_key(kbc->idev, kbc->current_keys[i], 0); + input_sync(kbc->idev); + + kbc->num_pressed_keys = 0; + + /* All keys are released so enable the keypress interrupt */ + spin_lock_irqsave(&kbc->lock, flags); + val = readl(kbc->mmio + KBC_CONTROL_0); + val |= KBC_CONTROL_FIFO_CNT_INT_EN; + writel(val, kbc->mmio + KBC_CONTROL_0); + spin_unlock_irqrestore(&kbc->lock, flags); + } +} + +static irqreturn_t tegra_kbc_isr(int irq, void *args) +{ + struct tegra_kbc *kbc = args; + u32 val, ctl; + + /* + * Until all keys are released, defer further processing to + * the polling loop in tegra_kbc_keypress_timer + */ + ctl = readl(kbc->mmio + KBC_CONTROL_0); + ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN; + writel(ctl, kbc->mmio + KBC_CONTROL_0); + + /* + * Quickly bail out & reenable interrupts if the fifo threshold + * count interrupt wasn't the interrupt source + */ + val = readl(kbc->mmio + KBC_INT_0); + writel(val, kbc->mmio + KBC_INT_0); + + if (val & KBC_INT_FIFO_CNT_INT_STATUS) { + /* + * Schedule timer to run when hardware is in continuous + * polling mode. + */ + mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); + } else { + ctl |= KBC_CONTROL_FIFO_CNT_INT_EN; + writel(ctl, kbc->mmio + KBC_CONTROL_0); + } + + return IRQ_HANDLED; +} + +static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter) +{ + const struct tegra_kbc_platform_data *pdata = kbc->pdata; + int i; + unsigned int rst_val; + + BUG_ON(pdata->wake_cnt > KBC_MAX_KEY); + rst_val = (filter && pdata->wake_cnt) ? ~0 : 0; + + for (i = 0; i < KBC_MAX_ROW; i++) + writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4); + + if (filter) { + for (i = 0; i < pdata->wake_cnt; i++) { + u32 val, addr; + addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0; + val = readl(kbc->mmio + addr); + val &= ~(1 << pdata->wake_cfg[i].col); + writel(val, kbc->mmio + addr); + } + } +} + +static void tegra_kbc_config_pins(struct tegra_kbc *kbc) +{ + const struct tegra_kbc_platform_data *pdata = kbc->pdata; + int i; + + for (i = 0; i < KBC_MAX_GPIO; i++) { + u32 r_shft = 5 * (i % 6); + u32 c_shft = 4 * (i % 8); + u32 r_mask = 0x1f << r_shft; + u32 c_mask = 0x0f << c_shft; + u32 r_offs = (i / 6) * 4 + KBC_ROW_CFG0_0; + u32 c_offs = (i / 8) * 4 + KBC_COL_CFG0_0; + u32 row_cfg = readl(kbc->mmio + r_offs); + u32 col_cfg = readl(kbc->mmio + c_offs); + + row_cfg &= ~r_mask; + col_cfg &= ~c_mask; + + if (pdata->pin_cfg[i].is_row) + row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft; + else + col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft; + + writel(row_cfg, kbc->mmio + r_offs); + writel(col_cfg, kbc->mmio + c_offs); + } +} + +static int tegra_kbc_start(struct tegra_kbc *kbc) +{ + const struct tegra_kbc_platform_data *pdata = kbc->pdata; + unsigned long flags; + unsigned int debounce_cnt; + u32 val = 0; + + clk_enable(kbc->clk); + + /* Reset the KBC controller to clear all previous status.*/ + tegra_periph_reset_assert(kbc->clk); + udelay(100); + tegra_periph_reset_deassert(kbc->clk); + udelay(100); + + tegra_kbc_config_pins(kbc); + tegra_kbc_setup_wakekeys(kbc, false); + + writel(pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0); + + /* Keyboard debounce count is maximum of 12 bits. */ + debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); + val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt); + val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */ + val |= KBC_CONTROL_FIFO_CNT_INT_EN; /* interrupt on FIFO threshold */ + val |= KBC_CONTROL_KBC_EN; /* enable */ + writel(val, kbc->mmio + KBC_CONTROL_0); + + /* + * Compute the delay(ns) from interrupt mode to continuous polling + * mode so the timer routine is scheduled appropriately. + */ + val = readl(kbc->mmio + KBC_INIT_DLY_0); + kbc->cp_dly_jiffies = usecs_to_jiffies((val & 0xfffff) * 32); + + kbc->num_pressed_keys = 0; + + /* + * Atomically clear out any remaining entries in the key FIFO + * and enable keyboard interrupts. + */ + spin_lock_irqsave(&kbc->lock, flags); + while (1) { + val = readl(kbc->mmio + KBC_INT_0); + val >>= 4; + if (!val) + break; + + val = readl(kbc->mmio + KBC_KP_ENT0_0); + val = readl(kbc->mmio + KBC_KP_ENT1_0); + } + writel(0x7, kbc->mmio + KBC_INT_0); + spin_unlock_irqrestore(&kbc->lock, flags); + + enable_irq(kbc->irq); + + return 0; +} + +static void tegra_kbc_stop(struct tegra_kbc *kbc) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&kbc->lock, flags); + val = readl(kbc->mmio + KBC_CONTROL_0); + val &= ~1; + writel(val, kbc->mmio + KBC_CONTROL_0); + spin_unlock_irqrestore(&kbc->lock, flags); + + disable_irq(kbc->irq); + del_timer_sync(&kbc->timer); + + clk_disable(kbc->clk); +} + +static int tegra_kbc_open(struct input_dev *dev) +{ + struct tegra_kbc *kbc = input_get_drvdata(dev); + + return tegra_kbc_start(kbc); +} + +static void tegra_kbc_close(struct input_dev *dev) +{ + struct tegra_kbc *kbc = input_get_drvdata(dev); + + return tegra_kbc_stop(kbc); +} + +static bool __devinit +tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, + struct device *dev, unsigned int *num_rows) +{ + int i; + + *num_rows = 0; + + for (i = 0; i < KBC_MAX_GPIO; i++) { + const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i]; + + if (pin_cfg->is_row) { + if (pin_cfg->num >= KBC_MAX_ROW) { + dev_err(dev, + "pin_cfg[%d]: invalid row number %d\n", + i, pin_cfg->num); + return false; + } + (*num_rows)++; + } else { + if (pin_cfg->num >= KBC_MAX_COL) { + dev_err(dev, + "pin_cfg[%d]: invalid column number %d\n", + i, pin_cfg->num); + return false; + } + } + } + + return true; +} + +static int __devinit tegra_kbc_probe(struct platform_device *pdev) +{ + const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data; + const struct matrix_keymap_data *keymap_data; + struct tegra_kbc *kbc; + struct input_dev *input_dev; + struct resource *res; + int irq; + int err; + int i; + int num_rows = 0; + unsigned int debounce_cnt; + unsigned int scan_time_rows; + + if (!pdata) + return -EINVAL; + + if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + return -ENXIO; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get keyboard IRQ\n"); + return -ENXIO; + } + + kbc = kzalloc(sizeof(*kbc), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!kbc || !input_dev) { + err = -ENOMEM; + goto err_free_mem; + } + + kbc->pdata = pdata; + kbc->idev = input_dev; + kbc->irq = irq; + spin_lock_init(&kbc->lock); + setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc); + + 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 err_free_mem; + } + + kbc->mmio = ioremap(res->start, resource_size(res)); + if (!kbc->mmio) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + err = -ENXIO; + goto err_free_mem_region; + } + + kbc->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(kbc->clk)) { + dev_err(&pdev->dev, "failed to get keyboard clock\n"); + err = PTR_ERR(kbc->clk); + goto err_iounmap; + } + + kbc->wake_enable_rows = 0; + kbc->wake_enable_cols = 0; + for (i = 0; i < pdata->wake_cnt; i++) { + kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row); + kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col); + } + + /* + * The time delay between two consecutive reads of the FIFO is + * the sum of the repeat time and the time taken for scanning + * the rows. There is an additional delay before the row scanning + * starts. The repoll delay is computed in milliseconds. + */ + debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); + scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows; + kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt; + kbc->repoll_dly = ((kbc->repoll_dly * KBC_CYCLE_USEC) + 999) / 1000; + + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + input_dev->dev.parent = &pdev->dev; + input_dev->open = tegra_kbc_open; + input_dev->close = tegra_kbc_close; + + input_set_drvdata(input_dev, kbc); + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + + input_dev->keycode = kbc->keycode; + input_dev->keycodesize = sizeof(kbc->keycode[0]); + input_dev->keycodemax = ARRAY_SIZE(kbc->keycode); + + keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data; + matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT, + input_dev->keycode, input_dev->keybit); + + err = request_irq(kbc->irq, tegra_kbc_isr, IRQF_TRIGGER_HIGH, + pdev->name, kbc); + if (err) { + dev_err(&pdev->dev, "failed to request keyboard IRQ\n"); + goto err_put_clk; + } + + disable_irq(kbc->irq); + + err = input_register_device(kbc->idev); + if (err) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto err_free_irq; + } + + platform_set_drvdata(pdev, kbc); + device_init_wakeup(&pdev->dev, pdata->wakeup); + + return 0; + +err_free_irq: + free_irq(kbc->irq, pdev); +err_put_clk: + clk_put(kbc->clk); +err_iounmap: + iounmap(kbc->mmio); +err_free_mem_region: + release_mem_region(res->start, resource_size(res)); +err_free_mem: + input_free_device(kbc->idev); + kfree(kbc); + + return err; +} + +static int __devexit tegra_kbc_remove(struct platform_device *pdev) +{ + struct tegra_kbc *kbc = platform_get_drvdata(pdev); + struct resource *res; + + free_irq(kbc->irq, pdev); + clk_put(kbc->clk); + + input_unregister_device(kbc->idev); + iounmap(kbc->mmio); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + kfree(kbc); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tegra_kbc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tegra_kbc *kbc = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) { + tegra_kbc_setup_wakekeys(kbc, true); + enable_irq_wake(kbc->irq); + /* Forcefully clear the interrupt status */ + writel(0x7, kbc->mmio + KBC_INT_0); + msleep(30); + } else { + mutex_lock(&kbc->idev->mutex); + if (kbc->idev->users) + tegra_kbc_stop(kbc); + mutex_unlock(&kbc->idev->mutex); + } + + return 0; +} + +static int tegra_kbc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tegra_kbc *kbc = platform_get_drvdata(pdev); + int err = 0; + + if (device_may_wakeup(&pdev->dev)) { + disable_irq_wake(kbc->irq); + tegra_kbc_setup_wakekeys(kbc, false); + } else { + mutex_lock(&kbc->idev->mutex); + if (kbc->idev->users) + err = tegra_kbc_start(kbc); + mutex_unlock(&kbc->idev->mutex); + } + + return err; +} +#endif + +static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume); + +static struct platform_driver tegra_kbc_driver = { + .probe = tegra_kbc_probe, + .remove = __devexit_p(tegra_kbc_remove), + .driver = { + .name = "tegra-kbc", + .owner = THIS_MODULE, + .pm = &tegra_kbc_pm_ops, + }, +}; + +static void __exit tegra_kbc_exit(void) +{ + platform_driver_unregister(&tegra_kbc_driver); +} +module_exit(tegra_kbc_exit); + +static int __init tegra_kbc_init(void) +{ + return platform_driver_register(&tegra_kbc_driver); +} +module_init(tegra_kbc_init); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rakesh Iyer <riyer@nvidia.com>"); +MODULE_DESCRIPTION("Tegra matrix keyboard controller driver"); +MODULE_ALIAS("platform:tegra-kbc"); diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c index b4a81ebfab92..c8f097a15d89 100644 --- a/drivers/input/keyboard/tnetv107x-keypad.c +++ b/drivers/input/keyboard/tnetv107x-keypad.c @@ -14,6 +14,7 @@ */ #include <linux/kernel.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/input.h> #include <linux/platform_device.h> @@ -219,9 +220,9 @@ static int __devinit keypad_probe(struct platform_device *pdev) } kp->clk = clk_get(dev, NULL); - if (!kp->clk) { + if (IS_ERR(kp->clk)) { dev_err(dev, "cannot claim device clock\n"); - error = -EINVAL; + error = PTR_ERR(kp->clk); goto error_clk; } diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index f0d90172a65f..b0c6772851a9 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -294,24 +294,6 @@ config INPUT_SGI_BTNS To compile this driver as a module, choose M here: the module will be called sgi_btns. -config INPUT_WINBOND_CIR - tristate "Winbond IR remote control" - depends on X86 && PNP - select NEW_LEDS - select LEDS_CLASS - select LEDS_TRIGGERS - select BITREVERSE - help - Say Y here if you want to use the IR remote functionality found - in some Winbond SuperI/O chips. Currently only the WPCD376I - chip is supported (included in some Intel Media series motherboards). - - IR Receive and wake-on-IR from suspend and power-off is currently - supported. - - To compile this driver as a module, choose M here: the module will be - called winbond_cir. - config HP_SDC_RTC tristate "HP SDC Real Time Clock" depends on (GSC || HP300) && SERIO diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 35bcfe46555e..9b4797112c9a 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -40,7 +40,6 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o -obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o diff --git a/drivers/input/misc/winbond-cir.c b/drivers/input/misc/winbond-cir.c deleted file mode 100644 index 64f1de7960c6..000000000000 --- a/drivers/input/misc/winbond-cir.c +++ /dev/null @@ -1,1608 +0,0 @@ -/* - * winbond-cir.c - Driver for the Consumer IR functionality of Winbond - * SuperI/O chips. - * - * Currently supports the Winbond WPCD376i chip (PNP id WEC1022), but - * could probably support others (Winbond WEC102X, NatSemi, etc) - * with minor modifications. - * - * Original Author: David Härdeman <david@hardeman.nu> - * Copyright (C) 2009 David Härdeman <david@hardeman.nu> - * - * Dedicated to Matilda, my newborn daughter, without whose loving attention - * this driver would have been finished in half the time and with a fraction - * of the bugs. - * - * Written using: - * o Winbond WPCD376I datasheet helpfully provided by Jesse Barnes at Intel - * o NatSemi PC87338/PC97338 datasheet (for the serial port stuff) - * o DSDT dumps - * - * Supported features: - * o RC6 - * o Wake-On-CIR functionality - * - * To do: - * o Test NEC and RC5 - * - * Left as an exercise for the reader: - * o Learning (I have neither the hardware, nor the need) - * o IR Transmit (ibid) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/pnp.h> -#include <linux/interrupt.h> -#include <linux/timer.h> -#include <linux/input.h> -#include <linux/leds.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/pci_ids.h> -#include <linux/io.h> -#include <linux/bitrev.h> -#include <linux/bitops.h> -#include <linux/slab.h> - -#define DRVNAME "winbond-cir" - -/* CEIR Wake-Up Registers, relative to data->wbase */ -#define WBCIR_REG_WCEIR_CTL 0x03 /* CEIR Receiver Control */ -#define WBCIR_REG_WCEIR_STS 0x04 /* CEIR Receiver Status */ -#define WBCIR_REG_WCEIR_EV_EN 0x05 /* CEIR Receiver Event Enable */ -#define WBCIR_REG_WCEIR_CNTL 0x06 /* CEIR Receiver Counter Low */ -#define WBCIR_REG_WCEIR_CNTH 0x07 /* CEIR Receiver Counter High */ -#define WBCIR_REG_WCEIR_INDEX 0x08 /* CEIR Receiver Index */ -#define WBCIR_REG_WCEIR_DATA 0x09 /* CEIR Receiver Data */ -#define WBCIR_REG_WCEIR_CSL 0x0A /* CEIR Re. Compare Strlen */ -#define WBCIR_REG_WCEIR_CFG1 0x0B /* CEIR Re. Configuration 1 */ -#define WBCIR_REG_WCEIR_CFG2 0x0C /* CEIR Re. Configuration 2 */ - -/* CEIR Enhanced Functionality Registers, relative to data->ebase */ -#define WBCIR_REG_ECEIR_CTS 0x00 /* Enhanced IR Control Status */ -#define WBCIR_REG_ECEIR_CCTL 0x01 /* Infrared Counter Control */ -#define WBCIR_REG_ECEIR_CNT_LO 0x02 /* Infrared Counter LSB */ -#define WBCIR_REG_ECEIR_CNT_HI 0x03 /* Infrared Counter MSB */ -#define WBCIR_REG_ECEIR_IREM 0x04 /* Infrared Emitter Status */ - -/* SP3 Banked Registers, relative to data->sbase */ -#define WBCIR_REG_SP3_BSR 0x03 /* Bank Select, all banks */ - /* Bank 0 */ -#define WBCIR_REG_SP3_RXDATA 0x00 /* FIFO RX data (r) */ -#define WBCIR_REG_SP3_TXDATA 0x00 /* FIFO TX data (w) */ -#define WBCIR_REG_SP3_IER 0x01 /* Interrupt Enable */ -#define WBCIR_REG_SP3_EIR 0x02 /* Event Identification (r) */ -#define WBCIR_REG_SP3_FCR 0x02 /* FIFO Control (w) */ -#define WBCIR_REG_SP3_MCR 0x04 /* Mode Control */ -#define WBCIR_REG_SP3_LSR 0x05 /* Link Status */ -#define WBCIR_REG_SP3_MSR 0x06 /* Modem Status */ -#define WBCIR_REG_SP3_ASCR 0x07 /* Aux Status and Control */ - /* Bank 2 */ -#define WBCIR_REG_SP3_BGDL 0x00 /* Baud Divisor LSB */ -#define WBCIR_REG_SP3_BGDH 0x01 /* Baud Divisor MSB */ -#define WBCIR_REG_SP3_EXCR1 0x02 /* Extended Control 1 */ -#define WBCIR_REG_SP3_EXCR2 0x04 /* Extended Control 2 */ -#define WBCIR_REG_SP3_TXFLV 0x06 /* TX FIFO Level */ -#define WBCIR_REG_SP3_RXFLV 0x07 /* RX FIFO Level */ - /* Bank 3 */ -#define WBCIR_REG_SP3_MRID 0x00 /* Module Identification */ -#define WBCIR_REG_SP3_SH_LCR 0x01 /* LCR Shadow */ -#define WBCIR_REG_SP3_SH_FCR 0x02 /* FCR Shadow */ - /* Bank 4 */ -#define WBCIR_REG_SP3_IRCR1 0x02 /* Infrared Control 1 */ - /* Bank 5 */ -#define WBCIR_REG_SP3_IRCR2 0x04 /* Infrared Control 2 */ - /* Bank 6 */ -#define WBCIR_REG_SP3_IRCR3 0x00 /* Infrared Control 3 */ -#define WBCIR_REG_SP3_SIR_PW 0x02 /* SIR Pulse Width */ - /* Bank 7 */ -#define WBCIR_REG_SP3_IRRXDC 0x00 /* IR RX Demod Control */ -#define WBCIR_REG_SP3_IRTXMC 0x01 /* IR TX Mod Control */ -#define WBCIR_REG_SP3_RCCFG 0x02 /* CEIR Config */ -#define WBCIR_REG_SP3_IRCFG1 0x04 /* Infrared Config 1 */ -#define WBCIR_REG_SP3_IRCFG4 0x07 /* Infrared Config 4 */ - -/* - * Magic values follow - */ - -/* No interrupts for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ -#define WBCIR_IRQ_NONE 0x00 -/* RX data bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ -#define WBCIR_IRQ_RX 0x01 -/* Over/Under-flow bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ -#define WBCIR_IRQ_ERR 0x04 -/* Led enable/disable bit for WBCIR_REG_ECEIR_CTS */ -#define WBCIR_LED_ENABLE 0x80 -/* RX data available bit for WBCIR_REG_SP3_LSR */ -#define WBCIR_RX_AVAIL 0x01 -/* RX disable bit for WBCIR_REG_SP3_ASCR */ -#define WBCIR_RX_DISABLE 0x20 -/* Extended mode enable bit for WBCIR_REG_SP3_EXCR1 */ -#define WBCIR_EXT_ENABLE 0x01 -/* Select compare register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */ -#define WBCIR_REGSEL_COMPARE 0x10 -/* Select mask register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */ -#define WBCIR_REGSEL_MASK 0x20 -/* Starting address of selected register in WBCIR_REG_WCEIR_INDEX */ -#define WBCIR_REG_ADDR0 0x00 - -/* Valid banks for the SP3 UART */ -enum wbcir_bank { - WBCIR_BANK_0 = 0x00, - WBCIR_BANK_1 = 0x80, - WBCIR_BANK_2 = 0xE0, - WBCIR_BANK_3 = 0xE4, - WBCIR_BANK_4 = 0xE8, - WBCIR_BANK_5 = 0xEC, - WBCIR_BANK_6 = 0xF0, - WBCIR_BANK_7 = 0xF4, -}; - -/* Supported IR Protocols */ -enum wbcir_protocol { - IR_PROTOCOL_RC5 = 0x0, - IR_PROTOCOL_NEC = 0x1, - IR_PROTOCOL_RC6 = 0x2, -}; - -/* Misc */ -#define WBCIR_NAME "Winbond CIR" -#define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */ -#define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */ -#define IR_KEYPRESS_TIMEOUT 250 /* FIXME: should be per-protocol? */ -#define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */ -#define WAKEUP_IOMEM_LEN 0x10 /* Wake-Up I/O Reg Len */ -#define EHFUNC_IOMEM_LEN 0x10 /* Enhanced Func I/O Reg Len */ -#define SP_IOMEM_LEN 0x08 /* Serial Port 3 (IR) Reg Len */ -#define WBCIR_MAX_IDLE_BYTES 10 - -static DEFINE_SPINLOCK(wbcir_lock); -static DEFINE_RWLOCK(keytable_lock); - -struct wbcir_key { - u32 scancode; - unsigned int keycode; -}; - -struct wbcir_keyentry { - struct wbcir_key key; - struct list_head list; -}; - -static struct wbcir_key rc6_def_keymap[] = { - { 0x800F0400, KEY_NUMERIC_0 }, - { 0x800F0401, KEY_NUMERIC_1 }, - { 0x800F0402, KEY_NUMERIC_2 }, - { 0x800F0403, KEY_NUMERIC_3 }, - { 0x800F0404, KEY_NUMERIC_4 }, - { 0x800F0405, KEY_NUMERIC_5 }, - { 0x800F0406, KEY_NUMERIC_6 }, - { 0x800F0407, KEY_NUMERIC_7 }, - { 0x800F0408, KEY_NUMERIC_8 }, - { 0x800F0409, KEY_NUMERIC_9 }, - { 0x800F041D, KEY_NUMERIC_STAR }, - { 0x800F041C, KEY_NUMERIC_POUND }, - { 0x800F0410, KEY_VOLUMEUP }, - { 0x800F0411, KEY_VOLUMEDOWN }, - { 0x800F0412, KEY_CHANNELUP }, - { 0x800F0413, KEY_CHANNELDOWN }, - { 0x800F040E, KEY_MUTE }, - { 0x800F040D, KEY_VENDOR }, /* Vista Logo Key */ - { 0x800F041E, KEY_UP }, - { 0x800F041F, KEY_DOWN }, - { 0x800F0420, KEY_LEFT }, - { 0x800F0421, KEY_RIGHT }, - { 0x800F0422, KEY_OK }, - { 0x800F0423, KEY_ESC }, - { 0x800F040F, KEY_INFO }, - { 0x800F040A, KEY_CLEAR }, - { 0x800F040B, KEY_ENTER }, - { 0x800F045B, KEY_RED }, - { 0x800F045C, KEY_GREEN }, - { 0x800F045D, KEY_YELLOW }, - { 0x800F045E, KEY_BLUE }, - { 0x800F045A, KEY_TEXT }, - { 0x800F0427, KEY_SWITCHVIDEOMODE }, - { 0x800F040C, KEY_POWER }, - { 0x800F0450, KEY_RADIO }, - { 0x800F0448, KEY_PVR }, - { 0x800F0447, KEY_AUDIO }, - { 0x800F0426, KEY_EPG }, - { 0x800F0449, KEY_CAMERA }, - { 0x800F0425, KEY_TV }, - { 0x800F044A, KEY_VIDEO }, - { 0x800F0424, KEY_DVD }, - { 0x800F0416, KEY_PLAY }, - { 0x800F0418, KEY_PAUSE }, - { 0x800F0419, KEY_STOP }, - { 0x800F0414, KEY_FASTFORWARD }, - { 0x800F041A, KEY_NEXT }, - { 0x800F041B, KEY_PREVIOUS }, - { 0x800F0415, KEY_REWIND }, - { 0x800F0417, KEY_RECORD }, -}; - -/* Registers and other state is protected by wbcir_lock */ -struct wbcir_data { - unsigned long wbase; /* Wake-Up Baseaddr */ - unsigned long ebase; /* Enhanced Func. Baseaddr */ - unsigned long sbase; /* Serial Port Baseaddr */ - unsigned int irq; /* Serial Port IRQ */ - - struct input_dev *input_dev; - struct timer_list timer_keyup; - struct led_trigger *rxtrigger; - struct led_trigger *txtrigger; - struct led_classdev led; - - u32 last_scancode; - unsigned int last_keycode; - u8 last_toggle; - u8 keypressed; - unsigned long keyup_jiffies; - unsigned int idle_count; - - /* RX irdata and parsing state */ - unsigned long irdata[30]; - unsigned int irdata_count; - unsigned int irdata_idle; - unsigned int irdata_off; - unsigned int irdata_error; - - /* Protected by keytable_lock */ - struct list_head keytable; -}; - -static enum wbcir_protocol protocol = IR_PROTOCOL_RC6; -module_param(protocol, uint, 0444); -MODULE_PARM_DESC(protocol, "IR protocol to use " - "(0 = RC5, 1 = NEC, 2 = RC6A, default)"); - -static int invert; /* default = 0 */ -module_param(invert, bool, 0444); -MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver"); - -static unsigned int wake_sc = 0x800F040C; -module_param(wake_sc, uint, 0644); -MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command"); - -static unsigned int wake_rc6mode = 6; -module_param(wake_rc6mode, uint, 0644); -MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command " - "(0 = 0, 6 = 6A, default)"); - - - -/***************************************************************************** - * - * UTILITY FUNCTIONS - * - *****************************************************************************/ - -/* Caller needs to hold wbcir_lock */ -static void -wbcir_set_bits(unsigned long addr, u8 bits, u8 mask) -{ - u8 val; - - val = inb(addr); - val = ((val & ~mask) | (bits & mask)); - outb(val, addr); -} - -/* Selects the register bank for the serial port */ -static inline void -wbcir_select_bank(struct wbcir_data *data, enum wbcir_bank bank) -{ - outb(bank, data->sbase + WBCIR_REG_SP3_BSR); -} - -static enum led_brightness -wbcir_led_brightness_get(struct led_classdev *led_cdev) -{ - struct wbcir_data *data = container_of(led_cdev, - struct wbcir_data, - led); - - if (inb(data->ebase + WBCIR_REG_ECEIR_CTS) & WBCIR_LED_ENABLE) - return LED_FULL; - else - return LED_OFF; -} - -static void -wbcir_led_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct wbcir_data *data = container_of(led_cdev, - struct wbcir_data, - led); - - wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CTS, - brightness == LED_OFF ? 0x00 : WBCIR_LED_ENABLE, - WBCIR_LED_ENABLE); -} - -/* Manchester encodes bits to RC6 message cells (see wbcir_parse_rc6) */ -static u8 -wbcir_to_rc6cells(u8 val) -{ - u8 coded = 0x00; - int i; - - val &= 0x0F; - for (i = 0; i < 4; i++) { - if (val & 0x01) - coded |= 0x02 << (i * 2); - else - coded |= 0x01 << (i * 2); - val >>= 1; - } - - return coded; -} - - - -/***************************************************************************** - * - * INPUT FUNCTIONS - * - *****************************************************************************/ - -static unsigned int -wbcir_do_getkeycode(struct wbcir_data *data, u32 scancode) -{ - struct wbcir_keyentry *keyentry; - unsigned int keycode = KEY_RESERVED; - unsigned long flags; - - read_lock_irqsave(&keytable_lock, flags); - - list_for_each_entry(keyentry, &data->keytable, list) { - if (keyentry->key.scancode == scancode) { - keycode = keyentry->key.keycode; - break; - } - } - - read_unlock_irqrestore(&keytable_lock, flags); - return keycode; -} - -static int -wbcir_getkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) -{ - struct wbcir_data *data = input_get_drvdata(dev); - - *keycode = wbcir_do_getkeycode(data, scancode); - return 0; -} - -static int -wbcir_setkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode) -{ - struct wbcir_data *data = input_get_drvdata(dev); - struct wbcir_keyentry *keyentry; - struct wbcir_keyentry *new_keyentry; - unsigned long flags; - unsigned int old_keycode = KEY_RESERVED; - - new_keyentry = kmalloc(sizeof(*new_keyentry), GFP_KERNEL); - if (!new_keyentry) - return -ENOMEM; - - write_lock_irqsave(&keytable_lock, flags); - - list_for_each_entry(keyentry, &data->keytable, list) { - if (keyentry->key.scancode != scancode) - continue; - - old_keycode = keyentry->key.keycode; - keyentry->key.keycode = keycode; - - if (keyentry->key.keycode == KEY_RESERVED) { - list_del(&keyentry->list); - kfree(keyentry); - } - - break; - } - - set_bit(keycode, dev->keybit); - - if (old_keycode == KEY_RESERVED) { - new_keyentry->key.scancode = scancode; - new_keyentry->key.keycode = keycode; - list_add(&new_keyentry->list, &data->keytable); - } else { - kfree(new_keyentry); - clear_bit(old_keycode, dev->keybit); - list_for_each_entry(keyentry, &data->keytable, list) { - if (keyentry->key.keycode == old_keycode) { - set_bit(old_keycode, dev->keybit); - break; - } - } - } - - write_unlock_irqrestore(&keytable_lock, flags); - return 0; -} - -/* - * Timer function to report keyup event some time after keydown is - * reported by the ISR. - */ -static void -wbcir_keyup(unsigned long cookie) -{ - struct wbcir_data *data = (struct wbcir_data *)cookie; - unsigned long flags; - - /* - * data->keyup_jiffies is used to prevent a race condition if a - * hardware interrupt occurs at this point and the keyup timer - * event is moved further into the future as a result. - * - * The timer will then be reactivated and this function called - * again in the future. We need to exit gracefully in that case - * to allow the input subsystem to do its auto-repeat magic or - * a keyup event might follow immediately after the keydown. - */ - - spin_lock_irqsave(&wbcir_lock, flags); - - if (time_is_after_eq_jiffies(data->keyup_jiffies) && data->keypressed) { - data->keypressed = 0; - led_trigger_event(data->rxtrigger, LED_OFF); - input_report_key(data->input_dev, data->last_keycode, 0); - input_sync(data->input_dev); - } - - spin_unlock_irqrestore(&wbcir_lock, flags); -} - -static void -wbcir_keydown(struct wbcir_data *data, u32 scancode, u8 toggle) -{ - unsigned int keycode; - - /* Repeat? */ - if (data->last_scancode == scancode && - data->last_toggle == toggle && - data->keypressed) - goto set_timer; - data->last_scancode = scancode; - - /* Do we need to release an old keypress? */ - if (data->keypressed) { - input_report_key(data->input_dev, data->last_keycode, 0); - input_sync(data->input_dev); - data->keypressed = 0; - } - - /* Report scancode */ - input_event(data->input_dev, EV_MSC, MSC_SCAN, (int)scancode); - - /* Do we know this scancode? */ - keycode = wbcir_do_getkeycode(data, scancode); - if (keycode == KEY_RESERVED) - goto set_timer; - - /* Register a keypress */ - input_report_key(data->input_dev, keycode, 1); - data->keypressed = 1; - data->last_keycode = keycode; - data->last_toggle = toggle; - -set_timer: - input_sync(data->input_dev); - led_trigger_event(data->rxtrigger, - data->keypressed ? LED_FULL : LED_OFF); - data->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); - mod_timer(&data->timer_keyup, data->keyup_jiffies); -} - - - -/***************************************************************************** - * - * IR PARSING FUNCTIONS - * - *****************************************************************************/ - -/* Resets all irdata */ -static void -wbcir_reset_irdata(struct wbcir_data *data) -{ - memset(data->irdata, 0, sizeof(data->irdata)); - data->irdata_count = 0; - data->irdata_off = 0; - data->irdata_error = 0; - data->idle_count = 0; -} - -/* Adds one bit of irdata */ -static void -add_irdata_bit(struct wbcir_data *data, int set) -{ - if (data->irdata_count >= sizeof(data->irdata) * 8) { - data->irdata_error = 1; - return; - } - - if (set) - __set_bit(data->irdata_count, data->irdata); - data->irdata_count++; -} - -/* Gets count bits of irdata */ -static u16 -get_bits(struct wbcir_data *data, int count) -{ - u16 val = 0x0; - - if (data->irdata_count - data->irdata_off < count) { - data->irdata_error = 1; - return 0x0; - } - - while (count > 0) { - val <<= 1; - if (test_bit(data->irdata_off, data->irdata)) - val |= 0x1; - count--; - data->irdata_off++; - } - - return val; -} - -/* Reads 16 cells and converts them to a byte */ -static u8 -wbcir_rc6cells_to_byte(struct wbcir_data *data) -{ - u16 raw = get_bits(data, 16); - u8 val = 0x00; - int bit; - - for (bit = 0; bit < 8; bit++) { - switch (raw & 0x03) { - case 0x01: - break; - case 0x02: - val |= (0x01 << bit); - break; - default: - data->irdata_error = 1; - break; - } - raw >>= 2; - } - - return val; -} - -/* Decodes a number of bits from raw RC5 data */ -static u8 -wbcir_get_rc5bits(struct wbcir_data *data, unsigned int count) -{ - u16 raw = get_bits(data, count * 2); - u8 val = 0x00; - int bit; - - for (bit = 0; bit < count; bit++) { - switch (raw & 0x03) { - case 0x01: - val |= (0x01 << bit); - break; - case 0x02: - break; - default: - data->irdata_error = 1; - break; - } - raw >>= 2; - } - - return val; -} - -static void -wbcir_parse_rc6(struct device *dev, struct wbcir_data *data) -{ - /* - * Normal bits are manchester coded as follows: - * cell0 + cell1 = logic "0" - * cell1 + cell0 = logic "1" - * - * The IR pulse has the following components: - * - * Leader - 6 * cell1 - discarded - * Gap - 2 * cell0 - discarded - * Start bit - Normal Coding - always "1" - * Mode Bit 2 - 0 - Normal Coding - * Toggle bit - Normal Coding with double bit time, - * e.g. cell0 + cell0 + cell1 + cell1 - * means logic "0". - * - * The rest depends on the mode, the following modes are known: - * - * MODE 0: - * Address Bit 7 - 0 - Normal Coding - * Command Bit 7 - 0 - Normal Coding - * - * MODE 6: - * The above Toggle Bit is used as a submode bit, 0 = A, 1 = B. - * Submode B is for pointing devices, only remotes using submode A - * are supported. - * - * Customer range bit - 0 => Customer = 7 bits, 0...127 - * 1 => Customer = 15 bits, 32768...65535 - * Customer Bits - Normal Coding - * - * Customer codes are allocated by Philips. The rest of the bits - * are customer dependent. The following is commonly used (and the - * only supported config): - * - * Toggle Bit - Normal Coding - * Address Bit 6 - 0 - Normal Coding - * Command Bit 7 - 0 - Normal Coding - * - * All modes are followed by at least 6 * cell0. - * - * MODE 0 msglen: - * 1 * 2 (start bit) + 3 * 2 (mode) + 2 * 2 (toggle) + - * 8 * 2 (address) + 8 * 2 (command) = - * 44 cells - * - * MODE 6A msglen: - * 1 * 2 (start bit) + 3 * 2 (mode) + 2 * 2 (submode) + - * 1 * 2 (customer range bit) + 7/15 * 2 (customer bits) + - * 1 * 2 (toggle bit) + 7 * 2 (address) + 8 * 2 (command) = - * 60 - 76 cells - */ - u8 mode; - u8 toggle; - u16 customer = 0x0; - u8 address; - u8 command; - u32 scancode; - - /* Leader mark */ - while (get_bits(data, 1) && !data->irdata_error) - /* Do nothing */; - - /* Leader space */ - if (get_bits(data, 1)) { - dev_dbg(dev, "RC6 - Invalid leader space\n"); - return; - } - - /* Start bit */ - if (get_bits(data, 2) != 0x02) { - dev_dbg(dev, "RC6 - Invalid start bit\n"); - return; - } - - /* Mode */ - mode = get_bits(data, 6); - switch (mode) { - case 0x15: /* 010101 = b000 */ - mode = 0; - break; - case 0x29: /* 101001 = b110 */ - mode = 6; - break; - default: - dev_dbg(dev, "RC6 - Invalid mode\n"); - return; - } - - /* Toggle bit / Submode bit */ - toggle = get_bits(data, 4); - switch (toggle) { - case 0x03: - toggle = 0; - break; - case 0x0C: - toggle = 1; - break; - default: - dev_dbg(dev, "RC6 - Toggle bit error\n"); - break; - } - - /* Customer */ - if (mode == 6) { - if (toggle != 0) { - dev_dbg(dev, "RC6B - Not Supported\n"); - return; - } - - customer = wbcir_rc6cells_to_byte(data); - - if (customer & 0x80) { - /* 15 bit customer value */ - customer <<= 8; - customer |= wbcir_rc6cells_to_byte(data); - } - } - - /* Address */ - address = wbcir_rc6cells_to_byte(data); - if (mode == 6) { - toggle = address >> 7; - address &= 0x7F; - } - - /* Command */ - command = wbcir_rc6cells_to_byte(data); - - /* Create scancode */ - scancode = command; - scancode |= address << 8; - scancode |= customer << 16; - - /* Last sanity check */ - if (data->irdata_error) { - dev_dbg(dev, "RC6 - Cell error(s)\n"); - return; - } - - dev_dbg(dev, "IR-RC6 ad 0x%02X cm 0x%02X cu 0x%04X " - "toggle %u mode %u scan 0x%08X\n", - address, - command, - customer, - (unsigned int)toggle, - (unsigned int)mode, - scancode); - - wbcir_keydown(data, scancode, toggle); -} - -static void -wbcir_parse_rc5(struct device *dev, struct wbcir_data *data) -{ - /* - * Bits are manchester coded as follows: - * cell1 + cell0 = logic "0" - * cell0 + cell1 = logic "1" - * (i.e. the reverse of RC6) - * - * Start bit 1 - "1" - discarded - * Start bit 2 - Must be inverted to get command bit 6 - * Toggle bit - * Address Bit 4 - 0 - * Command Bit 5 - 0 - */ - u8 toggle; - u8 address; - u8 command; - u32 scancode; - - /* Start bit 1 */ - if (!get_bits(data, 1)) { - dev_dbg(dev, "RC5 - Invalid start bit\n"); - return; - } - - /* Start bit 2 */ - if (!wbcir_get_rc5bits(data, 1)) - command = 0x40; - else - command = 0x00; - - toggle = wbcir_get_rc5bits(data, 1); - address = wbcir_get_rc5bits(data, 5); - command |= wbcir_get_rc5bits(data, 6); - scancode = address << 7 | command; - - /* Last sanity check */ - if (data->irdata_error) { - dev_dbg(dev, "RC5 - Invalid message\n"); - return; - } - - dev_dbg(dev, "IR-RC5 ad %u cm %u t %u s %u\n", - (unsigned int)address, - (unsigned int)command, - (unsigned int)toggle, - (unsigned int)scancode); - - wbcir_keydown(data, scancode, toggle); -} - -static void -wbcir_parse_nec(struct device *dev, struct wbcir_data *data) -{ - /* - * Each bit represents 560 us. - * - * Leader - 9 ms burst - * Gap - 4.5 ms silence - * Address1 bit 0 - 7 - Address 1 - * Address2 bit 0 - 7 - Address 2 - * Command1 bit 0 - 7 - Command 1 - * Command2 bit 0 - 7 - Command 2 - * - * Note the bit order! - * - * With the old NEC protocol, Address2 was the inverse of Address1 - * and Command2 was the inverse of Command1 and were used as - * an error check. - * - * With NEC extended, Address1 is the LSB of the Address and - * Address2 is the MSB, Command parsing remains unchanged. - * - * A repeat message is coded as: - * Leader - 9 ms burst - * Gap - 2.25 ms silence - * Repeat - 560 us active - */ - u8 address1; - u8 address2; - u8 command1; - u8 command2; - u16 address; - u32 scancode; - - /* Leader mark */ - while (get_bits(data, 1) && !data->irdata_error) - /* Do nothing */; - - /* Leader space */ - if (get_bits(data, 4)) { - dev_dbg(dev, "NEC - Invalid leader space\n"); - return; - } - - /* Repeat? */ - if (get_bits(data, 1)) { - if (!data->keypressed) { - dev_dbg(dev, "NEC - Stray repeat message\n"); - return; - } - - dev_dbg(dev, "IR-NEC repeat s %u\n", - (unsigned int)data->last_scancode); - - wbcir_keydown(data, data->last_scancode, data->last_toggle); - return; - } - - /* Remaining leader space */ - if (get_bits(data, 3)) { - dev_dbg(dev, "NEC - Invalid leader space\n"); - return; - } - - address1 = bitrev8(get_bits(data, 8)); - address2 = bitrev8(get_bits(data, 8)); - command1 = bitrev8(get_bits(data, 8)); - command2 = bitrev8(get_bits(data, 8)); - - /* Sanity check */ - if (data->irdata_error) { - dev_dbg(dev, "NEC - Invalid message\n"); - return; - } - - /* Check command validity */ - if (command1 != ~command2) { - dev_dbg(dev, "NEC - Command bytes mismatch\n"); - return; - } - - /* Check for extended NEC protocol */ - address = address1; - if (address1 != ~address2) - address |= address2 << 8; - - scancode = address << 8 | command1; - - dev_dbg(dev, "IR-NEC ad %u cm %u s %u\n", - (unsigned int)address, - (unsigned int)command1, - (unsigned int)scancode); - - wbcir_keydown(data, scancode, !data->last_toggle); -} - - - -/***************************************************************************** - * - * INTERRUPT FUNCTIONS - * - *****************************************************************************/ - -static irqreturn_t -wbcir_irq_handler(int irqno, void *cookie) -{ - struct pnp_dev *device = cookie; - struct wbcir_data *data = pnp_get_drvdata(device); - struct device *dev = &device->dev; - u8 status; - unsigned long flags; - u8 irdata[8]; - int i; - unsigned int hw; - - spin_lock_irqsave(&wbcir_lock, flags); - - wbcir_select_bank(data, WBCIR_BANK_0); - - status = inb(data->sbase + WBCIR_REG_SP3_EIR); - - if (!(status & (WBCIR_IRQ_RX | WBCIR_IRQ_ERR))) { - spin_unlock_irqrestore(&wbcir_lock, flags); - return IRQ_NONE; - } - - if (status & WBCIR_IRQ_ERR) - data->irdata_error = 1; - - if (!(status & WBCIR_IRQ_RX)) - goto out; - - /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */ - insb(data->sbase + WBCIR_REG_SP3_RXDATA, &irdata[0], 8); - - for (i = 0; i < sizeof(irdata); i++) { - hw = hweight8(irdata[i]); - if (hw > 4) - add_irdata_bit(data, 0); - else - add_irdata_bit(data, 1); - - if (hw == 8) - data->idle_count++; - else - data->idle_count = 0; - } - - if (data->idle_count > WBCIR_MAX_IDLE_BYTES) { - /* Set RXINACTIVE... */ - outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR); - - /* ...and drain the FIFO */ - while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) - inb(data->sbase + WBCIR_REG_SP3_RXDATA); - - dev_dbg(dev, "IRDATA:\n"); - for (i = 0; i < data->irdata_count; i += BITS_PER_LONG) - dev_dbg(dev, "0x%08lX\n", data->irdata[i/BITS_PER_LONG]); - - switch (protocol) { - case IR_PROTOCOL_RC5: - wbcir_parse_rc5(dev, data); - break; - case IR_PROTOCOL_RC6: - wbcir_parse_rc6(dev, data); - break; - case IR_PROTOCOL_NEC: - wbcir_parse_nec(dev, data); - break; - } - - wbcir_reset_irdata(data); - } - -out: - spin_unlock_irqrestore(&wbcir_lock, flags); - return IRQ_HANDLED; -} - - - -/***************************************************************************** - * - * SETUP/INIT/SUSPEND/RESUME FUNCTIONS - * - *****************************************************************************/ - -static void -wbcir_shutdown(struct pnp_dev *device) -{ - struct device *dev = &device->dev; - struct wbcir_data *data = pnp_get_drvdata(device); - int do_wake = 1; - u8 match[11]; - u8 mask[11]; - u8 rc6_csl = 0; - int i; - - memset(match, 0, sizeof(match)); - memset(mask, 0, sizeof(mask)); - - if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) { - do_wake = 0; - goto finish; - } - - switch (protocol) { - case IR_PROTOCOL_RC5: - if (wake_sc > 0xFFF) { - do_wake = 0; - dev_err(dev, "RC5 - Invalid wake scancode\n"); - break; - } - - /* Mask = 13 bits, ex toggle */ - mask[0] = 0xFF; - mask[1] = 0x17; - - match[0] = (wake_sc & 0x003F); /* 6 command bits */ - match[0] |= (wake_sc & 0x0180) >> 1; /* 2 address bits */ - match[1] = (wake_sc & 0x0E00) >> 9; /* 3 address bits */ - if (!(wake_sc & 0x0040)) /* 2nd start bit */ - match[1] |= 0x10; - - break; - - case IR_PROTOCOL_NEC: - if (wake_sc > 0xFFFFFF) { - do_wake = 0; - dev_err(dev, "NEC - Invalid wake scancode\n"); - break; - } - - mask[0] = mask[1] = mask[2] = mask[3] = 0xFF; - - match[1] = bitrev8((wake_sc & 0xFF)); - match[0] = ~match[1]; - - match[3] = bitrev8((wake_sc & 0xFF00) >> 8); - if (wake_sc > 0xFFFF) - match[2] = bitrev8((wake_sc & 0xFF0000) >> 16); - else - match[2] = ~match[3]; - - break; - - case IR_PROTOCOL_RC6: - - if (wake_rc6mode == 0) { - if (wake_sc > 0xFFFF) { - do_wake = 0; - dev_err(dev, "RC6 - Invalid wake scancode\n"); - break; - } - - /* Command */ - match[0] = wbcir_to_rc6cells(wake_sc >> 0); - mask[0] = 0xFF; - match[1] = wbcir_to_rc6cells(wake_sc >> 4); - mask[1] = 0xFF; - - /* Address */ - match[2] = wbcir_to_rc6cells(wake_sc >> 8); - mask[2] = 0xFF; - match[3] = wbcir_to_rc6cells(wake_sc >> 12); - mask[3] = 0xFF; - - /* Header */ - match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */ - mask[4] = 0xF0; - match[5] = 0x09; /* start bit = 1, mode2 = 0 */ - mask[5] = 0x0F; - - rc6_csl = 44; - - } else if (wake_rc6mode == 6) { - i = 0; - - /* Command */ - match[i] = wbcir_to_rc6cells(wake_sc >> 0); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 4); - mask[i++] = 0xFF; - - /* Address + Toggle */ - match[i] = wbcir_to_rc6cells(wake_sc >> 8); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 12); - mask[i++] = 0x3F; - - /* Customer bits 7 - 0 */ - match[i] = wbcir_to_rc6cells(wake_sc >> 16); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 20); - mask[i++] = 0xFF; - - if (wake_sc & 0x80000000) { - /* Customer range bit and bits 15 - 8 */ - match[i] = wbcir_to_rc6cells(wake_sc >> 24); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 28); - mask[i++] = 0xFF; - rc6_csl = 76; - } else if (wake_sc <= 0x007FFFFF) { - rc6_csl = 60; - } else { - do_wake = 0; - dev_err(dev, "RC6 - Invalid wake scancode\n"); - break; - } - - /* Header */ - match[i] = 0x93; /* mode1 = mode0 = 1, submode = 0 */ - mask[i++] = 0xFF; - match[i] = 0x0A; /* start bit = 1, mode2 = 1 */ - mask[i++] = 0x0F; - - } else { - do_wake = 0; - dev_err(dev, "RC6 - Invalid wake mode\n"); - } - - break; - - default: - do_wake = 0; - break; - } - -finish: - if (do_wake) { - /* Set compare and compare mask */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX, - WBCIR_REGSEL_COMPARE | WBCIR_REG_ADDR0, - 0x3F); - outsb(data->wbase + WBCIR_REG_WCEIR_DATA, match, 11); - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX, - WBCIR_REGSEL_MASK | WBCIR_REG_ADDR0, - 0x3F); - outsb(data->wbase + WBCIR_REG_WCEIR_DATA, mask, 11); - - /* RC6 Compare String Len */ - outb(rc6_csl, data->wbase + WBCIR_REG_WCEIR_CSL); - - /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); - - /* Clear BUFF_EN, Clear END_EN, Set MATCH_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x01, 0x07); - - /* Set CEIR_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x01, 0x01); - - } else { - /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); - - /* Clear CEIR_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01); - } - - /* Disable interrupts */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER); - - /* - * ACPI will set the HW disable bit for SP3 which means that the - * output signals are left in an undefined state which may cause - * spurious interrupts which we need to ignore until the hardware - * is reinitialized. - */ - disable_irq(data->irq); -} - -static int -wbcir_suspend(struct pnp_dev *device, pm_message_t state) -{ - wbcir_shutdown(device); - return 0; -} - -static void -wbcir_init_hw(struct wbcir_data *data) -{ - u8 tmp; - - /* Disable interrupts */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER); - - /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */ - tmp = protocol << 4; - if (invert) - tmp |= 0x08; - outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL); - - /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); - - /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); - - /* Set RC5 cell time to correspond to 36 kHz */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CFG1, 0x4A, 0x7F); - - /* Set IRTX_INV */ - if (invert) - outb(0x04, data->ebase + WBCIR_REG_ECEIR_CCTL); - else - outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL); - - /* - * Clear IR LED, set SP3 clock to 24Mhz - * set SP3_IRRX_SW to binary 01, helpfully not documented - */ - outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS); - - /* Enable extended mode */ - wbcir_select_bank(data, WBCIR_BANK_2); - outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1); - - /* - * Configure baud generator, IR data will be sampled at - * a bitrate of: (24Mhz * prescaler) / (divisor * 16). - * - * The ECIR registers include a flag to change the - * 24Mhz clock freq to 48Mhz. - * - * It's not documented in the specs, but fifo levels - * other than 16 seems to be unsupported. - */ - - /* prescaler 1.0, tx/rx fifo lvl 16 */ - outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2); - - /* Set baud divisor to generate one byte per bit/cell */ - switch (protocol) { - case IR_PROTOCOL_RC5: - outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL); - break; - case IR_PROTOCOL_RC6: - outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL); - break; - case IR_PROTOCOL_NEC: - outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL); - break; - } - outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH); - - /* Set CEIR mode */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR); - inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */ - inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */ - - /* Disable RX demod, run-length encoding/decoding, set freq span */ - wbcir_select_bank(data, WBCIR_BANK_7); - outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG); - - /* Disable timer */ - wbcir_select_bank(data, WBCIR_BANK_4); - outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1); - - /* Enable MSR interrupt, Clear AUX_IRX */ - wbcir_select_bank(data, WBCIR_BANK_5); - outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2); - - /* Disable CRC */ - wbcir_select_bank(data, WBCIR_BANK_6); - outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3); - - /* Set RX/TX (de)modulation freq, not really used */ - wbcir_select_bank(data, WBCIR_BANK_7); - outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC); - outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC); - - /* Set invert and pin direction */ - if (invert) - outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4); - else - outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4); - - /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(0x97, data->sbase + WBCIR_REG_SP3_FCR); - - /* Clear AUX status bits */ - outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR); - - /* Enable interrupts */ - wbcir_reset_irdata(data); - outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER); -} - -static int -wbcir_resume(struct pnp_dev *device) -{ - struct wbcir_data *data = pnp_get_drvdata(device); - - wbcir_init_hw(data); - enable_irq(data->irq); - - return 0; -} - -static int __devinit -wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) -{ - struct device *dev = &device->dev; - struct wbcir_data *data; - int err; - - if (!(pnp_port_len(device, 0) == EHFUNC_IOMEM_LEN && - pnp_port_len(device, 1) == WAKEUP_IOMEM_LEN && - pnp_port_len(device, 2) == SP_IOMEM_LEN)) { - dev_err(dev, "Invalid resources\n"); - return -ENODEV; - } - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - err = -ENOMEM; - goto exit; - } - - pnp_set_drvdata(device, data); - - data->ebase = pnp_port_start(device, 0); - data->wbase = pnp_port_start(device, 1); - data->sbase = pnp_port_start(device, 2); - data->irq = pnp_irq(device, 0); - - if (data->wbase == 0 || data->ebase == 0 || - data->sbase == 0 || data->irq == 0) { - err = -ENODEV; - dev_err(dev, "Invalid resources\n"); - goto exit_free_data; - } - - dev_dbg(&device->dev, "Found device " - "(w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n", - data->wbase, data->ebase, data->sbase, data->irq); - - if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) { - dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", - data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1); - err = -EBUSY; - goto exit_free_data; - } - - if (!request_region(data->ebase, EHFUNC_IOMEM_LEN, DRVNAME)) { - dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", - data->ebase, data->ebase + EHFUNC_IOMEM_LEN - 1); - err = -EBUSY; - goto exit_release_wbase; - } - - if (!request_region(data->sbase, SP_IOMEM_LEN, DRVNAME)) { - dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", - data->sbase, data->sbase + SP_IOMEM_LEN - 1); - err = -EBUSY; - goto exit_release_ebase; - } - - err = request_irq(data->irq, wbcir_irq_handler, - IRQF_DISABLED, DRVNAME, device); - if (err) { - dev_err(dev, "Failed to claim IRQ %u\n", data->irq); - err = -EBUSY; - goto exit_release_sbase; - } - - led_trigger_register_simple("cir-tx", &data->txtrigger); - if (!data->txtrigger) { - err = -ENOMEM; - goto exit_free_irq; - } - - led_trigger_register_simple("cir-rx", &data->rxtrigger); - if (!data->rxtrigger) { - err = -ENOMEM; - goto exit_unregister_txtrigger; - } - - data->led.name = "cir::activity"; - data->led.default_trigger = "cir-rx"; - data->led.brightness_set = wbcir_led_brightness_set; - data->led.brightness_get = wbcir_led_brightness_get; - err = led_classdev_register(&device->dev, &data->led); - if (err) - goto exit_unregister_rxtrigger; - - data->input_dev = input_allocate_device(); - if (!data->input_dev) { - err = -ENOMEM; - goto exit_unregister_led; - } - - data->input_dev->evbit[0] = BIT(EV_KEY); - data->input_dev->name = WBCIR_NAME; - data->input_dev->phys = "wbcir/cir0"; - data->input_dev->id.bustype = BUS_HOST; - data->input_dev->id.vendor = PCI_VENDOR_ID_WINBOND; - data->input_dev->id.product = WBCIR_ID_FAMILY; - data->input_dev->id.version = WBCIR_ID_CHIP; - data->input_dev->getkeycode = wbcir_getkeycode; - data->input_dev->setkeycode = wbcir_setkeycode; - input_set_capability(data->input_dev, EV_MSC, MSC_SCAN); - input_set_drvdata(data->input_dev, data); - - err = input_register_device(data->input_dev); - if (err) - goto exit_free_input; - - data->last_scancode = INVALID_SCANCODE; - INIT_LIST_HEAD(&data->keytable); - setup_timer(&data->timer_keyup, wbcir_keyup, (unsigned long)data); - - /* Load default keymaps */ - if (protocol == IR_PROTOCOL_RC6) { - int i; - for (i = 0; i < ARRAY_SIZE(rc6_def_keymap); i++) { - err = wbcir_setkeycode(data->input_dev, - (int)rc6_def_keymap[i].scancode, - (int)rc6_def_keymap[i].keycode); - if (err) - goto exit_unregister_keys; - } - } - - device_init_wakeup(&device->dev, 1); - - wbcir_init_hw(data); - - return 0; - -exit_unregister_keys: - if (!list_empty(&data->keytable)) { - struct wbcir_keyentry *key; - struct wbcir_keyentry *keytmp; - - list_for_each_entry_safe(key, keytmp, &data->keytable, list) { - list_del(&key->list); - kfree(key); - } - } - input_unregister_device(data->input_dev); - /* Can't call input_free_device on an unregistered device */ - data->input_dev = NULL; -exit_free_input: - input_free_device(data->input_dev); -exit_unregister_led: - led_classdev_unregister(&data->led); -exit_unregister_rxtrigger: - led_trigger_unregister_simple(data->rxtrigger); -exit_unregister_txtrigger: - led_trigger_unregister_simple(data->txtrigger); -exit_free_irq: - free_irq(data->irq, device); -exit_release_sbase: - release_region(data->sbase, SP_IOMEM_LEN); -exit_release_ebase: - release_region(data->ebase, EHFUNC_IOMEM_LEN); -exit_release_wbase: - release_region(data->wbase, WAKEUP_IOMEM_LEN); -exit_free_data: - kfree(data); - pnp_set_drvdata(device, NULL); -exit: - return err; -} - -static void __devexit -wbcir_remove(struct pnp_dev *device) -{ - struct wbcir_data *data = pnp_get_drvdata(device); - struct wbcir_keyentry *key; - struct wbcir_keyentry *keytmp; - - /* Disable interrupts */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER); - - del_timer_sync(&data->timer_keyup); - - free_irq(data->irq, device); - - /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); - - /* Clear CEIR_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01); - - /* Clear BUFF_EN, END_EN, MATCH_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); - - /* This will generate a keyup event if necessary */ - input_unregister_device(data->input_dev); - - led_trigger_unregister_simple(data->rxtrigger); - led_trigger_unregister_simple(data->txtrigger); - led_classdev_unregister(&data->led); - - /* This is ok since &data->led isn't actually used */ - wbcir_led_brightness_set(&data->led, LED_OFF); - - release_region(data->wbase, WAKEUP_IOMEM_LEN); - release_region(data->ebase, EHFUNC_IOMEM_LEN); - release_region(data->sbase, SP_IOMEM_LEN); - - list_for_each_entry_safe(key, keytmp, &data->keytable, list) { - list_del(&key->list); - kfree(key); - } - - kfree(data); - - pnp_set_drvdata(device, NULL); -} - -static const struct pnp_device_id wbcir_ids[] = { - { "WEC1022", 0 }, - { "", 0 } -}; -MODULE_DEVICE_TABLE(pnp, wbcir_ids); - -static struct pnp_driver wbcir_driver = { - .name = WBCIR_NAME, - .id_table = wbcir_ids, - .probe = wbcir_probe, - .remove = __devexit_p(wbcir_remove), - .suspend = wbcir_suspend, - .resume = wbcir_resume, - .shutdown = wbcir_shutdown -}; - -static int __init -wbcir_init(void) -{ - int ret; - - switch (protocol) { - case IR_PROTOCOL_RC5: - case IR_PROTOCOL_NEC: - case IR_PROTOCOL_RC6: - break; - default: - printk(KERN_ERR DRVNAME ": Invalid protocol argument\n"); - return -EINVAL; - } - - ret = pnp_register_driver(&wbcir_driver); - if (ret) - printk(KERN_ERR DRVNAME ": Unable to register driver\n"); - - return ret; -} - -static void __exit -wbcir_exit(void) -{ - pnp_unregister_driver(&wbcir_driver); -} - -MODULE_AUTHOR("David Härdeman <david@hardeman.nu>"); -MODULE_DESCRIPTION("Winbond SuperI/O Consumer IR Driver"); -MODULE_LICENSE("GPL"); - -module_init(wbcir_init); -module_exit(wbcir_exit); - - diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index bf5fd7f6a313..9c1e6ee83531 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -39,7 +39,7 @@ config MOUSE_PS2 module will be called psmouse. config MOUSE_PS2_ALPS - bool "ALPS PS/2 mouse protocol extension" if EMBEDDED + bool "ALPS PS/2 mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 help @@ -49,7 +49,7 @@ config MOUSE_PS2_ALPS If unsure, say Y. config MOUSE_PS2_LOGIPS2PP - bool "Logitech PS/2++ mouse protocol extension" if EMBEDDED + bool "Logitech PS/2++ mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 help @@ -59,7 +59,7 @@ config MOUSE_PS2_LOGIPS2PP If unsure, say Y. config MOUSE_PS2_SYNAPTICS - bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED + bool "Synaptics PS/2 mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 help @@ -69,7 +69,7 @@ config MOUSE_PS2_SYNAPTICS If unsure, say Y. config MOUSE_PS2_LIFEBOOK - bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED + bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 && X86 && DMI help @@ -79,7 +79,7 @@ config MOUSE_PS2_LIFEBOOK If unsure, say Y. config MOUSE_PS2_TRACKPOINT - bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED + bool "IBM Trackpoint PS/2 mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 help diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index b95231763911..ee82851afe3e 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -55,6 +55,14 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 +/* MacbookAir3,2 (unibody), aka wellspring5 */ +#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f +#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240 +#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241 +/* MacbookAir3,1 (unibody), aka wellspring4 */ +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244 #define BCM5974_DEVICE(prod) { \ .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ @@ -80,6 +88,14 @@ static const struct usb_device_id bcm5974_table[] = { BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS), + /* MacbookAir3,2 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_JIS), + /* MacbookAir3,1 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS), /* Terminating entry */ {} }; @@ -234,6 +250,30 @@ static const struct bcm5974_config bcm5974_config_table[] = { { DIM_X, DIM_X / SN_COORD, -4460, 5166 }, { DIM_Y, DIM_Y / SN_COORD, -75, 6700 } }, + { + USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING4_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING4_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4620, 5140 }, + { DIM_Y, DIM_Y / SN_COORD, -150, 6600 } + }, + { + USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4616, 5112 }, + { DIM_Y, DIM_Y / SN_COORD, -142, 5234 } + }, {} }; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index da392c22fc6c..aa186cf6c514 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -755,23 +755,26 @@ static int synaptics_reconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; struct synaptics_data old_priv = *priv; + int retry = 0; + int error; - psmouse_reset(psmouse); + do { + psmouse_reset(psmouse); + error = synaptics_detect(psmouse, 0); + } while (error && ++retry < 3); - if (synaptics_detect(psmouse, 0)) + if (error) return -1; + if (retry > 1) + printk(KERN_DEBUG "Synaptics reconnected after %d tries\n", + retry); + if (synaptics_query_hardware(psmouse)) { printk(KERN_ERR "Unable to query Synaptics hardware.\n"); return -1; } - if (old_priv.identity != priv->identity || - old_priv.model_id != priv->model_id || - old_priv.capabilities != priv->capabilities || - old_priv.ext_cap != priv->ext_cap) - return -1; - if (synaptics_set_absolute_mode(psmouse)) { printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); return -1; @@ -782,6 +785,19 @@ static int synaptics_reconnect(struct psmouse *psmouse) return -1; } + if (old_priv.identity != priv->identity || + old_priv.model_id != priv->model_id || + old_priv.capabilities != priv->capabilities || + old_priv.ext_cap != priv->ext_cap) { + printk(KERN_ERR "Synaptics hardware appears to be different: " + "id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", + old_priv.identity, priv->identity, + old_priv.model_id, priv->model_id, + old_priv.capabilities, priv->capabilities, + old_priv.ext_cap, priv->ext_cap); + return -1; + } + return 0; } diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 50e20e9da442..25e5d042a72c 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -51,7 +51,8 @@ #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) #define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) -#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100) +#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ +#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ #define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 6256233d2bfb..55f2c2293ec6 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -2,7 +2,7 @@ # Input core configuration # config SERIO - tristate "Serial I/O support" if EMBEDDED || !X86 + tristate "Serial I/O support" if EXPERT || !X86 default y help Say Yes here if you have any input device that uses serial I/O to @@ -19,7 +19,7 @@ config SERIO if SERIO config SERIO_I8042 - tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 + tristate "i8042 PC Keyboard controller" if EXPERT || !X86 default y depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN @@ -168,7 +168,7 @@ config SERIO_MACEPS2 module will be called maceps2. config SERIO_LIBPS2 - tristate "PS/2 driver library" if EMBEDDED + tristate "PS/2 driver library" if EXPERT depends on SERIO_I8042 || SERIO_I8042=n help Say Y here if you are using a driver for device connected @@ -214,7 +214,6 @@ config SERIO_AMS_DELTA tristate "Amstrad Delta (E3) mailboard support" depends on MACH_AMS_DELTA default y - select AMS_DELTA_FIQ ---help--- Say Y here if you have an E3 and want to use its mailboard, or any standard AT keyboard connected to the mailboard port. @@ -230,7 +229,7 @@ config SERIO_PS2MULT tristate "TQC PS/2 multiplexer" help Say Y here if you have the PS/2 line multiplexer like the one - present on TQC boads. + present on TQC boards. To compile this driver as a module, choose M here: the module will be called ps2mult. diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 448c7724beb9..852816567241 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -111,9 +111,11 @@ static void ct82c710_close(struct serio *serio) static int ct82c710_open(struct serio *serio) { unsigned char status; + int err; - if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) - return -1; + err = request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL); + if (err) + return err; status = inb_p(CT82C710_STATUS); @@ -131,7 +133,7 @@ static int ct82c710_open(struct serio *serio) status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); outb_p(status, CT82C710_STATUS); free_irq(CT82C710_IRQ, NULL); - return -1; + return -EBUSY; } return 0; diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 3c287dd879d3..4225f5d6b15f 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -358,7 +358,7 @@ static int __devinit gscps2_probe(struct parisc_device *dev) gscps2_reset(ps2port); ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f; - snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s", + snprintf(serio->name, sizeof(serio->name), "gsc-ps2-%s", (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse"); strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys)); serio->id.type = SERIO_8042; diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index cd82bb125915..b7ba4597f7f0 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -11,7 +11,6 @@ #include <linux/sched.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/poll.h> #include <linux/module.h> #include <linux/serio.h> diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 6e362de3f412..8755f5f3ad37 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -116,14 +116,15 @@ static void serport_ldisc_close(struct tty_struct *tty) /* * serport_ldisc_receive() is called by the low level tty driver when characters - * are ready for us. We forward the characters, one by one to the 'interrupt' - * routine. + * are ready for us. We forward the characters and flags, one by one to the + * 'interrupt' routine. */ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct serport *serport = (struct serport*) tty->disc_data; unsigned long flags; + unsigned int ch_flags; int i; spin_lock_irqsave(&serport->lock, flags); @@ -131,8 +132,23 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c if (!test_bit(SERPORT_ACTIVE, &serport->flags)) goto out; - for (i = 0; i < count; i++) - serio_interrupt(serport->serio, cp[i], 0); + for (i = 0; i < count; i++) { + switch (fp[i]) { + case TTY_FRAME: + ch_flags = SERIO_FRAME; + break; + + case TTY_PARITY: + ch_flags = SERIO_PARITY; + break; + + default: + ch_flags = 0; + break; + } + + serio_interrupt(serport->serio, cp[i], ch_flags); + } out: spin_unlock_irqrestore(&serport->lock, flags); diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index a29a7812bd46..7729e547ba65 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -201,6 +201,7 @@ int sparse_keymap_setup(struct input_dev *dev, break; case KE_SW: + case KE_VSW: __set_bit(EV_SW, dev->evbit); __set_bit(entry->sw.code, dev->swbit); break; diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 57b25b84d1fc..0a619c558bfb 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1097,7 +1097,7 @@ store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(pointer_mode, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletPointerMode, store_tabletPointerMode); /*********************************************************************** @@ -1134,7 +1134,7 @@ store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, co } static DEVICE_ATTR(coordinate_mode, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletCoordinateMode, store_tabletCoordinateMode); /*********************************************************************** @@ -1176,7 +1176,7 @@ store_tabletToolMode(struct device *dev, struct device_attribute *attr, const ch } static DEVICE_ATTR(tool_mode, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletToolMode, store_tabletToolMode); /*********************************************************************** @@ -1219,7 +1219,7 @@ store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char } static DEVICE_ATTR(xtilt, - S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt); + S_IRUGO | S_IWUSR, show_tabletXtilt, store_tabletXtilt); /*********************************************************************** * support routines for the 'ytilt' file. Note that this file @@ -1261,7 +1261,7 @@ store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char } static DEVICE_ATTR(ytilt, - S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt); + S_IRUGO | S_IWUSR, show_tabletYtilt, store_tabletYtilt); /*********************************************************************** * support routines for the 'jitter' file. Note that this file @@ -1288,7 +1288,7 @@ store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(jitter, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletJitterDelay, store_tabletJitterDelay); /*********************************************************************** @@ -1317,7 +1317,7 @@ store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(delay, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletProgrammableDelay, store_tabletProgrammableDelay); /*********************************************************************** @@ -1406,7 +1406,7 @@ store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(stylus_upper, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletStylusUpper, store_tabletStylusUpper); /*********************************************************************** @@ -1437,7 +1437,7 @@ store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(stylus_lower, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletStylusLower, store_tabletStylusLower); /*********************************************************************** @@ -1475,7 +1475,7 @@ store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const c } static DEVICE_ATTR(mouse_left, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletMouseLeft, store_tabletMouseLeft); /*********************************************************************** @@ -1505,7 +1505,7 @@ store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(mouse_middle, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletMouseMiddle, store_tabletMouseMiddle); /*********************************************************************** @@ -1535,7 +1535,7 @@ store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(mouse_right, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletMouseRight, store_tabletMouseRight); /*********************************************************************** @@ -1567,7 +1567,7 @@ store_tabletWheel(struct device *dev, struct device_attribute *attr, const char } static DEVICE_ATTR(wheel, - S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel); + S_IRUGO | S_IWUSR, show_tabletWheel, store_tabletWheel); /*********************************************************************** * support routines for the 'execute' file. Note that this file @@ -1600,7 +1600,7 @@ store_tabletExecute(struct device *dev, struct device_attribute *attr, const cha } static DEVICE_ATTR(execute, - S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute); + S_IRUGO | S_IWUSR, show_tabletExecute, store_tabletExecute); /*********************************************************************** * support routines for the 'odm_code' file. Note that this file diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index de5adb109030..23317bd09c82 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -103,6 +103,7 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE(DRIVER_LICENSE); #define USB_VENDOR_ID_WACOM 0x056a +#define USB_VENDOR_ID_LENOVO 0x17ef struct wacom { dma_addr_t data_dma; diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 0b0525486711..367fa82a607e 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1101,6 +1101,13 @@ void wacom_setup_device_quirks(struct wacom_features *features) } } +static unsigned int wacom_calculate_touch_res(unsigned int logical_max, + unsigned int physical_max) +{ + /* Touch physical dimensions are in 100th of mm */ + return (logical_max * 100) / physical_max; +} + void wacom_setup_input_capabilities(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { @@ -1228,8 +1235,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case TABLETPC: if (features->device_type == BTN_TOOL_DOUBLETAP || features->device_type == BTN_TOOL_TRIPLETAP) { - input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0); - input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0); + input_abs_set_res(input_dev, ABS_X, + wacom_calculate_touch_res(features->x_max, + features->x_phy)); + input_abs_set_res(input_dev, ABS_Y, + wacom_calculate_touch_res(features->y_max, + features->y_phy)); __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); } @@ -1272,6 +1283,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, features->pressure_max, features->pressure_fuzz, 0); + input_abs_set_res(input_dev, ABS_X, + wacom_calculate_touch_res(features->x_max, + features->x_phy)); + input_abs_set_res(input_dev, ABS_Y, + wacom_calculate_touch_res(features->y_max, + features->y_phy)); } else if (features->device_type == BTN_TOOL_PEN) { __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit); @@ -1424,11 +1441,29 @@ static struct wacom_features wacom_features_0xD2 = { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; static struct wacom_features wacom_features_0xD3 = { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; +static const struct wacom_features wacom_features_0xD4 = + { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xD6 = + { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xD7 = + { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xD8 = + { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xDA = + { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xDB = + { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; +static const struct wacom_features wacom_features_0x6004 = + { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, 0, TABLETPC }; #define USB_DEVICE_WACOM(prod) \ USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \ .driver_info = (kernel_ulong_t)&wacom_features_##prod +#define USB_DEVICE_LENOVO(prod) \ + USB_DEVICE(USB_VENDOR_ID_LENOVO, prod), \ + .driver_info = (kernel_ulong_t)&wacom_features_##prod + const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x00) }, { USB_DEVICE_WACOM(0x10) }, @@ -1492,6 +1527,12 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xD1) }, { USB_DEVICE_WACOM(0xD2) }, { USB_DEVICE_WACOM(0xD3) }, + { USB_DEVICE_WACOM(0xD4) }, + { USB_DEVICE_WACOM(0xD6) }, + { USB_DEVICE_WACOM(0xD7) }, + { USB_DEVICE_WACOM(0xD8) }, + { USB_DEVICE_WACOM(0xDA) }, + { USB_DEVICE_WACOM(0xDB) }, { USB_DEVICE_WACOM(0xF0) }, { USB_DEVICE_WACOM(0xCC) }, { USB_DEVICE_WACOM(0x90) }, @@ -1501,6 +1542,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xE2) }, { USB_DEVICE_WACOM(0xE3) }, { USB_DEVICE_WACOM(0x47) }, + { USB_DEVICE_LENOVO(0x6004) }, { } }; MODULE_DEVICE_TABLE(usb, wacom_ids); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index ec5ee98fa6f6..258e43e98ec3 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -550,62 +550,62 @@ config TOUCHSCREEN_MC13783 config TOUCHSCREEN_USB_EGALAX default y - bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED + bool "eGalax, eTurboTouch CT-410/510/700 device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_PANJIT default y - bool "PanJit device support" if EMBEDDED + bool "PanJit device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_3M default y - bool "3M/Microtouch EX II series device support" if EMBEDDED + bool "3M/Microtouch EX II series device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_ITM default y - bool "ITM device support" if EMBEDDED + bool "ITM device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_ETURBO default y - bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED + bool "eTurboTouch (non-eGalax compatible) device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_GUNZE default y - bool "Gunze AHL61 device support" if EMBEDDED + bool "Gunze AHL61 device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_DMC_TSC10 default y - bool "DMC TSC-10/25 device support" if EMBEDDED + bool "DMC TSC-10/25 device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_IRTOUCH default y - bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED + bool "IRTOUCHSYSTEMS/UNITOP device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_IDEALTEK default y - bool "IdealTEK URTC1000 device support" if EMBEDDED + bool "IdealTEK URTC1000 device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_GENERAL_TOUCH default y - bool "GeneralTouch Touchscreen device support" if EMBEDDED + bool "GeneralTouch Touchscreen device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_GOTOP default y - bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED + bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_JASTEC default y - bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED + bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_E2I @@ -615,17 +615,17 @@ config TOUCHSCREEN_USB_E2I config TOUCHSCREEN_USB_ZYTRONIC default y - bool "Zytronic controller" if EMBEDDED + bool "Zytronic controller" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_ETT_TC45USB default y - bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED + bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_NEXIO default y - bool "NEXIO/iNexio device support" if EMBEDDED + bool "NEXIO/iNexio device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_TOUCHIT213 diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index f7fa9ef4cd65..1507ce108d5b 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -12,6 +12,7 @@ #include <linux/input.h> #include <linux/input/bu21013.h> #include <linux/slab.h> +#include <linux/regulator/consumer.h> #define PEN_DOWN_INTR 0 #define MAX_FINGERS 2 @@ -139,6 +140,7 @@ * @chip: pointer to the touch panel controller * @in_dev: pointer to the input device structure * @intr_pin: interrupt pin value + * @regulator: pointer to the Regulator used for touch screen * * Touch panel device data structure */ @@ -149,6 +151,7 @@ struct bu21013_ts_data { const struct bu21013_platform_device *chip; struct input_dev *in_dev; unsigned int intr_pin; + struct regulator *regulator; }; /** @@ -456,6 +459,20 @@ static int __devinit bu21013_probe(struct i2c_client *client, bu21013_data->in_dev = in_dev; bu21013_data->chip = pdata; bu21013_data->client = client; + + bu21013_data->regulator = regulator_get(&client->dev, "V-TOUCH"); + if (IS_ERR(bu21013_data->regulator)) { + dev_err(&client->dev, "regulator_get failed\n"); + error = PTR_ERR(bu21013_data->regulator); + goto err_free_mem; + } + + error = regulator_enable(bu21013_data->regulator); + if (error < 0) { + dev_err(&client->dev, "regulator enable failed\n"); + goto err_put_regulator; + } + bu21013_data->touch_stopped = false; init_waitqueue_head(&bu21013_data->wait); @@ -464,7 +481,7 @@ static int __devinit bu21013_probe(struct i2c_client *client, error = pdata->cs_en(pdata->cs_pin); if (error < 0) { dev_err(&client->dev, "chip init failed\n"); - goto err_free_mem; + goto err_disable_regulator; } } @@ -485,9 +502,9 @@ static int __devinit bu21013_probe(struct i2c_client *client, __set_bit(EV_ABS, in_dev->evbit); input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, - pdata->x_max_res, 0, 0); + pdata->touch_x_max, 0, 0); input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, - pdata->y_max_res, 0, 0); + pdata->touch_y_max, 0, 0); input_set_drvdata(in_dev, bu21013_data); error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq, @@ -513,6 +530,10 @@ err_free_irq: bu21013_free_irq(bu21013_data); err_cs_disable: pdata->cs_dis(pdata->cs_pin); +err_disable_regulator: + regulator_disable(bu21013_data->regulator); +err_put_regulator: + regulator_put(bu21013_data->regulator); err_free_mem: input_free_device(in_dev); kfree(bu21013_data); @@ -535,6 +556,10 @@ static int __devexit bu21013_remove(struct i2c_client *client) bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin); input_unregister_device(bu21013_data->in_dev); + + regulator_disable(bu21013_data->regulator); + regulator_put(bu21013_data->regulator); + kfree(bu21013_data); device_init_wakeup(&client->dev, false); @@ -561,6 +586,8 @@ static int bu21013_suspend(struct device *dev) else disable_irq(bu21013_data->chip->irq); + regulator_disable(bu21013_data->regulator); + return 0; } @@ -577,6 +604,12 @@ static int bu21013_resume(struct device *dev) struct i2c_client *client = bu21013_data->client; int retval; + retval = regulator_enable(bu21013_data->regulator); + if (retval < 0) { + dev_err(&client->dev, "bu21013 regulator enable failed\n"); + return retval; + } + retval = bu21013_init_chip(bu21013_data); if (retval < 0) { dev_err(&client->dev, "bu21013 controller config failed\n"); diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c index cf1dba2e267c..22a3411e93c5 100644 --- a/drivers/input/touchscreen/tnetv107x-ts.c +++ b/drivers/input/touchscreen/tnetv107x-ts.c @@ -14,6 +14,7 @@ */ #include <linux/kernel.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/input.h> #include <linux/platform_device.h> @@ -289,9 +290,9 @@ static int __devinit tsc_probe(struct platform_device *pdev) } ts->clk = clk_get(dev, NULL); - if (!ts->clk) { + if (IS_ERR(ts->clk)) { dev_err(dev, "cannot claim device clock\n"); - error = -EINVAL; + error = PTR_ERR(ts->clk); goto error_clk; } diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index f45f80f6d336..73fd6642b681 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -178,6 +178,7 @@ static const struct usb_device_id usbtouch_devices[] = { #ifdef CONFIG_TOUCHSCREEN_USB_ITM {USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM}, + {USB_DEVICE(0x16e3, 0xf9e9), .driver_info = DEVTYPE_ITM}, #endif #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO |