From fb5bbee0dd033db7c31fe6cb78d2ce2b6588fd42 Mon Sep 17 00:00:00 2001 From: Thomas Chou Date: Mon, 12 Oct 2009 21:35:00 -0700 Subject: [PATCH 01/51] Input: add driver for Altera PS/2 controller This patch adds a new SERIO driver to support the Altera University Program PS/2 controller. [dtor@mail.ru: assorted cleanups] Signed-off-by: Thomas Chou Signed-off-by: Dmitry Torokhov --- drivers/input/serio/Kconfig | 8 ++ drivers/input/serio/Makefile | 1 + drivers/input/serio/altera_ps2.c | 200 +++++++++++++++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 drivers/input/serio/altera_ps2.c diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index aa533ceffe34..7e319d65ec57 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -201,4 +201,12 @@ config SERIO_XILINX_XPS_PS2 To compile this driver as a module, choose M here: the module will be called xilinx_ps2. +config SERIO_ALTERA_PS2 + tristate "Altera UP PS/2 controller" + help + Say Y here if you have Altera University Program PS/2 ports. + + To compile this driver as a module, choose M here: the + module will be called altera_ps2. + endif diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 9b6c8135955f..bf945f789d05 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o obj-$(CONFIG_SERIO_LIBPS2) += libps2.o obj-$(CONFIG_SERIO_RAW) += serio_raw.o obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o +obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c new file mode 100644 index 000000000000..f479ea50919f --- /dev/null +++ b/drivers/input/serio/altera_ps2.c @@ -0,0 +1,200 @@ +/* + * Altera University Program PS2 controller driver + * + * Copyright (C) 2008 Thomas Chou + * + * Based on sa1111ps2.c, which is: + * Copyright (C) 2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "altera_ps2" + +struct ps2if { + struct serio *io; + struct resource *iomem_res; + void __iomem *base; + unsigned irq; +}; + +/* + * Read all bytes waiting in the PS2 port. There should be + * at the most one, but we loop for safety. + */ +static irqreturn_t altera_ps2_rxint(int irq, void *dev_id) +{ + struct ps2if *ps2if = dev_id; + unsigned int status; + int handled = IRQ_NONE; + + while ((status = readl(ps2if->base)) & 0xffff0000) { + serio_interrupt(ps2if->io, status & 0xff, 0); + handled = IRQ_HANDLED; + } + + return handled; +} + +/* + * Write a byte to the PS2 port. + */ +static int altera_ps2_write(struct serio *io, unsigned char val) +{ + struct ps2if *ps2if = io->port_data; + + writel(val, ps2if->base); + return 0; +} + +static int altera_ps2_open(struct serio *io) +{ + struct ps2if *ps2if = io->port_data; + + /* clear fifo */ + while (readl(ps2if->base) & 0xffff0000) + /* empty */; + + writel(1, ps2if->base + 4); /* enable rx irq */ + return 0; +} + +static void altera_ps2_close(struct serio *io) +{ + struct ps2if *ps2if = io->port_data; + + writel(0, ps2if->base); /* disable rx irq */ +} + +/* + * Add one device to this driver. + */ +static int altera_ps2_probe(struct platform_device *pdev) +{ + struct ps2if *ps2if; + struct serio *serio; + int error; + + ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { + error = -ENOMEM; + goto err_free_mem; + } + + serio->id.type = SERIO_8042; + serio->write = altera_ps2_write; + serio->open = altera_ps2_open; + serio->close = altera_ps2_close; + strlcpy(serio->name, dev_name(&pdev->dev), sizeof(serio->name)); + strlcpy(serio->phys, dev_name(&pdev->dev), sizeof(serio->phys)); + serio->port_data = ps2if; + serio->dev.parent = &pdev->dev; + ps2if->io = serio; + + ps2if->iomem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (ps2if->iomem_res == NULL) { + error = -ENOENT; + goto err_free_mem; + } + + ps2if->irq = platform_get_irq(pdev, 0); + if (ps2if->irq < 0) { + error = -ENXIO; + goto err_free_mem; + } + + if (!request_mem_region(ps2if->iomem_res->start, + resource_size(ps2if->iomem_res), pdev->name)) { + error = -EBUSY; + goto err_free_mem; + } + + ps2if->base = ioremap(ps2if->iomem_res->start, + resource_size(ps2if->iomem_res)); + if (!ps2if->base) { + error = -ENOMEM; + goto err_free_res; + } + + error = request_irq(ps2if->irq, altera_ps2_rxint, 0, pdev->name, ps2if); + if (error) { + dev_err(&pdev->dev, "could not allocate IRQ %d: %d\n", + ps2if->irq, error); + goto err_unmap; + } + + dev_info(&pdev->dev, "base %p, irq %d\n", ps2if->base, ps2if->irq); + + serio_register_port(ps2if->io); + platform_set_drvdata(pdev, ps2if); + + return 0; + + err_unmap: + iounmap(ps2if->base); + err_free_res: + release_mem_region(ps2if->iomem_res->start, + resource_size(ps2if->iomem_res)); + err_free_mem: + kfree(ps2if); + kfree(serio); + return error; +} + +/* + * Remove one device from this driver. + */ +static int altera_ps2_remove(struct platform_device *pdev) +{ + struct ps2if *ps2if = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + serio_unregister_port(ps2if->io); + free_irq(ps2if->irq, ps2if); + iounmap(ps2if->base); + release_mem_region(ps2if->iomem_res->start, + resource_size(ps2if->iomem_res)); + kfree(ps2if); + + return 0; +} + +/* + * Our device driver structure + */ +static struct platform_driver altera_ps2_driver = { + .probe = altera_ps2_probe, + .remove = altera_ps2_remove, + .driver = { + .name = DRV_NAME, + }, +}; + +static int __init altera_ps2_init(void) +{ + return platform_driver_register(&altera_ps2_driver); +} + +static void __exit altera_ps2_exit(void) +{ + platform_driver_unregister(&altera_ps2_driver); +} + +module_init(altera_ps2_init); +module_exit(altera_ps2_exit); + +MODULE_DESCRIPTION("Altera University Program PS2 controller driver"); +MODULE_AUTHOR("Thomas Chou "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); From 7d3fadd148cbba1bc1836dd5a5d2d4b67788ffd5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 13 Oct 2009 23:36:00 -0700 Subject: [PATCH 02/51] Input: lkkbd - change formatting style to match the rest of the kernel - no spaces between function name and opening parenthesis - switch statements were indented too much This makes checkpatch (and me) happy. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lkkbd.c | 472 ++++++++++++++++----------------- 1 file changed, 226 insertions(+), 246 deletions(-) diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index f9847e0fb553..fa9bb6d235e2 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -72,9 +72,9 @@ #define DRIVER_DESC "LK keyboard driver" -MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION (DRIVER_DESC); -MODULE_LICENSE ("GPL"); +MODULE_AUTHOR("Jan-Benedict Glaw "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); /* * Known parameters: @@ -85,27 +85,27 @@ MODULE_LICENSE ("GPL"); * Please notice that there's not yet an API to set these at runtime. */ static int bell_volume = 100; /* % */ -module_param (bell_volume, int, 0); -MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%"); +module_param(bell_volume, int, 0); +MODULE_PARM_DESC(bell_volume, "Bell volume (in %). default is 100%"); static int keyclick_volume = 100; /* % */ -module_param (keyclick_volume, int, 0); -MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%"); +module_param(keyclick_volume, int, 0); +MODULE_PARM_DESC(keyclick_volume, "Keyclick volume (in %), default is 100%"); static int ctrlclick_volume = 100; /* % */ -module_param (ctrlclick_volume, int, 0); -MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); +module_param(ctrlclick_volume, int, 0); +MODULE_PARM_DESC(ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); static int lk201_compose_is_alt; -module_param (lk201_compose_is_alt, int, 0); -MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " - "will act as an Alt key"); +module_param(lk201_compose_is_alt, int, 0); +MODULE_PARM_DESC(lk201_compose_is_alt, + "If set non-zero, LK201' Compose key will act as an Alt key"); #undef LKKBD_DEBUG #ifdef LKKBD_DEBUG -#define DBG(x...) printk (x) +#define DBG(x...) printk(x) #else #define DBG(x...) do {} while (0) #endif @@ -122,7 +122,7 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " #define LK_MODE_DOWN 0x80 #define LK_MODE_AUTODOWN 0x82 #define LK_MODE_UPDOWN 0x86 -#define LK_CMD_SET_MODE(mode,div) ((mode) | ((div) << 3)) +#define LK_CMD_SET_MODE(mode, div) ((mode) | ((div) << 3)) /* Misc commands */ #define LK_CMD_ENABLE_KEYCLICK 0x1b @@ -152,11 +152,8 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " #define LK_NUM_KEYCODES 256 #define LK_NUM_IGNORE_BYTES 6 -typedef u_int16_t lk_keycode_t; - - -static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { +static unsigned short lkkbd_keycode[LK_NUM_KEYCODES] = { [0x56] = KEY_F1, [0x57] = KEY_F2, [0x58] = KEY_F3, @@ -268,7 +265,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { }; #define CHECK_LED(LK, VAR_ON, VAR_OFF, LED, BITS) do { \ - if (test_bit (LED, (LK)->dev->led)) \ + if (test_bit(LED, (LK)->dev->led)) \ VAR_ON |= BITS; \ else \ VAR_OFF |= BITS; \ @@ -278,7 +275,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { * Per-keyboard data */ struct lkkbd { - lk_keycode_t keycode[LK_NUM_KEYCODES]; + unsigned short keycode[LK_NUM_KEYCODES]; int ignore_bytes; unsigned char id[LK_NUM_IGNORE_BYTES]; struct input_dev *dev; @@ -301,26 +298,25 @@ static struct { unsigned char *name; } lk_response[] = { #define RESPONSE(x) { .value = (x), .name = #x, } - RESPONSE (LK_STUCK_KEY), - RESPONSE (LK_SELFTEST_FAILED), - RESPONSE (LK_ALL_KEYS_UP), - RESPONSE (LK_METRONOME), - RESPONSE (LK_OUTPUT_ERROR), - RESPONSE (LK_INPUT_ERROR), - RESPONSE (LK_KBD_LOCKED), - RESPONSE (LK_KBD_TEST_MODE_ACK), - RESPONSE (LK_PREFIX_KEY_DOWN), - RESPONSE (LK_MODE_CHANGE_ACK), - RESPONSE (LK_RESPONSE_RESERVED), + RESPONSE(LK_STUCK_KEY), + RESPONSE(LK_SELFTEST_FAILED), + RESPONSE(LK_ALL_KEYS_UP), + RESPONSE(LK_METRONOME), + RESPONSE(LK_OUTPUT_ERROR), + RESPONSE(LK_INPUT_ERROR), + RESPONSE(LK_KBD_LOCKED), + RESPONSE(LK_KBD_TEST_MODE_ACK), + RESPONSE(LK_PREFIX_KEY_DOWN), + RESPONSE(LK_MODE_CHANGE_ACK), + RESPONSE(LK_RESPONSE_RESERVED), #undef RESPONSE }; -static unsigned char * -response_name (unsigned char value) +static unsigned char *response_name(unsigned char value) { int i; - for (i = 0; i < ARRAY_SIZE (lk_response); i++) + for (i = 0; i < ARRAY_SIZE(lk_response); i++) if (lk_response[i].value == value) return lk_response[i].name; @@ -331,8 +327,7 @@ response_name (unsigned char value) /* * Calculate volume parameter byte for a given volume. */ -static unsigned char -volume_to_hw (int volume_percent) +static unsigned char volume_to_hw(int volume_percent) { unsigned char ret = 0; @@ -363,8 +358,7 @@ volume_to_hw (int volume_percent) return ret; } -static void -lkkbd_detection_done (struct lkkbd *lk) +static void lkkbd_detection_done(struct lkkbd *lk) { int i; @@ -377,190 +371,202 @@ lkkbd_detection_done (struct lkkbd *lk) * Print keyboard name and modify Compose=Alt on user's request. */ switch (lk->id[4]) { - case 1: - strlcpy (lk->name, "DEC LK201 keyboard", - sizeof (lk->name)); + case 1: + strlcpy(lk->name, "DEC LK201 keyboard", sizeof(lk->name)); - if (lk201_compose_is_alt) - lk->keycode[0xb1] = KEY_LEFTALT; - break; + if (lk201_compose_is_alt) + lk->keycode[0xb1] = KEY_LEFTALT; + break; - case 2: - strlcpy (lk->name, "DEC LK401 keyboard", - sizeof (lk->name)); - break; + case 2: + strlcpy(lk->name, "DEC LK401 keyboard", sizeof(lk->name)); + break; - default: - strlcpy (lk->name, "Unknown DEC keyboard", - sizeof (lk->name)); - printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " - "please report to Jan-Benedict Glaw " - "\n", lk->phys); - printk (KERN_ERR "lkkbd: keyboard ID'ed as:"); - for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) - printk (" 0x%02x", lk->id[i]); - printk ("\n"); - break; + default: + strlcpy(lk->name, "Unknown DEC keyboard", sizeof(lk->name)); + printk(KERN_ERR + "lkkbd: keyboard on %s is unknown, please report to " + "Jan-Benedict Glaw \n", lk->phys); + printk(KERN_ERR "lkkbd: keyboard ID'ed as:"); + for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) + printk(" 0x%02x", lk->id[i]); + printk("\n"); + break; } - printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n", - lk->phys, lk->name); + + printk(KERN_INFO "lkkbd: keyboard on %s identified as: %s\n", + lk->phys, lk->name); /* * Report errors during keyboard boot-up. */ switch (lk->id[2]) { - case 0x00: - /* All okay */ - break; + case 0x00: + /* All okay */ + break; - case LK_STUCK_KEY: - printk (KERN_ERR "lkkbd: Stuck key on keyboard at " - "%s\n", lk->phys); - break; + case LK_STUCK_KEY: + printk(KERN_ERR "lkkbd: Stuck key on keyboard at %s\n", + lk->phys); + break; - case LK_SELFTEST_FAILED: - printk (KERN_ERR "lkkbd: Selftest failed on keyboard " - "at %s, keyboard may not work " - "properly\n", lk->phys); - break; + case LK_SELFTEST_FAILED: + printk(KERN_ERR + "lkkbd: Selftest failed on keyboard at %s, " + "keyboard may not work properly\n", lk->phys); + break; - default: - printk (KERN_ERR "lkkbd: Unknown error %02x on " - "keyboard at %s\n", lk->id[2], - lk->phys); - break; + default: + printk(KERN_ERR + "lkkbd: Unknown error %02x on keyboard at %s\n", + lk->id[2], lk->phys); + break; } /* * Try to hint user if there's a stuck key. */ if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0) - printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode " - "is 0x%04x\n", lk->id[3], - lk->keycode[lk->id[3]]); - - return; + printk(KERN_ERR + "Scancode of stuck key is 0x%02x, keycode is 0x%04x\n", + lk->id[3], lk->keycode[lk->id[3]]); } /* * lkkbd_interrupt() is called by the low level driver when a character * is received. */ -static irqreturn_t -lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags) +static irqreturn_t lkkbd_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) { - struct lkkbd *lk = serio_get_drvdata (serio); + struct lkkbd *lk = serio_get_drvdata(serio); + struct input_dev *input_dev = lk->dev; + unsigned int keycode; int i; - DBG (KERN_INFO "Got byte 0x%02x\n", data); + DBG(KERN_INFO "Got byte 0x%02x\n", data); if (lk->ignore_bytes > 0) { - DBG (KERN_INFO "Ignoring a byte on %s\n", lk->name); + DBG(KERN_INFO "Ignoring a byte on %s\n", lk->name); lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; if (lk->ignore_bytes == 0) - lkkbd_detection_done (lk); + lkkbd_detection_done(lk); return IRQ_HANDLED; } switch (data) { - case LK_ALL_KEYS_UP: - for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) - if (lk->keycode[i] != KEY_RESERVED) - input_report_key (lk->dev, lk->keycode[i], 0); - input_sync (lk->dev); - break; + case LK_ALL_KEYS_UP: + for (i = 0; i < ARRAY_SIZE(lkkbd_keycode); i++) + input_report_key(input_dev, lk->keycode[i], 0); + input_sync(input_dev); + break; - case 0x01: - DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); - lk->ignore_bytes = LK_NUM_IGNORE_BYTES; - lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; - schedule_work (&lk->tq); - break; + case 0x01: + DBG(KERN_INFO "Got 0x01, scheduling re-initialization\n"); + lk->ignore_bytes = LK_NUM_IGNORE_BYTES; + lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; + schedule_work(&lk->tq); + break; - case LK_METRONOME: - case LK_OUTPUT_ERROR: - case LK_INPUT_ERROR: - case LK_KBD_LOCKED: - case LK_KBD_TEST_MODE_ACK: - case LK_PREFIX_KEY_DOWN: - case LK_MODE_CHANGE_ACK: - case LK_RESPONSE_RESERVED: - DBG (KERN_INFO "Got %s and don't know how to handle...\n", - response_name (data)); - break; + case LK_METRONOME: + case LK_OUTPUT_ERROR: + case LK_INPUT_ERROR: + case LK_KBD_LOCKED: + case LK_KBD_TEST_MODE_ACK: + case LK_PREFIX_KEY_DOWN: + case LK_MODE_CHANGE_ACK: + case LK_RESPONSE_RESERVED: + DBG(KERN_INFO "Got %s and don't know how to handle...\n", + response_name(data)); + break; - default: - if (lk->keycode[data] != KEY_RESERVED) { - if (!test_bit (lk->keycode[data], lk->dev->key)) - input_report_key (lk->dev, lk->keycode[data], 1); - else - input_report_key (lk->dev, lk->keycode[data], 0); - input_sync (lk->dev); - } else - printk (KERN_WARNING "%s: Unknown key with " - "scancode 0x%02x on %s.\n", - __FILE__, data, lk->name); + default: + keycode = lk->keycode[data]; + if (keycode != KEY_RESERVED) { + input_report_key(input_dev, keycode, + !test_bit(keycode, input_dev->key)); + input_sync(input_dev); + } else { + printk(KERN_WARNING + "%s: Unknown key with scancode 0x%02x on %s.\n", + __FILE__, data, lk->name); + } } return IRQ_HANDLED; } -/* - * lkkbd_event() handles events from the input module. - */ -static int -lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, - int value) +static void lkkbd_toggle_leds(struct lkkbd *lk) { - struct lkkbd *lk = input_get_drvdata (dev); + struct serio *serio = lk->serio; unsigned char leds_on = 0; unsigned char leds_off = 0; + CHECK_LED(lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); + CHECK_LED(lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); + CHECK_LED(lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); + CHECK_LED(lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); + if (leds_on != 0) { + serio_write(serio, LK_CMD_LED_ON); + serio_write(serio, leds_on); + } + if (leds_off != 0) { + serio_write(serio, LK_CMD_LED_OFF); + serio_write(serio, leds_off); + } +} + +static void lkkbd_toggle_keyclick(struct lkkbd *lk, bool on) +{ + struct serio *serio = lk->serio; + + if (on) { + DBG("%s: Activating key clicks\n", __func__); + serio_write(serio, LK_CMD_ENABLE_KEYCLICK); + serio_write(serio, volume_to_hw(lk->keyclick_volume)); + serio_write(serio, LK_CMD_ENABLE_CTRCLICK); + serio_write(serio, volume_to_hw(lk->ctrlclick_volume)); + } else { + DBG("%s: Deactivating key clicks\n", __func__); + serio_write(serio, LK_CMD_DISABLE_KEYCLICK); + serio_write(serio, LK_CMD_DISABLE_CTRCLICK); + } + +} + +/* + * lkkbd_event() handles events from the input module. + */ +static int lkkbd_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) +{ + struct lkkbd *lk = input_get_drvdata(dev); + switch (type) { - case EV_LED: - CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); - CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); - CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); - CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); - if (leds_on != 0) { - serio_write (lk->serio, LK_CMD_LED_ON); - serio_write (lk->serio, leds_on); - } - if (leds_off != 0) { - serio_write (lk->serio, LK_CMD_LED_OFF); - serio_write (lk->serio, leds_off); - } + case EV_LED: + lkkbd_toggle_leds(lk); + return 0; + + case EV_SND: + switch (code) { + case SND_CLICK: + lkkbd_toggle_keyclick(lk, value); return 0; - case EV_SND: - switch (code) { - case SND_CLICK: - if (value == 0) { - DBG ("%s: Deactivating key clicks\n", __func__); - serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK); - serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK); - } else { - DBG ("%s: Activating key clicks\n", __func__); - serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK); - serio_write (lk->serio, volume_to_hw (lk->keyclick_volume)); - serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK); - serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); - } - return 0; + case SND_BELL: + if (value != 0) + serio_write(lk->serio, LK_CMD_SOUND_BELL); - case SND_BELL: - if (value != 0) - serio_write (lk->serio, LK_CMD_SOUND_BELL); + return 0; + } - return 0; - } - break; + break; - default: - printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n", - __func__, type, code, value); + default: + printk(KERN_ERR "%s(): Got unknown type %d, code %d, value %d\n", + __func__, type, code, value); } return -1; @@ -570,79 +576,56 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, * lkkbd_reinit() sets leds and beeps to a state the computer remembers they * were in. */ -static void -lkkbd_reinit (struct work_struct *work) +static void lkkbd_reinit(struct work_struct *work) { struct lkkbd *lk = container_of(work, struct lkkbd, tq); int division; - unsigned char leds_on = 0; - unsigned char leds_off = 0; /* Ask for ID */ - serio_write (lk->serio, LK_CMD_REQUEST_ID); + serio_write(lk->serio, LK_CMD_REQUEST_ID); /* Reset parameters */ - serio_write (lk->serio, LK_CMD_SET_DEFAULTS); + serio_write(lk->serio, LK_CMD_SET_DEFAULTS); /* Set LEDs */ - CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); - CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); - CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); - CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); - if (leds_on != 0) { - serio_write (lk->serio, LK_CMD_LED_ON); - serio_write (lk->serio, leds_on); - } - if (leds_off != 0) { - serio_write (lk->serio, LK_CMD_LED_OFF); - serio_write (lk->serio, leds_off); - } + lkkbd_toggle_leds(lk); /* * Try to activate extended LK401 mode. This command will * only work with a LK401 keyboard and grants access to * LAlt, RAlt, RCompose and RShift. */ - serio_write (lk->serio, LK_CMD_ENABLE_LK401); + serio_write(lk->serio, LK_CMD_ENABLE_LK401); /* Set all keys to UPDOWN mode */ for (division = 1; division <= 14; division++) - serio_write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, - division)); + serio_write(lk->serio, + LK_CMD_SET_MODE(LK_MODE_UPDOWN, division)); /* Enable bell and set volume */ - serio_write (lk->serio, LK_CMD_ENABLE_BELL); - serio_write (lk->serio, volume_to_hw (lk->bell_volume)); + serio_write(lk->serio, LK_CMD_ENABLE_BELL); + serio_write(lk->serio, volume_to_hw(lk->bell_volume)); /* Enable/disable keyclick (and possibly set volume) */ - if (test_bit (SND_CLICK, lk->dev->snd)) { - serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK); - serio_write (lk->serio, volume_to_hw (lk->keyclick_volume)); - serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK); - serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); - } else { - serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK); - serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK); - } + lkkbd_toggle_keyclick(lk, test_bit(SND_CLICK, lk->dev->snd)); /* Sound the bell if needed */ - if (test_bit (SND_BELL, lk->dev->snd)) - serio_write (lk->serio, LK_CMD_SOUND_BELL); + if (test_bit(SND_BELL, lk->dev->snd)) + serio_write(lk->serio, LK_CMD_SOUND_BELL); } /* * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. */ -static int -lkkbd_connect (struct serio *serio, struct serio_driver *drv) +static int lkkbd_connect(struct serio *serio, struct serio_driver *drv) { struct lkkbd *lk; struct input_dev *input_dev; int i; int err; - lk = kzalloc (sizeof (struct lkkbd), GFP_KERNEL); - input_dev = input_allocate_device (); + lk = kzalloc(sizeof(struct lkkbd), GFP_KERNEL); + input_dev = input_allocate_device(); if (!lk || !input_dev) { err = -ENOMEM; goto fail1; @@ -650,14 +633,14 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) lk->serio = serio; lk->dev = input_dev; - INIT_WORK (&lk->tq, lkkbd_reinit); + INIT_WORK(&lk->tq, lkkbd_reinit); lk->bell_volume = bell_volume; lk->keyclick_volume = keyclick_volume; lk->ctrlclick_volume = ctrlclick_volume; - memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); + memcpy(lk->keycode, lkkbd_keycode, sizeof(lk->keycode)); - strlcpy (lk->name, "DEC LK keyboard", sizeof(lk->name)); - snprintf (lk->phys, sizeof(lk->phys), "%s/input0", serio->phys); + strlcpy(lk->name, "DEC LK keyboard", sizeof(lk->name)); + snprintf(lk->phys, sizeof(lk->phys), "%s/input0", serio->phys); input_dev->name = lk->name; input_dev->phys = lk->phys; @@ -668,62 +651,61 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) input_dev->dev.parent = &serio->dev; input_dev->event = lkkbd_event; - input_set_drvdata (input_dev, lk); + input_set_drvdata(input_dev, lk); - set_bit (EV_KEY, input_dev->evbit); - set_bit (EV_LED, input_dev->evbit); - set_bit (EV_SND, input_dev->evbit); - set_bit (EV_REP, input_dev->evbit); - set_bit (LED_CAPSL, input_dev->ledbit); - set_bit (LED_SLEEP, input_dev->ledbit); - set_bit (LED_COMPOSE, input_dev->ledbit); - set_bit (LED_SCROLLL, input_dev->ledbit); - set_bit (SND_BELL, input_dev->sndbit); - set_bit (SND_CLICK, input_dev->sndbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(EV_LED, input_dev->evbit); + __set_bit(EV_SND, input_dev->evbit); + __set_bit(EV_REP, input_dev->evbit); + __set_bit(LED_CAPSL, input_dev->ledbit); + __set_bit(LED_SLEEP, input_dev->ledbit); + __set_bit(LED_COMPOSE, input_dev->ledbit); + __set_bit(LED_SCROLLL, input_dev->ledbit); + __set_bit(SND_BELL, input_dev->sndbit); + __set_bit(SND_CLICK, input_dev->sndbit); input_dev->keycode = lk->keycode; - input_dev->keycodesize = sizeof (lk_keycode_t); - input_dev->keycodemax = LK_NUM_KEYCODES; + input_dev->keycodesize = sizeof(lk->keycode[0]); + input_dev->keycodemax = ARRAY_SIZE(lk->keycode); for (i = 0; i < LK_NUM_KEYCODES; i++) - __set_bit (lk->keycode[i], input_dev->keybit); + __set_bit(lk->keycode[i], input_dev->keybit); __clear_bit(KEY_RESERVED, input_dev->keybit); - serio_set_drvdata (serio, lk); + serio_set_drvdata(serio, lk); - err = serio_open (serio, drv); + err = serio_open(serio, drv); if (err) goto fail2; - err = input_register_device (lk->dev); + err = input_register_device(lk->dev); if (err) goto fail3; - serio_write (lk->serio, LK_CMD_POWERCYCLE_RESET); + serio_write(lk->serio, LK_CMD_POWERCYCLE_RESET); return 0; - fail3: serio_close (serio); - fail2: serio_set_drvdata (serio, NULL); - fail1: input_free_device (input_dev); - kfree (lk); + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(lk); return err; } /* * lkkbd_disconnect() unregisters and closes behind us. */ -static void -lkkbd_disconnect (struct serio *serio) +static void lkkbd_disconnect(struct serio *serio) { - struct lkkbd *lk = serio_get_drvdata (serio); + struct lkkbd *lk = serio_get_drvdata(serio); - input_get_device (lk->dev); - input_unregister_device (lk->dev); - serio_close (serio); - serio_set_drvdata (serio, NULL); - input_put_device (lk->dev); - kfree (lk); + input_get_device(lk->dev); + input_unregister_device(lk->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(lk->dev); + kfree(lk); } static struct serio_device_id lkkbd_serio_ids[] = { @@ -752,18 +734,16 @@ static struct serio_driver lkkbd_drv = { /* * The functions for insering/removing us as a module. */ -static int __init -lkkbd_init (void) +static int __init lkkbd_init(void) { return serio_register_driver(&lkkbd_drv); } -static void __exit -lkkbd_exit (void) +static void __exit lkkbd_exit(void) { serio_unregister_driver(&lkkbd_drv); } -module_init (lkkbd_init); -module_exit (lkkbd_exit); +module_init(lkkbd_init); +module_exit(lkkbd_exit); From 216023255abc13ca276adfcf4ff2af111aaebc5e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 13 Oct 2009 23:37:30 -0700 Subject: [PATCH 03/51] Input: vsxxxaa - change formatting style to match the rest of the kernel - no spaces between function name and opening parenthesis - switch statements were indented too much This makes checkpatch (and me) happy. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/vsxxxaa.c | 368 ++++++++++++++++------------------ 1 file changed, 172 insertions(+), 196 deletions(-) diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index 70111443678e..bf2c0c80d6cc 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -86,27 +86,28 @@ #define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet" -MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION (DRIVER_DESC); -MODULE_LICENSE ("GPL"); +MODULE_AUTHOR("Jan-Benedict Glaw "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); #undef VSXXXAA_DEBUG #ifdef VSXXXAA_DEBUG -#define DBG(x...) printk (x) +#define DBG(x...) printk(x) #else #define DBG(x...) do {} while (0) #endif #define VSXXXAA_INTRO_MASK 0x80 #define VSXXXAA_INTRO_HEAD 0x80 -#define IS_HDR_BYTE(x) (((x) & VSXXXAA_INTRO_MASK) \ - == VSXXXAA_INTRO_HEAD) +#define IS_HDR_BYTE(x) \ + (((x) & VSXXXAA_INTRO_MASK) == VSXXXAA_INTRO_HEAD) #define VSXXXAA_PACKET_MASK 0xe0 #define VSXXXAA_PACKET_REL 0x80 #define VSXXXAA_PACKET_ABS 0xc0 #define VSXXXAA_PACKET_POR 0xa0 -#define MATCH_PACKET_TYPE(data, type) (((data) & VSXXXAA_PACKET_MASK) == (type)) +#define MATCH_PACKET_TYPE(data, type) \ + (((data) & VSXXXAA_PACKET_MASK) == (type)) @@ -123,52 +124,50 @@ struct vsxxxaa { char phys[32]; }; -static void -vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num) +static void vsxxxaa_drop_bytes(struct vsxxxaa *mouse, int num) { - if (num >= mouse->count) + if (num >= mouse->count) { mouse->count = 0; - else { - memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num); + } else { + memmove(mouse->buf, mouse->buf + num - 1, BUFLEN - num); mouse->count -= num; } } -static void -vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte) +static void vsxxxaa_queue_byte(struct vsxxxaa *mouse, unsigned char byte) { if (mouse->count == BUFLEN) { - printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", - mouse->name, mouse->phys); - vsxxxaa_drop_bytes (mouse, 1); + printk(KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", + mouse->name, mouse->phys); + vsxxxaa_drop_bytes(mouse, 1); } - DBG (KERN_INFO "Queueing byte 0x%02x\n", byte); + + DBG(KERN_INFO "Queueing byte 0x%02x\n", byte); mouse->buf[mouse->count++] = byte; } -static void -vsxxxaa_detection_done (struct vsxxxaa *mouse) +static void vsxxxaa_detection_done(struct vsxxxaa *mouse) { switch (mouse->type) { - case 0x02: - strlcpy (mouse->name, "DEC VSXXX-AA/-GA mouse", - sizeof (mouse->name)); - break; + case 0x02: + strlcpy(mouse->name, "DEC VSXXX-AA/-GA mouse", + sizeof(mouse->name)); + break; - case 0x04: - strlcpy (mouse->name, "DEC VSXXX-AB digitizer", - sizeof (mouse->name)); - break; + case 0x04: + strlcpy(mouse->name, "DEC VSXXX-AB digitizer", + sizeof(mouse->name)); + break; - default: - snprintf (mouse->name, sizeof (mouse->name), - "unknown DEC pointer device (type = 0x%02x)", - mouse->type); - break; + default: + snprintf(mouse->name, sizeof(mouse->name), + "unknown DEC pointer device (type = 0x%02x)", + mouse->type); + break; } - printk (KERN_INFO + printk(KERN_INFO "Found %s version 0x%02x from country 0x%02x on port %s\n", mouse->name, mouse->version, mouse->country, mouse->phys); } @@ -176,42 +175,38 @@ vsxxxaa_detection_done (struct vsxxxaa *mouse) /* * Returns number of bytes to be dropped, 0 if packet is okay. */ -static int -vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len) +static int vsxxxaa_check_packet(struct vsxxxaa *mouse, int packet_len) { int i; /* First byte must be a header byte */ - if (!IS_HDR_BYTE (mouse->buf[0])) { - DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]); + if (!IS_HDR_BYTE(mouse->buf[0])) { + DBG("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]); return 1; } /* Check all following bytes */ - if (packet_len > 1) { - for (i = 1; i < packet_len; i++) { - if (IS_HDR_BYTE (mouse->buf[i])) { - printk (KERN_ERR "Need to drop %d bytes " - "of a broken packet.\n", - i - 1); - DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n", - packet_len, i, mouse->buf[i]); - return i - 1; - } + for (i = 1; i < packet_len; i++) { + if (IS_HDR_BYTE(mouse->buf[i])) { + printk(KERN_ERR + "Need to drop %d bytes of a broken packet.\n", + i - 1); + DBG(KERN_INFO "check: len=%d, b[%d]=0x%02x\n", + packet_len, i, mouse->buf[i]); + return i - 1; } } return 0; } -static __inline__ int -vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len) +static inline int vsxxxaa_smells_like_packet(struct vsxxxaa *mouse, + unsigned char type, size_t len) { - return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type); + return mouse->count >= len && MATCH_PACKET_TYPE(mouse->buf[0], type); } -static void -vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse) +static void vsxxxaa_handle_REL_packet(struct vsxxxaa *mouse) { struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; @@ -232,43 +227,42 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse) * 0, bit 4 of byte 0 is direction. */ dx = buf[1] & 0x7f; - dx *= ((buf[0] >> 4) & 0x01)? 1: -1; + dx *= ((buf[0] >> 4) & 0x01) ? 1 : -1; /* * Low 7 bit of byte 2 are abs(dy), bit 7 is * 0, bit 3 of byte 0 is direction. */ dy = buf[2] & 0x7f; - dy *= ((buf[0] >> 3) & 0x01)? -1: 1; + dy *= ((buf[0] >> 3) & 0x01) ? -1 : 1; /* * Get button state. It's the low three bits * (for three buttons) of byte 0. */ - left = (buf[0] & 0x04)? 1: 0; - middle = (buf[0] & 0x02)? 1: 0; - right = (buf[0] & 0x01)? 1: 0; + left = buf[0] & 0x04; + middle = buf[0] & 0x02; + right = buf[0] & 0x01; - vsxxxaa_drop_bytes (mouse, 3); + vsxxxaa_drop_bytes(mouse, 3); - DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n", - mouse->name, mouse->phys, dx, dy, - left? "L": "l", middle? "M": "m", right? "R": "r"); + DBG(KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n", + mouse->name, mouse->phys, dx, dy, + left ? "L" : "l", middle ? "M" : "m", right ? "R" : "r"); /* * Report what we've found so far... */ - input_report_key (dev, BTN_LEFT, left); - input_report_key (dev, BTN_MIDDLE, middle); - input_report_key (dev, BTN_RIGHT, right); - input_report_key (dev, BTN_TOUCH, 0); - input_report_rel (dev, REL_X, dx); - input_report_rel (dev, REL_Y, dy); - input_sync (dev); + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_MIDDLE, middle); + input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_TOUCH, 0); + input_report_rel(dev, REL_X, dx); + input_report_rel(dev, REL_Y, dy); + input_sync(dev); } -static void -vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse) +static void vsxxxaa_handle_ABS_packet(struct vsxxxaa *mouse) { struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; @@ -296,32 +290,31 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse) /* * Get button state. It's bits <4..1> of byte 0. */ - left = (buf[0] & 0x02)? 1: 0; - middle = (buf[0] & 0x04)? 1: 0; - right = (buf[0] & 0x08)? 1: 0; - touch = (buf[0] & 0x10)? 1: 0; + left = buf[0] & 0x02; + middle = buf[0] & 0x04; + right = buf[0] & 0x08; + touch = buf[0] & 0x10; - vsxxxaa_drop_bytes (mouse, 5); + vsxxxaa_drop_bytes(mouse, 5); - DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n", - mouse->name, mouse->phys, x, y, - left? "L": "l", middle? "M": "m", - right? "R": "r", touch? "T": "t"); + DBG(KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n", + mouse->name, mouse->phys, x, y, + left ? "L" : "l", middle ? "M" : "m", + right ? "R" : "r", touch ? "T" : "t"); /* * Report what we've found so far... */ - input_report_key (dev, BTN_LEFT, left); - input_report_key (dev, BTN_MIDDLE, middle); - input_report_key (dev, BTN_RIGHT, right); - input_report_key (dev, BTN_TOUCH, touch); - input_report_abs (dev, ABS_X, x); - input_report_abs (dev, ABS_Y, y); - input_sync (dev); + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_MIDDLE, middle); + input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_TOUCH, touch); + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_sync(dev); } -static void -vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) +static void vsxxxaa_handle_POR_packet(struct vsxxxaa *mouse) { struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; @@ -356,24 +349,24 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) * (for three buttons) of byte 0. Maybe even the bit <3> * has some meaning if a tablet is attached. */ - left = (buf[0] & 0x04)? 1: 0; - middle = (buf[0] & 0x02)? 1: 0; - right = (buf[0] & 0x01)? 1: 0; + left = buf[0] & 0x04; + middle = buf[0] & 0x02; + right = buf[0] & 0x01; - vsxxxaa_drop_bytes (mouse, 4); - vsxxxaa_detection_done (mouse); + vsxxxaa_drop_bytes(mouse, 4); + vsxxxaa_detection_done(mouse); if (error <= 0x1f) { /* No (serious) error. Report buttons */ - input_report_key (dev, BTN_LEFT, left); - input_report_key (dev, BTN_MIDDLE, middle); - input_report_key (dev, BTN_RIGHT, right); - input_report_key (dev, BTN_TOUCH, 0); - input_sync (dev); + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_MIDDLE, middle); + input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_TOUCH, 0); + input_sync(dev); if (error != 0) - printk (KERN_INFO "Your %s on %s reports error=0x%02x\n", - mouse->name, mouse->phys, error); + printk(KERN_INFO "Your %s on %s reports error=0x%02x\n", + mouse->name, mouse->phys, error); } @@ -381,18 +374,18 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) * If the mouse was hot-plugged, we need to force differential mode * now... However, give it a second to recover from it's reset. */ - printk (KERN_NOTICE "%s on %s: Forceing standard packet format, " - "incremental streaming mode and 72 samples/sec\n", - mouse->name, mouse->phys); - serio_write (mouse->serio, 'S'); /* Standard format */ - mdelay (50); - serio_write (mouse->serio, 'R'); /* Incremental */ - mdelay (50); - serio_write (mouse->serio, 'L'); /* 72 samples/sec */ + printk(KERN_NOTICE + "%s on %s: Forcing standard packet format, " + "incremental streaming mode and 72 samples/sec\n", + mouse->name, mouse->phys); + serio_write(mouse->serio, 'S'); /* Standard format */ + mdelay(50); + serio_write(mouse->serio, 'R'); /* Incremental */ + mdelay(50); + serio_write(mouse->serio, 'L'); /* 72 samples/sec */ } -static void -vsxxxaa_parse_buffer (struct vsxxxaa *mouse) +static void vsxxxaa_parse_buffer(struct vsxxxaa *mouse) { unsigned char *buf = mouse->buf; int stray_bytes; @@ -409,122 +402,107 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse) * activity on the mouse. */ while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) { - printk (KERN_ERR "%s on %s: Dropping a byte to regain " - "sync with mouse data stream...\n", - mouse->name, mouse->phys); - vsxxxaa_drop_bytes (mouse, 1); + printk(KERN_ERR "%s on %s: Dropping a byte to regain " + "sync with mouse data stream...\n", + mouse->name, mouse->phys); + vsxxxaa_drop_bytes(mouse, 1); } /* * Check for packets we know about. */ - if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) { + if (vsxxxaa_smells_like_packet(mouse, VSXXXAA_PACKET_REL, 3)) { /* Check for broken packet */ - stray_bytes = vsxxxaa_check_packet (mouse, 3); - if (stray_bytes > 0) { - printk (KERN_ERR "Dropping %d bytes now...\n", - stray_bytes); - vsxxxaa_drop_bytes (mouse, stray_bytes); - continue; - } + stray_bytes = vsxxxaa_check_packet(mouse, 3); + if (!stray_bytes) + vsxxxaa_handle_REL_packet(mouse); - vsxxxaa_handle_REL_packet (mouse); - continue; /* More to parse? */ + } else if (vsxxxaa_smells_like_packet(mouse, + VSXXXAA_PACKET_ABS, 5)) { + /* Check for broken packet */ + stray_bytes = vsxxxaa_check_packet(mouse, 5); + if (!stray_bytes) + vsxxxaa_handle_ABS_packet(mouse); + + } else if (vsxxxaa_smells_like_packet(mouse, + VSXXXAA_PACKET_POR, 4)) { + /* Check for broken packet */ + stray_bytes = vsxxxaa_check_packet(mouse, 4); + if (!stray_bytes) + vsxxxaa_handle_POR_packet(mouse); + + } else { + break; /* No REL, ABS or POR packet found */ } - if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) { - /* Check for broken packet */ - stray_bytes = vsxxxaa_check_packet (mouse, 5); - if (stray_bytes > 0) { - printk (KERN_ERR "Dropping %d bytes now...\n", - stray_bytes); - vsxxxaa_drop_bytes (mouse, stray_bytes); - continue; - } - - vsxxxaa_handle_ABS_packet (mouse); - continue; /* More to parse? */ + if (stray_bytes > 0) { + printk(KERN_ERR "Dropping %d bytes now...\n", + stray_bytes); + vsxxxaa_drop_bytes(mouse, stray_bytes); } - if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) { - /* Check for broken packet */ - stray_bytes = vsxxxaa_check_packet (mouse, 4); - if (stray_bytes > 0) { - printk (KERN_ERR "Dropping %d bytes now...\n", - stray_bytes); - vsxxxaa_drop_bytes (mouse, stray_bytes); - continue; - } - - vsxxxaa_handle_POR_packet (mouse); - continue; /* More to parse? */ - } - - break; /* No REL, ABS or POR packet found */ } while (1); } -static irqreturn_t -vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags) +static irqreturn_t vsxxxaa_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) { - struct vsxxxaa *mouse = serio_get_drvdata (serio); + struct vsxxxaa *mouse = serio_get_drvdata(serio); - vsxxxaa_queue_byte (mouse, data); - vsxxxaa_parse_buffer (mouse); + vsxxxaa_queue_byte(mouse, data); + vsxxxaa_parse_buffer(mouse); return IRQ_HANDLED; } -static void -vsxxxaa_disconnect (struct serio *serio) +static void vsxxxaa_disconnect(struct serio *serio) { - struct vsxxxaa *mouse = serio_get_drvdata (serio); + struct vsxxxaa *mouse = serio_get_drvdata(serio); - serio_close (serio); - serio_set_drvdata (serio, NULL); - input_unregister_device (mouse->dev); - kfree (mouse); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_unregister_device(mouse->dev); + kfree(mouse); } -static int -vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) +static int vsxxxaa_connect(struct serio *serio, struct serio_driver *drv) { struct vsxxxaa *mouse; struct input_dev *input_dev; int err = -ENOMEM; - mouse = kzalloc (sizeof (struct vsxxxaa), GFP_KERNEL); - input_dev = input_allocate_device (); + mouse = kzalloc(sizeof(struct vsxxxaa), GFP_KERNEL); + input_dev = input_allocate_device(); if (!mouse || !input_dev) goto fail1; mouse->dev = input_dev; mouse->serio = serio; - strlcat (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer", - sizeof (mouse->name)); - snprintf (mouse->phys, sizeof (mouse->phys), "%s/input0", serio->phys); + strlcat(mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer", + sizeof(mouse->name)); + snprintf(mouse->phys, sizeof(mouse->phys), "%s/input0", serio->phys); input_dev->name = mouse->name; input_dev->phys = mouse->phys; input_dev->id.bustype = BUS_RS232; input_dev->dev.parent = &serio->dev; - set_bit (EV_KEY, input_dev->evbit); /* We have buttons */ - set_bit (EV_REL, input_dev->evbit); - set_bit (EV_ABS, input_dev->evbit); - set_bit (BTN_LEFT, input_dev->keybit); /* We have 3 buttons */ - set_bit (BTN_MIDDLE, input_dev->keybit); - set_bit (BTN_RIGHT, input_dev->keybit); - set_bit (BTN_TOUCH, input_dev->keybit); /* ...and Tablet */ - set_bit (REL_X, input_dev->relbit); - set_bit (REL_Y, input_dev->relbit); - input_set_abs_params (input_dev, ABS_X, 0, 1023, 0, 0); - input_set_abs_params (input_dev, ABS_Y, 0, 1023, 0, 0); + __set_bit(EV_KEY, input_dev->evbit); /* We have buttons */ + __set_bit(EV_REL, input_dev->evbit); + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(BTN_LEFT, input_dev->keybit); /* We have 3 buttons */ + __set_bit(BTN_MIDDLE, input_dev->keybit); + __set_bit(BTN_RIGHT, input_dev->keybit); + __set_bit(BTN_TOUCH, input_dev->keybit); /* ...and Tablet */ + __set_bit(REL_X, input_dev->relbit); + __set_bit(REL_Y, input_dev->relbit); + input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0); - serio_set_drvdata (serio, mouse); + serio_set_drvdata(serio, mouse); - err = serio_open (serio, drv); + err = serio_open(serio, drv); if (err) goto fail2; @@ -532,18 +510,18 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) * Request selftest. Standard packet format and differential * mode will be requested after the device ID'ed successfully. */ - serio_write (serio, 'T'); /* Test */ + serio_write(serio, 'T'); /* Test */ - err = input_register_device (input_dev); + err = input_register_device(input_dev); if (err) goto fail3; return 0; - fail3: serio_close (serio); - fail2: serio_set_drvdata (serio, NULL); - fail1: input_free_device (input_dev); - kfree (mouse); + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(mouse); return err; } @@ -570,18 +548,16 @@ static struct serio_driver vsxxxaa_drv = { .disconnect = vsxxxaa_disconnect, }; -static int __init -vsxxxaa_init (void) +static int __init vsxxxaa_init(void) { return serio_register_driver(&vsxxxaa_drv); } -static void __exit -vsxxxaa_exit (void) +static void __exit vsxxxaa_exit(void) { serio_unregister_driver(&vsxxxaa_drv); } -module_init (vsxxxaa_init); -module_exit (vsxxxaa_exit); +module_init(vsxxxaa_init); +module_exit(vsxxxaa_exit); From bc09dcadc1a3da87d58aa70ebc8e9441205be75c Mon Sep 17 00:00:00 2001 From: Miguel Aguilar Date: Tue, 13 Oct 2009 23:37:32 -0700 Subject: [PATCH 04/51] Input: add DaVinci Keypad Driver This driver enables keypad support on DaVinci platforms. DM365 is the only platform that uses this driver at the moment. Signed-off-by: Miguel Aguilar Signed-off-by: Dmitry Torokhov --- arch/arm/mach-davinci/include/mach/keyscan.h | 41 +++ drivers/input/keyboard/Kconfig | 10 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/davinci_keyscan.c | 337 +++++++++++++++++++ 4 files changed, 389 insertions(+) create mode 100644 arch/arm/mach-davinci/include/mach/keyscan.h create mode 100644 drivers/input/keyboard/davinci_keyscan.c diff --git a/arch/arm/mach-davinci/include/mach/keyscan.h b/arch/arm/mach-davinci/include/mach/keyscan.h new file mode 100644 index 000000000000..b4e21a2976d1 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/keyscan.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009 Texas Instruments, Inc + * + * Author: Miguel Aguilar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DAVINCI_KEYSCAN_H +#define DAVINCI_KEYSCAN_H + +#include + +enum davinci_matrix_types { + DAVINCI_KEYSCAN_MATRIX_4X4, + DAVINCI_KEYSCAN_MATRIX_5X3, +}; + +struct davinci_ks_platform_data { + unsigned short *keymap; + u32 keymapsize; + u8 rep:1; + u8 strobe; + u8 interval; + u8 matrix_type; +}; + +#endif + diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index ee98b1bc5d89..203b88a82b56 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -361,6 +361,16 @@ config KEYBOARD_SH_KEYSC To compile this driver as a module, choose M here: the module will be called sh_keysc. +config KEYBOARD_DAVINCI + tristate "TI DaVinci Key Scan" + depends on ARCH_DAVINCI_DM365 + help + Say Y to enable keypad module support for the TI DaVinci + platforms (DM365). + + To compile this driver as a module, choose M here: the + module will be called davinci_keyscan. + config KEYBOARD_OMAP tristate "TI OMAP keypad support" depends on (ARCH_OMAP1 || ARCH_OMAP2) diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index babad5e58b77..68c017235ce9 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o +obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c new file mode 100644 index 000000000000..6e52d855f637 --- /dev/null +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -0,0 +1,337 @@ +/* + * DaVinci Key Scan Driver for TI platforms + * + * Copyright (C) 2009 Texas Instruments, Inc + * + * Author: Miguel Aguilar + * + * Intial Code: Sandeep Paulraj + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +/* Key scan registers */ +#define DAVINCI_KEYSCAN_KEYCTRL 0x0000 +#define DAVINCI_KEYSCAN_INTENA 0x0004 +#define DAVINCI_KEYSCAN_INTFLAG 0x0008 +#define DAVINCI_KEYSCAN_INTCLR 0x000c +#define DAVINCI_KEYSCAN_STRBWIDTH 0x0010 +#define DAVINCI_KEYSCAN_INTERVAL 0x0014 +#define DAVINCI_KEYSCAN_CONTTIME 0x0018 +#define DAVINCI_KEYSCAN_CURRENTST 0x001c +#define DAVINCI_KEYSCAN_PREVSTATE 0x0020 +#define DAVINCI_KEYSCAN_EMUCTRL 0x0024 +#define DAVINCI_KEYSCAN_IODFTCTRL 0x002c + +/* Key Control Register (KEYCTRL) */ +#define DAVINCI_KEYSCAN_KEYEN 0x00000001 +#define DAVINCI_KEYSCAN_PREVMODE 0x00000002 +#define DAVINCI_KEYSCAN_CHATOFF 0x00000004 +#define DAVINCI_KEYSCAN_AUTODET 0x00000008 +#define DAVINCI_KEYSCAN_SCANMODE 0x00000010 +#define DAVINCI_KEYSCAN_OUTTYPE 0x00000020 + +/* Masks for the interrupts */ +#define DAVINCI_KEYSCAN_INT_CONT 0x00000008 +#define DAVINCI_KEYSCAN_INT_OFF 0x00000004 +#define DAVINCI_KEYSCAN_INT_ON 0x00000002 +#define DAVINCI_KEYSCAN_INT_CHANGE 0x00000001 +#define DAVINCI_KEYSCAN_INT_ALL 0x0000000f + +struct davinci_ks { + struct input_dev *input; + struct davinci_ks_platform_data *pdata; + int irq; + void __iomem *base; + resource_size_t pbase; + size_t base_size; + unsigned short keymap[]; +}; + +/* Initializing the kp Module */ +static int __init davinci_ks_initialize(struct davinci_ks *davinci_ks) +{ + struct device *dev = &davinci_ks->input->dev; + struct davinci_ks_platform_data *pdata = davinci_ks->pdata; + u32 matrix_ctrl; + + /* Enable all interrupts */ + __raw_writel(DAVINCI_KEYSCAN_INT_ALL, + davinci_ks->base + DAVINCI_KEYSCAN_INTENA); + + /* Clear interrupts if any */ + __raw_writel(DAVINCI_KEYSCAN_INT_ALL, + davinci_ks->base + DAVINCI_KEYSCAN_INTCLR); + + /* Setup the scan period = strobe + interval */ + __raw_writel(pdata->strobe, + davinci_ks->base + DAVINCI_KEYSCAN_STRBWIDTH); + __raw_writel(pdata->interval, + davinci_ks->base + DAVINCI_KEYSCAN_INTERVAL); + __raw_writel(0x01, + davinci_ks->base + DAVINCI_KEYSCAN_CONTTIME); + + /* Define matrix type */ + switch (pdata->matrix_type) { + case DAVINCI_KEYSCAN_MATRIX_4X4: + matrix_ctrl = 0; + break; + case DAVINCI_KEYSCAN_MATRIX_5X3: + matrix_ctrl = (1 << 6); + break; + default: + dev_err(dev->parent, "wrong matrix type\n"); + return -EINVAL; + } + + /* Enable key scan module and set matrix type */ + __raw_writel(DAVINCI_KEYSCAN_AUTODET | DAVINCI_KEYSCAN_KEYEN | + matrix_ctrl, davinci_ks->base + DAVINCI_KEYSCAN_KEYCTRL); + + return 0; +} + +static irqreturn_t davinci_ks_interrupt(int irq, void *dev_id) +{ + struct davinci_ks *davinci_ks = dev_id; + struct device *dev = &davinci_ks->input->dev; + unsigned short *keymap = davinci_ks->keymap; + int keymapsize = davinci_ks->pdata->keymapsize; + u32 prev_status, new_status, changed; + bool release; + int keycode = KEY_UNKNOWN; + int i; + + /* Disable interrupt */ + __raw_writel(0x0, davinci_ks->base + DAVINCI_KEYSCAN_INTENA); + + /* Reading previous and new status of the key scan */ + prev_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_PREVSTATE); + new_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_CURRENTST); + + changed = prev_status ^ new_status; + + if (changed) { + /* + * It goes through all bits in 'changed' to ensure + * that no key changes are being missed + */ + for (i = 0 ; i < keymapsize; i++) { + if ((changed>>i) & 0x1) { + keycode = keymap[i]; + release = (new_status >> i) & 0x1; + dev_dbg(dev->parent, "key %d %s\n", keycode, + release ? "released" : "pressed"); + input_report_key(davinci_ks->input, keycode, + !release); + input_sync(davinci_ks->input); + } + } + /* Clearing interrupt */ + __raw_writel(DAVINCI_KEYSCAN_INT_ALL, + davinci_ks->base + DAVINCI_KEYSCAN_INTCLR); + } + + /* Enable interrupts */ + __raw_writel(0x1, davinci_ks->base + DAVINCI_KEYSCAN_INTENA); + + return IRQ_HANDLED; +} + +static int __init davinci_ks_probe(struct platform_device *pdev) +{ + struct davinci_ks *davinci_ks; + struct input_dev *key_dev; + struct resource *res, *mem; + struct device *dev = &pdev->dev; + struct davinci_ks_platform_data *pdata = pdev->dev.platform_data; + int error, i; + + if (!pdata->keymap) { + dev_dbg(dev, "no keymap from pdata\n"); + return -EINVAL; + } + + davinci_ks = kzalloc(sizeof(struct davinci_ks) + + sizeof(unsigned short) * pdata->keymapsize, GFP_KERNEL); + if (!davinci_ks) { + dev_dbg(dev, "could not allocate memory for private data\n"); + return -ENOMEM; + } + + memcpy(davinci_ks->keymap, pdata->keymap, + sizeof(unsigned short) * pdata->keymapsize); + + key_dev = input_allocate_device(); + if (!key_dev) { + dev_dbg(dev, "could not allocate input device\n"); + error = -ENOMEM; + goto fail1; + } + + davinci_ks->input = key_dev; + + davinci_ks->irq = platform_get_irq(pdev, 0); + if (davinci_ks->irq < 0) { + dev_err(dev, "no key scan irq\n"); + error = davinci_ks->irq; + goto fail2; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no mem resource\n"); + error = -EINVAL; + goto fail2; + } + + davinci_ks->pbase = res->start; + davinci_ks->base_size = resource_size(res); + + mem = request_mem_region(davinci_ks->pbase, davinci_ks->base_size, + pdev->name); + if (!mem) { + dev_err(dev, "key scan registers at %08x are not free\n", + davinci_ks->pbase); + error = -EBUSY; + goto fail2; + } + + davinci_ks->base = ioremap(davinci_ks->pbase, davinci_ks->base_size); + if (!davinci_ks->base) { + dev_err(dev, "can't ioremap MEM resource.\n"); + error = -ENOMEM; + goto fail3; + } + + /* Enable auto repeat feature of Linux input subsystem */ + if (pdata->rep) + __set_bit(EV_REP, key_dev->evbit); + + /* Setup input device */ + __set_bit(EV_KEY, key_dev->evbit); + + /* Setup the platform data */ + davinci_ks->pdata = pdata; + + for (i = 0; i < davinci_ks->pdata->keymapsize; i++) + __set_bit(davinci_ks->pdata->keymap[i], key_dev->keybit); + + key_dev->name = "davinci_keyscan"; + key_dev->phys = "davinci_keyscan/input0"; + key_dev->dev.parent = &pdev->dev; + key_dev->id.bustype = BUS_HOST; + key_dev->id.vendor = 0x0001; + key_dev->id.product = 0x0001; + key_dev->id.version = 0x0001; + key_dev->keycode = davinci_ks->keymap; + key_dev->keycodesize = sizeof(davinci_ks->keymap[0]); + key_dev->keycodemax = davinci_ks->pdata->keymapsize; + + error = input_register_device(davinci_ks->input); + if (error < 0) { + dev_err(dev, "unable to register davinci key scan device\n"); + goto fail4; + } + + error = request_irq(davinci_ks->irq, davinci_ks_interrupt, + IRQF_DISABLED, pdev->name, davinci_ks); + if (error < 0) { + dev_err(dev, "unable to register davinci key scan interrupt\n"); + goto fail5; + } + + error = davinci_ks_initialize(davinci_ks); + if (error < 0) { + dev_err(dev, "unable to initialize davinci key scan device\n"); + goto fail6; + } + + platform_set_drvdata(pdev, davinci_ks); + return 0; + +fail6: + free_irq(davinci_ks->irq, davinci_ks); +fail5: + input_unregister_device(davinci_ks->input); + key_dev = NULL; +fail4: + iounmap(davinci_ks->base); +fail3: + release_mem_region(davinci_ks->pbase, davinci_ks->base_size); +fail2: + input_free_device(key_dev); +fail1: + kfree(davinci_ks); + + return error; +} + +static int __devexit davinci_ks_remove(struct platform_device *pdev) +{ + struct davinci_ks *davinci_ks = platform_get_drvdata(pdev); + + free_irq(davinci_ks->irq, davinci_ks); + + input_unregister_device(davinci_ks->input); + + iounmap(davinci_ks->base); + release_mem_region(davinci_ks->pbase, davinci_ks->base_size); + + platform_set_drvdata(pdev, NULL); + + kfree(davinci_ks); + + return 0; +} + +static struct platform_driver davinci_ks_driver = { + .driver = { + .name = "davinci_keyscan", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(davinci_ks_remove), +}; + +static int __init davinci_ks_init(void) +{ + return platform_driver_probe(&davinci_ks_driver, davinci_ks_probe); +} +module_init(davinci_ks_init); + +static void __exit davinci_ks_exit(void) +{ + platform_driver_unregister(&davinci_ks_driver); +} +module_exit(davinci_ks_exit); + +MODULE_AUTHOR("Miguel Aguilar"); +MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver"); +MODULE_LICENSE("GPL"); From b0aba1e66c38d64be2c7dbf4b08c71857031ab67 Mon Sep 17 00:00:00 2001 From: Samu Onkalo Date: Sun, 18 Oct 2009 00:38:57 -0700 Subject: [PATCH 05/51] Input: add open and close methods for polled devices Optional open and close methods for preparing and closing the device. Signed-off-by: Samu Onkalo Signed-off-by: Dmitry Torokhov --- drivers/input/input-polldev.c | 7 +++++-- drivers/input/misc/wistron_btns.c | 2 +- include/linux/input-polldev.h | 11 +++++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 0d3ce7a50fb1..910220c127cb 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -80,8 +80,8 @@ static int input_open_polled_device(struct input_dev *input) if (error) return error; - if (dev->flush) - dev->flush(dev); + if (dev->open) + dev->open(dev); queue_delayed_work(polldev_wq, &dev->work, msecs_to_jiffies(dev->poll_interval)); @@ -95,6 +95,9 @@ static void input_close_polled_device(struct input_dev *input) cancel_delayed_work_sync(&dev->work); input_polldev_stop_workqueue(); + + if (dev->close) + dev->close(dev); } /** diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index a932179c4c9e..00eb9d651d97 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -1263,7 +1263,7 @@ static int __devinit setup_input_dev(void) if (!wistron_idev) return -ENOMEM; - wistron_idev->flush = wistron_flush; + wistron_idev->open = wistron_flush; wistron_idev->poll = wistron_poll; wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT; diff --git a/include/linux/input-polldev.h b/include/linux/input-polldev.h index 597a0077b3c5..5c0ec68a965e 100644 --- a/include/linux/input-polldev.h +++ b/include/linux/input-polldev.h @@ -14,9 +14,11 @@ /** * struct input_polled_dev - simple polled input device - * @private: private driver data - * @flush: driver-supplied method that flushes device's state upon - * opening (optional) + * @private: private driver data. + * @open: driver-supplied method that prepares device for polling + * (enabled the device and maybe flushes device state). + * @close: driver-supplied method that is called when device is no + * longer being polled. Used to put device into low power mode. * @poll: driver-supplied method that polls the device and posts * input events (mandatory). * @poll_interval: specifies how often the poll() method shoudl be called. @@ -30,7 +32,8 @@ struct input_polled_dev { void *private; - void (*flush)(struct input_polled_dev *dev); + void (*open)(struct input_polled_dev *dev); + void (*close)(struct input_polled_dev *dev); void (*poll)(struct input_polled_dev *dev); unsigned int poll_interval; /* msec */ From a5f523bc0cdee2a163a034344ebf1163799b3c5d Mon Sep 17 00:00:00 2001 From: Tias Guns Date: Sun, 25 Oct 2009 12:13:58 -0700 Subject: [PATCH 06/51] Input: add driver for Dynapro serial touchscreen This is a driver for Dynapro serial touchscreen, which used to be supported in Xorg. The driver needs updated inputattach utility to initialize serial port and create proper serio device before the driver will be bound to it. Signed-off-by: Tias Guns Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 ++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/dynapro.c | 206 ++++++++++++++++++++++++++++ include/linux/serio.h | 1 + 4 files changed, 220 insertions(+) create mode 100644 drivers/input/touchscreen/dynapro.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 8cc453c85ea7..1cd9e8c8efb3 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -111,6 +111,18 @@ config TOUCHSCREEN_DA9034 Say Y here to enable the support for the touchscreen found on Dialog Semiconductor DA9034 PMIC. +config TOUCHSCREEN_DYNAPRO + tristate "Dynapro serial touchscreen" + select SERIO + help + Say Y here if you have a Dynapro serial touchscreen connected to + your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called dynapro. + config TOUCHSCREEN_EETI tristate "EETI touchscreen panel support" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 15fa62cffc77..1f5cccd3a16a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o +obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c new file mode 100644 index 000000000000..455353908bdf --- /dev/null +++ b/drivers/input/touchscreen/dynapro.c @@ -0,0 +1,206 @@ +/* + * Dynapro serial touchscreen driver + * + * Copyright (c) 2009 Tias Guns + * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and + * Richard Lemon + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * 2009/09/19 Tias Guns + * Copied inexio.c and edited for Dynapro protocol (from retired Xorg module) + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Dynapro serial touchscreen driver" + +MODULE_AUTHOR("Tias Guns "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define DYNAPRO_FORMAT_TOUCH_BIT 0x40 +#define DYNAPRO_FORMAT_LENGTH 3 +#define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80 + +#define DYNAPRO_MIN_XC 0 +#define DYNAPRO_MAX_XC 0x3ff +#define DYNAPRO_MIN_YC 0 +#define DYNAPRO_MAX_YC 0x3ff + +#define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4)) +#define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7)) +#define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0]) + +/* + * Per-touchscreen data. + */ + +struct dynapro { + struct input_dev *dev; + struct serio *serio; + int idx; + unsigned char data[DYNAPRO_FORMAT_LENGTH]; + char phys[32]; +}; + +static void dynapro_process_data(struct dynapro *pdynapro) +{ + struct input_dev *dev = pdynapro->dev; + + if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) { + input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data)); + input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data)); + input_report_key(dev, BTN_TOUCH, + DYNAPRO_GET_TOUCHED(pdynapro->data)); + input_sync(dev); + + pdynapro->idx = 0; + } +} + +static irqreturn_t dynapro_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) +{ + struct dynapro *pdynapro = serio_get_drvdata(serio); + + pdynapro->data[pdynapro->idx] = data; + + if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0]) + dynapro_process_data(pdynapro); + else + dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n", + pdynapro->data[0]); + + return IRQ_HANDLED; +} + +static void dynapro_disconnect(struct serio *serio) +{ + struct dynapro *pdynapro = serio_get_drvdata(serio); + + input_get_device(pdynapro->dev); + input_unregister_device(pdynapro->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(pdynapro->dev); + kfree(pdynapro); +} + +/* + * dynapro_connect() is the routine that is called when someone adds a + * new serio device that supports dynapro protocol and registers it as + * an input device. This is usually accomplished using inputattach. + */ + +static int dynapro_connect(struct serio *serio, struct serio_driver *drv) +{ + struct dynapro *pdynapro; + struct input_dev *input_dev; + int err; + + pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!pdynapro || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + pdynapro->serio = serio; + pdynapro->dev = input_dev; + snprintf(pdynapro->phys, sizeof(pdynapro->phys), + "%s/input0", serio->phys); + + input_dev->name = "Dynapro Serial TouchScreen"; + input_dev->phys = pdynapro->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_DYNAPRO; + input_dev->id.product = 0; + input_dev->id.version = 0x0001; + input_dev->dev.parent = &serio->dev; + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_abs_params(pdynapro->dev, ABS_X, + DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0); + input_set_abs_params(pdynapro->dev, ABS_Y, + DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0); + + serio_set_drvdata(serio, pdynapro); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(pdynapro->dev); + if (err) + goto fail3; + + return 0; + + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(pdynapro); + return err; +} + +/* + * The serio driver structure. + */ + +static struct serio_device_id dynapro_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_DYNAPRO, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, dynapro_serio_ids); + +static struct serio_driver dynapro_drv = { + .driver = { + .name = "dynapro", + }, + .description = DRIVER_DESC, + .id_table = dynapro_serio_ids, + .interrupt = dynapro_interrupt, + .connect = dynapro_connect, + .disconnect = dynapro_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +static int __init dynapro_init(void) +{ + return serio_register_driver(&dynapro_drv); +} + +static void __exit dynapro_exit(void) +{ + serio_unregister_driver(&dynapro_drv); +} + +module_init(dynapro_init); +module_exit(dynapro_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index a640bc2afe76..e2f3044d4a4a 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -215,5 +215,6 @@ static inline void serio_unpin_driver(struct serio *serio) #define SERIO_INEXIO 0x37 #define SERIO_TOUCHIT213 0x38 #define SERIO_W8001 0x39 +#define SERIO_DYNAPRO 0x3a #endif From e74c2e81fc9e1e674f2747c85fe8cfeaaafa55f6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 2 Nov 2009 21:57:39 -0800 Subject: [PATCH 07/51] Input: mark custom_data in ff_periodic_effect as __user The custom_data pointer in ff_periodict_effect structure is a userspace pointer and should be marked as such. Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/input.h b/include/linux/input.h index 0ccfc30cd40f..9ee67b4b2b48 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -890,7 +890,7 @@ struct ff_periodic_effect { struct ff_envelope envelope; __u32 custom_len; - __s16 *custom_data; + __s16 __user *custom_data; }; /** From f5ba35023697e54a24487bcd822194390a333893 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 2 Nov 2009 21:57:40 -0800 Subject: [PATCH 08/51] Input: synaptic_i2c - make unnecessarily global functions static Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics_i2c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 7283c78044af..9867dfe2a638 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -420,8 +420,8 @@ static void synaptics_i2c_check_params(struct synaptics_i2c *touch) } /* Control the Device polling rate / Work Handler sleep time */ -unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch, - bool have_data) +static unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch, + bool have_data) { unsigned long delay, nodata_count_thres; @@ -520,7 +520,7 @@ static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch) __set_bit(BTN_LEFT, input->keybit); } -struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client) +static struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client) { struct synaptics_i2c *touch; From 765af10de6d93820def9978c53ed828e4d3bd4f4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 5 Nov 2009 22:59:46 -0800 Subject: [PATCH 09/51] Input: add new keycodes useful in mobile devices Add new codes for camera focus key, and camera lens cover, keypad slide, front proximity switches. Signed-off-by: Jani Nikula Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/input.h b/include/linux/input.h index 9ee67b4b2b48..9a04e26daab2 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -595,6 +595,8 @@ struct input_absinfo { #define KEY_NUMERIC_STAR 0x20a #define KEY_NUMERIC_POUND 0x20b +#define KEY_CAMERA_FOCUS 0x210 + /* We avoid low common keys in module aliases so they don't get huge. */ #define KEY_MIN_INTERESTING KEY_MUTE #define KEY_MAX 0x2ff @@ -677,6 +679,9 @@ struct input_absinfo { #define SW_LINEOUT_INSERT 0x06 /* set = inserted */ #define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */ #define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */ +#define SW_CAMERA_LENS_COVER 0x09 /* set = lens covered */ +#define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */ +#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) From fb141597550243b471f3bd526fe689aa3b74df25 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 8 Nov 2009 19:45:54 -0800 Subject: [PATCH 10/51] Input: ucb1400_ts - allow passing IRQ through platfrom_data This patch allows UCB1400 to get IRQ GPIO from platform data. In case platform_data are not supplied or the IRQ supplied in the platform_data is negative, fall back to the old IRQ detection algorithm. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ucb1400_ts.c | 11 +++++++---- drivers/mfd/ucb1400_core.c | 7 +++++++ include/linux/ucb1400.h | 4 ++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 095f84b1f56e..89dcbe7b4b02 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -355,10 +355,13 @@ static int ucb1400_ts_probe(struct platform_device *dev) goto err; } - error = ucb1400_ts_detect_irq(ucb); - if (error) { - printk(KERN_ERR "UCB1400: IRQ probe failed\n"); - goto err_free_devs; + /* Only in case the IRQ line wasn't supplied, try detecting it */ + if (ucb->irq < 0) { + error = ucb1400_ts_detect_irq(ucb); + if (error) { + printk(KERN_ERR "UCB1400: IRQ probe failed\n"); + goto err_free_devs; + } } init_waitqueue_head(&ucb->ts_wait); diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index fa294b6d600a..85fd9421be94 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c @@ -51,6 +51,7 @@ static int ucb1400_core_probe(struct device *dev) struct ucb1400_ts ucb_ts; struct ucb1400_gpio ucb_gpio; struct snd_ac97 *ac97; + struct ucb1400_pdata *pdata = dev->platform_data; memset(&ucb_ts, 0, sizeof(ucb_ts)); memset(&ucb_gpio, 0, sizeof(ucb_gpio)); @@ -88,6 +89,12 @@ static int ucb1400_core_probe(struct device *dev) /* TOUCHSCREEN */ ucb_ts.ac97 = ac97; + + if (pdata != NULL && pdata->irq >= 0) + ucb_ts.irq = pdata->irq; + else + ucb_ts.irq = -1; + ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1); if (!ucb->ucb1400_ts) { err = -ENOMEM; diff --git a/include/linux/ucb1400.h b/include/linux/ucb1400.h index adb44066680c..1b4790911052 100644 --- a/include/linux/ucb1400.h +++ b/include/linux/ucb1400.h @@ -110,6 +110,10 @@ struct ucb1400 { struct platform_device *ucb1400_gpio; }; +struct ucb1400_pdata { + int irq; +}; + static inline u16 ucb1400_reg_read(struct snd_ac97 *ac97, u16 reg) { return ac97->bus->ops->read(ac97, reg); From db19fd8b3a3e198e84b93fa217acf77e72a4cd35 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 10 Nov 2009 21:00:35 -0800 Subject: [PATCH 11/51] Input: gpio_keys - use dev_ macros to report information The gpio_keys driver is binding to a platform device but using pr_err() to report errors. Change to using dev_err() so that all messages are prefixed by the device name. Signed-off-by: Ben Dooks Signed-off-by: Simtec Linux Team Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 77d130914259..5c8e2113cb34 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -78,6 +78,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) { struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; struct gpio_keys_drvdata *ddata; + struct device *dev = &pdev->dev; struct input_dev *input; int i, error; int wakeup = 0; @@ -87,6 +88,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) GFP_KERNEL); input = input_allocate_device(); if (!ddata || !input) { + dev_err(dev, "failed to allocate state\n"); error = -ENOMEM; goto fail1; } @@ -122,14 +124,14 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); if (error < 0) { - pr_err("gpio-keys: failed to request GPIO %d," - " error %d\n", button->gpio, error); + dev_err(dev, "failed to request GPIO %d, error %d\n", + button->gpio, error); goto fail2; } error = gpio_direction_input(button->gpio); if (error < 0) { - pr_err("gpio-keys: failed to configure input" + dev_err(dev, "failed to configure" " direction for GPIO %d, error %d\n", button->gpio, error); gpio_free(button->gpio); @@ -139,8 +141,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) irq = gpio_to_irq(button->gpio); if (irq < 0) { error = irq; - pr_err("gpio-keys: Unable to get irq number" - " for GPIO %d, error %d\n", + dev_err(dev, "Unable to get irq number " + "for GPIO %d, error %d\n", button->gpio, error); gpio_free(button->gpio); goto fail2; @@ -152,7 +154,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) button->desc ? button->desc : "gpio_keys", bdata); if (error) { - pr_err("gpio-keys: Unable to claim irq %d; error %d\n", + dev_err(dev, "Unable to claim irq %d; error %d\n", irq, error); gpio_free(button->gpio); goto fail2; @@ -166,7 +168,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) error = input_register_device(input); if (error) { - pr_err("gpio-keys: Unable to register input device, " + dev_err(dev, "Unable to register input device, " "error: %d\n", error); goto fail2; } From 111bc59c08c437e433bd5b9cc726adaa912c6e6c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 10 Nov 2009 21:01:31 -0800 Subject: [PATCH 12/51] Input: gpio_keys - use instead of The gpio keys driver should be using instead of Signed-off-by: Ben Dooks Signed-off-by: Simtec Linux Team Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 5c8e2113cb34..b236709a2c01 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -23,8 +23,7 @@ #include #include #include - -#include +#include struct gpio_button_data { struct gpio_keys_button *button; From bc8f1eaf68a8aa1d993492f1ad2d74502665f578 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 10 Nov 2009 21:01:31 -0800 Subject: [PATCH 13/51] Input: gpio_keys - seperate individual button setup to make code neater Move the code that deals with setting up each individual button out into a new function to reduce the indentation and allow us to common up some of the error recovery code. Signed-off-by: Ben Dooks Signed-off-by: Simtec Linux Team Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 93 +++++++++++++++++------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index b236709a2c01..8941a8ba89bf 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -73,6 +73,57 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static int __devinit gpio_keys_setup_key(struct device *dev, + struct gpio_button_data *bdata, + struct gpio_keys_button *button) +{ + char *desc = button->desc ? button->desc : "gpio_keys"; + int irq, error; + + setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata); + INIT_WORK(&bdata->work, gpio_keys_report_event); + + error = gpio_request(button->gpio, desc); + if (error < 0) { + dev_err(dev, "failed to request GPIO %d, error %d\n", + button->gpio, error); + goto fail2; + } + + error = gpio_direction_input(button->gpio); + if (error < 0) { + dev_err(dev, "failed to configure" + " direction for GPIO %d, error %d\n", + button->gpio, error); + goto fail3; + } + + irq = gpio_to_irq(button->gpio); + if (irq < 0) { + error = irq; + dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n", + button->gpio, error); + goto fail3; + } + + error = request_irq(irq, gpio_keys_isr, + IRQF_SHARED | + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + desc, bdata); + if (error) { + dev_err(dev, "Unable to claim irq %d; error %d\n", + irq, error); + goto fail3; + } + + return 0; + +fail3: + gpio_free(button->gpio); +fail2: + return error; +} + static int __devinit gpio_keys_probe(struct platform_device *pdev) { struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; @@ -112,52 +163,14 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_button_data *bdata = &ddata->data[i]; - int irq; unsigned int type = button->type ?: EV_KEY; bdata->input = input; bdata->button = button; - setup_timer(&bdata->timer, - gpio_keys_timer, (unsigned long)bdata); - INIT_WORK(&bdata->work, gpio_keys_report_event); - error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); - if (error < 0) { - dev_err(dev, "failed to request GPIO %d, error %d\n", - button->gpio, error); + error = gpio_keys_setup_key(dev, bdata, button); + if (error) goto fail2; - } - - error = gpio_direction_input(button->gpio); - if (error < 0) { - dev_err(dev, "failed to configure" - " direction for GPIO %d, error %d\n", - button->gpio, error); - gpio_free(button->gpio); - goto fail2; - } - - irq = gpio_to_irq(button->gpio); - if (irq < 0) { - error = irq; - dev_err(dev, "Unable to get irq number " - "for GPIO %d, error %d\n", - button->gpio, error); - gpio_free(button->gpio); - goto fail2; - } - - error = request_irq(irq, gpio_keys_isr, - IRQF_SHARED | - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - button->desc ? button->desc : "gpio_keys", - bdata); - if (error) { - dev_err(dev, "Unable to claim irq %d; error %d\n", - irq, error); - gpio_free(button->gpio); - goto fail2; - } if (button->wakeup) wakeup = 1; From dad725d089b94bce8bbc769b7471dcfba3fbda0e Mon Sep 17 00:00:00 2001 From: Samu Onkalo Date: Fri, 13 Nov 2009 21:13:22 -0800 Subject: [PATCH 14/51] Input: input-polldev - add sysfs interface for controlling poll interval Sysfs entry for reading and setting of the polling interval. If the interval is set to 0, polling is stopped. Polling is restarted when interval is changed to non-zero. sysfs entries: poll = current polling interval in msec (RW) max = max allowed polling interval (RO) min = min allowed polling interval (RO) Minimum and maximum limit for interval can be set while setting up the device. Interval can be adjusted even if the input device is not currently open. [dtor@mail.ru: add kernel doc markup for the new fields] Signed-off-by: Samu Onkalo Signed-off-by: Dmitry Torokhov --- drivers/input/input-polldev.c | 111 ++++++++++++++++++++++++++++++++-- include/linux/input-polldev.h | 11 +++- 2 files changed, 115 insertions(+), 7 deletions(-) diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 910220c127cb..31874275fed0 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -56,14 +56,10 @@ static void input_polldev_stop_workqueue(void) mutex_unlock(&polldev_mutex); } -static void input_polled_device_work(struct work_struct *work) +static void input_polldev_queue_work(struct input_polled_dev *dev) { - struct input_polled_dev *dev = - container_of(work, struct input_polled_dev, work.work); unsigned long delay; - dev->poll(dev); - delay = msecs_to_jiffies(dev->poll_interval); if (delay >= HZ) delay = round_jiffies_relative(delay); @@ -71,6 +67,15 @@ static void input_polled_device_work(struct work_struct *work) queue_delayed_work(polldev_wq, &dev->work, delay); } +static void input_polled_device_work(struct work_struct *work) +{ + struct input_polled_dev *dev = + container_of(work, struct input_polled_dev, work.work); + + dev->poll(dev); + input_polldev_queue_work(dev); +} + static int input_open_polled_device(struct input_dev *input) { struct input_polled_dev *dev = input_get_drvdata(input); @@ -100,6 +105,83 @@ static void input_close_polled_device(struct input_dev *input) dev->close(dev); } +/* SYSFS interface */ + +static ssize_t input_polldev_get_poll(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_polled_dev *polldev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", polldev->poll_interval); +} + +static ssize_t input_polldev_set_poll(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct input_polled_dev *polldev = dev_get_drvdata(dev); + struct input_dev *input = polldev->input; + unsigned long interval; + + if (strict_strtoul(buf, 0, &interval)) + return -EINVAL; + + if (interval < polldev->poll_interval_min) + return -EINVAL; + + if (interval > polldev->poll_interval_max) + return -EINVAL; + + mutex_lock(&input->mutex); + + polldev->poll_interval = interval; + + if (input->users) { + cancel_delayed_work_sync(&polldev->work); + if (polldev->poll_interval > 0) + input_polldev_queue_work(polldev); + } + + mutex_unlock(&input->mutex); + + return count; +} + +static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll, + input_polldev_set_poll); + + +static ssize_t input_polldev_get_max(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_polled_dev *polldev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", polldev->poll_interval_max); +} + +static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL); + +static ssize_t input_polldev_get_min(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_polled_dev *polldev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", polldev->poll_interval_min); +} + +static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL); + +static struct attribute *sysfs_attrs[] = { + &dev_attr_poll.attr, + &dev_attr_max.attr, + &dev_attr_min.attr, + NULL +}; + +static struct attribute_group input_polldev_attribute_group = { + .attrs = sysfs_attrs +}; + /** * input_allocate_polled_device - allocated memory polled device * @@ -153,15 +235,29 @@ EXPORT_SYMBOL(input_free_polled_device); int input_register_polled_device(struct input_polled_dev *dev) { struct input_dev *input = dev->input; + int error; input_set_drvdata(input, dev); INIT_DELAYED_WORK(&dev->work, input_polled_device_work); if (!dev->poll_interval) dev->poll_interval = 500; + if (!dev->poll_interval_max) + dev->poll_interval_max = dev->poll_interval; input->open = input_open_polled_device; input->close = input_close_polled_device; - return input_register_device(input); + error = input_register_device(input); + if (error) + return error; + + error = sysfs_create_group(&input->dev.kobj, + &input_polldev_attribute_group); + if (error) { + input_unregister_device(input); + return error; + } + + return 0; } EXPORT_SYMBOL(input_register_polled_device); @@ -177,6 +273,9 @@ EXPORT_SYMBOL(input_register_polled_device); */ void input_unregister_polled_device(struct input_polled_dev *dev) { + sysfs_remove_group(&dev->input->dev.kobj, + &input_polldev_attribute_group); + input_unregister_device(dev->input); dev->input = NULL; } diff --git a/include/linux/input-polldev.h b/include/linux/input-polldev.h index 5c0ec68a965e..5e3dddf8f562 100644 --- a/include/linux/input-polldev.h +++ b/include/linux/input-polldev.h @@ -21,7 +21,12 @@ * longer being polled. Used to put device into low power mode. * @poll: driver-supplied method that polls the device and posts * input events (mandatory). - * @poll_interval: specifies how often the poll() method shoudl be called. + * @poll_interval: specifies how often the poll() method should be called. + * Defaults to 500 msec unless overriden when registering the device. + * @poll_interval_max: specifies upper bound for the poll interval. + * Defaults to the initial value of @poll_interval. + * @poll_interval_min: specifies lower bound for the poll interval. + * Defaults to 0. * @input: input device structire associated with the polled device. * Must be properly initialized by the driver (id, name, phys, bits). * @@ -36,8 +41,12 @@ struct input_polled_dev { void (*close)(struct input_polled_dev *dev); void (*poll)(struct input_polled_dev *dev); unsigned int poll_interval; /* msec */ + unsigned int poll_interval_max; /* msec */ + unsigned int poll_interval_min; /* msec */ struct input_dev *input; + +/* private: */ struct delayed_work work; }; From d69249f4b6857c0b23ceca270ae591381b16bba9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 16 Nov 2009 22:12:20 -0800 Subject: [PATCH 15/51] Input: input-polldev, matrix-keypad - include in kernel doc Make sure that polled input device and matrix keypad APIs are included with the rest of input API when generating kernel documentation. Also description of absres was missing as well. Signed-off-by: Dmitry Torokhov --- Documentation/DocBook/device-drivers.tmpl | 9 +++++++++ include/linux/input.h | 1 + include/linux/input/matrix_keypad.h | 3 +++ 3 files changed, 13 insertions(+) diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index 94a20fe8fedf..e994d1d9fbe6 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -293,10 +293,19 @@ X!Idrivers/video/console/fonts.c Input Subsystem + Input core !Iinclude/linux/input.h !Edrivers/input/input.c !Edrivers/input/ff-core.c !Edrivers/input/ff-memless.c + + Polled input devices +!Iinclude/linux/input-polldev.h +!Edrivers/input/input-polldev.c + + Matrix keyboars/keypads +!Iinclude/linux/input/matrix_keypad.h + diff --git a/include/linux/input.h b/include/linux/input.h index 9a04e26daab2..56d8e048c646 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1040,6 +1040,7 @@ struct ff_effect { * @absmin: minimum values for events coming from absolute axes * @absfuzz: describes noisiness for axes * @absflat: size of the center flat position (used by joydev) + * @absres: resolution used for events coming form absolute axes * @open: this method is called when the very first user calls * input_open_device(). The driver must prepare the device * to start generating events (start polling thread, diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h index b3cd42d50e16..3bd018baae20 100644 --- a/include/linux/input/matrix_keypad.h +++ b/include/linux/input/matrix_keypad.h @@ -41,6 +41,9 @@ struct matrix_keymap_data { * @col_scan_delay_us: delay, measured in microseconds, that is * needed before we can keypad after activating column gpio * @debounce_ms: debounce interval in milliseconds + * @active_low: gpio polarity + * @wakeup: controls whether the device should be set up as wakeup + * source * * This structure represents platform-specific data that use used by * matrix_keypad driver to perform proper initialization. From 21f25573fbd1b459d5401f2b72160f745013fc34 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 16 Nov 2009 22:12:21 -0800 Subject: [PATCH 16/51] Input: touchkit_ps2 - do not advertise unsupported buttons Touchkit PS/2 touchscreen does not have left/right/middle buttons and should not be advertising as capable of generating these events. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/touchkit_ps2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/mouse/touchkit_ps2.c b/drivers/input/mouse/touchkit_ps2.c index 0308a0faa94d..909431c31ab4 100644 --- a/drivers/input/mouse/touchkit_ps2.c +++ b/drivers/input/mouse/touchkit_ps2.c @@ -86,7 +86,8 @@ int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties) if (set_properties) { dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - __set_bit(BTN_TOUCH, dev->keybit); + dev->keybit[BIT_WORD(BTN_MOUSE)] = 0; + dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0); input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0); From c7a1f3ccfc2f99427f2e1545b3171e98539c3c95 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 16 Nov 2009 22:12:21 -0800 Subject: [PATCH 17/51] Input: elantech - do not advertise relative events Elantech touchpads work in absolute mode and do not generate relative events so they should not be advertising them. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index fda35e615abf..b27684f267bf 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -420,6 +420,7 @@ static void elantech_set_input_params(struct psmouse *psmouse) __set_bit(EV_KEY, dev->evbit); __set_bit(EV_ABS, dev->evbit); + __clear_bit(EV_REL, dev->evbit); __set_bit(BTN_LEFT, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); From 0cc1770b66ddc2524ab5f0ed6ba5f2df19d6414a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 16 Nov 2009 22:12:21 -0800 Subject: [PATCH 18/51] Input: lifebook - do not advertise unsupported buttons The main input device of Lifebook touchscreens does not generate left/right/middle button events and therefore should not be advertising them in its capabilities. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/lifebook.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 5e6308694408..4c254876609f 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -199,10 +199,10 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) return -1; /* - Enable absolute output -- ps2_command fails always but if - you leave this call out the touchsreen will never send - absolute coordinates - */ + * Enable absolute output -- ps2_command fails always but if + * you leave this call out the touchsreen will never send + * absolute coordinates + */ param = lifebook_use_6byte_proto ? 0x08 : 0x07; ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); @@ -284,8 +284,8 @@ static int lifebook_create_relative_device(struct psmouse *psmouse) dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); - dev2->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_RIGHT); + dev2->keybit[BIT_WORD(BTN_LEFT)] = + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); error = input_register_device(priv->dev2); if (error) @@ -310,6 +310,7 @@ int lifebook_init(struct psmouse *psmouse) dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); dev1->relbit[0] = 0; + dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0; dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0); input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0); From 315eb996d5505112b22452ccbc7e01fb02eaae81 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 16 Nov 2009 22:12:21 -0800 Subject: [PATCH 19/51] Input: psmouse - rework setting of BTN_MIDDLE capability Do not start protocol detection assuming that middle mouse is present, instead let individual protocols explicitly set this capability. This fixes issue with Synaptics touchpads pretending that they have middle button when hardware clearly reports otherwise. Reported-and-tested-by: Andrey Borzenkov Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/hgpk.c | 13 ---------- drivers/input/mouse/logips2pp.c | 4 ++-- drivers/input/mouse/psmouse-base.c | 38 +++++++++++++++++++++--------- drivers/input/mouse/sentelic.c | 1 + drivers/input/mouse/trackpoint.c | 13 ++++++---- 5 files changed, 38 insertions(+), 31 deletions(-) diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index de1e553028b7..b146237266d8 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -430,19 +430,6 @@ static int hgpk_register(struct psmouse *psmouse) struct input_dev *dev = psmouse->dev; int err; - /* unset the things that psmouse-base sets which we don't have */ - __clear_bit(BTN_MIDDLE, dev->keybit); - - /* set the things we do have */ - __set_bit(EV_KEY, dev->evbit); - __set_bit(EV_REL, dev->evbit); - - __set_bit(REL_X, dev->relbit); - __set_bit(REL_Y, dev->relbit); - - __set_bit(BTN_LEFT, dev->keybit); - __set_bit(BTN_RIGHT, dev->keybit); - /* register handlers */ psmouse->protocol_handler = hgpk_process_byte; psmouse->poll = hgpk_poll; diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index ab5dc5f5fd83..543c240a85f2 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -404,8 +404,8 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) } } - if (buttons < 3) - __clear_bit(BTN_MIDDLE, psmouse->dev->keybit); + if (buttons >= 3) + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); if (model_info) ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 690aed905436..e1c9fe210083 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -425,6 +425,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties) return -1; if (set_properties) { + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_EXTRA, psmouse->dev->keybit); __set_bit(BTN_SIDE, psmouse->dev->keybit); __set_bit(REL_WHEEL, psmouse->dev->relbit); @@ -460,8 +461,10 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties) __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(REL_WHEEL, psmouse->dev->relbit); - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Wheel Mouse"; + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Wheel Mouse"; psmouse->pktsize = 4; } @@ -504,8 +507,10 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) __set_bit(BTN_SIDE, psmouse->dev->keybit); __set_bit(BTN_EXTRA, psmouse->dev->keybit); - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Explorer Mouse"; + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Explorer Mouse"; psmouse->pktsize = 4; } @@ -536,6 +541,7 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties) return -1; if (set_properties) { + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_EXTRA, psmouse->dev->keybit); psmouse->vendor = "Kensington"; @@ -551,8 +557,16 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties) static int ps2bare_detect(struct psmouse *psmouse, bool set_properties) { if (set_properties) { - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Mouse"; + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Mouse"; + +/* + * We have no way of figuring true number of buttons so let's + * assume that the device has 3. + */ + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); } return 0; @@ -567,6 +581,8 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties) if (set_properties) { psmouse->vendor = "Cortron"; psmouse->name = "PS/2 Trackball"; + + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_SIDE, psmouse->dev->keybit); } @@ -1184,15 +1200,16 @@ static void psmouse_disconnect(struct serio *serio) mutex_unlock(&psmouse_mutex); } -static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto) +static int psmouse_switch_protocol(struct psmouse *psmouse, + const struct psmouse_protocol *proto) { struct input_dev *input_dev = psmouse->dev; input_dev->dev.parent = &psmouse->ps2dev.serio->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); + input_dev->keybit[BIT_WORD(BTN_MOUSE)] = + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); psmouse->set_rate = psmouse_set_rate; @@ -1209,8 +1226,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse return -1; psmouse->type = proto->type; - } - else + } else psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, true); diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index f84cbd97c884..77b9fd0b3fbf 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -836,6 +836,7 @@ int fsp_init(struct psmouse *psmouse) priv->flags |= FSPDRV_FLAG_EN_OPC; /* Set up various supported input event bits */ + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_BACK, psmouse->dev->keybit); __set_bit(BTN_FORWARD, psmouse->dev->keybit); __set_bit(REL_WHEEL, psmouse->dev->relbit); diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index e354362f2971..63d4a67830f2 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -284,7 +284,6 @@ static int trackpoint_reconnect(struct psmouse *psmouse) int trackpoint_detect(struct psmouse *psmouse, bool set_properties) { - struct trackpoint_data *priv; struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char firmware_id; unsigned char button_info; @@ -301,8 +300,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) button_info = 0; } - psmouse->private = priv = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL); - if (!priv) + psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL); + if (!psmouse->private) return -1; psmouse->vendor = "IBM"; @@ -311,7 +310,10 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) psmouse->reconnect = trackpoint_reconnect; psmouse->disconnect = trackpoint_disconnect; - trackpoint_defaults(priv); + if ((button_info & 0x0f) >= 3) + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + + trackpoint_defaults(psmouse->private); trackpoint_sync(psmouse); error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); @@ -319,7 +321,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) printk(KERN_ERR "trackpoint.c: failed to create sysfs attributes, error: %d\n", error); - kfree(priv); + kfree(psmouse->private); + psmouse->private = NULL; return -1; } From 71bb21b677e89a2b438b804231f92b779beda5d7 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 16 Nov 2009 22:12:22 -0800 Subject: [PATCH 20/51] Input: ALPS - add support for touchpads with 4-directional button The touchpad on Acer Aspire 5720, 5520 and some other Aspire models (signature 0x73, 0x02, 0x50) has a button that can be rocked in 4 different directions. Make the driver to generate BTN_0..BTN_3 events in response. The Synaptics driver by default maps BTN_0 and BTN_1 to up and down, so there should be no visible changes with the old setup that generated BTN_FORWARD and BTN_BACK (also mapped to up and down). Signed-off-by: Maxim Levitsky Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 100 ++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f36110689aae..a3f492a50850 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -28,13 +28,16 @@ #define dbg(format, arg...) do {} while (0) #endif -#define ALPS_DUALPOINT 0x01 -#define ALPS_WHEEL 0x02 -#define ALPS_FW_BK_1 0x04 -#define ALPS_4BTN 0x08 -#define ALPS_OLDPROTO 0x10 -#define ALPS_PASS 0x20 -#define ALPS_FW_BK_2 0x40 + +#define ALPS_OLDPROTO 0x01 /* old style input */ +#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ +#define ALPS_PASS 0x04 /* device has a pass-through port */ + +#define ALPS_WHEEL 0x08 /* hardware wheel present */ +#define ALPS_FW_BK_1 0x10 /* front & back buttons present */ +#define ALPS_FW_BK_2 0x20 /* front & back buttons present */ +#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ + static const struct alps_model_info alps_model_data[] = { { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ @@ -56,7 +59,7 @@ static const struct alps_model_info alps_model_data[] = { { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ - { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 }, /* Dell Vostro 1400 */ + { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ }; /* @@ -83,6 +86,7 @@ static const struct alps_model_info alps_model_data[] = { static void alps_process_packet(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; + const struct alps_model_info *model = priv->i; unsigned char *packet = psmouse->packet; struct input_dev *dev = psmouse->dev; struct input_dev *dev2 = priv->dev2; @@ -101,7 +105,7 @@ static void alps_process_packet(struct psmouse *psmouse) return; } - if (priv->i->flags & ALPS_OLDPROTO) { + if (model->flags & ALPS_OLDPROTO) { left = packet[2] & 0x10; right = packet[2] & 0x08; middle = 0; @@ -117,12 +121,12 @@ static void alps_process_packet(struct psmouse *psmouse) z = packet[5]; } - if (priv->i->flags & ALPS_FW_BK_1) { + if (model->flags & ALPS_FW_BK_1) { back = packet[0] & 0x10; forward = packet[2] & 4; } - if (priv->i->flags & ALPS_FW_BK_2) { + if (model->flags & ALPS_FW_BK_2) { back = packet[3] & 4; forward = packet[2] & 4; if ((middle = forward && back)) @@ -132,7 +136,7 @@ static void alps_process_packet(struct psmouse *psmouse) ges = packet[2] & 1; fin = packet[2] & 2; - if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) { + if ((model->flags & ALPS_DUALPOINT) && z == 127) { input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); @@ -150,7 +154,8 @@ static void alps_process_packet(struct psmouse *psmouse) input_report_key(dev, BTN_MIDDLE, middle); /* Convert hardware tap to a reasonable Z value */ - if (ges && !fin) z = 40; + if (ges && !fin) + z = 40; /* * A "tap and drag" operation is reported by the hardware as a transition @@ -166,8 +171,10 @@ static void alps_process_packet(struct psmouse *psmouse) } priv->prev_fin = fin; - if (z > 30) input_report_key(dev, BTN_TOUCH, 1); - if (z < 25) input_report_key(dev, BTN_TOUCH, 0); + if (z > 30) + input_report_key(dev, BTN_TOUCH, 1); + if (z < 25) + input_report_key(dev, BTN_TOUCH, 0); if (z > 0) { input_report_abs(dev, ABS_X, x); @@ -177,14 +184,21 @@ static void alps_process_packet(struct psmouse *psmouse) input_report_abs(dev, ABS_PRESSURE, z); input_report_key(dev, BTN_TOOL_FINGER, z > 0); - if (priv->i->flags & ALPS_WHEEL) + if (model->flags & ALPS_WHEEL) input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); - if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { + if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { input_report_key(dev, BTN_FORWARD, forward); input_report_key(dev, BTN_BACK, back); } + if (model->flags & ALPS_FOUR_BUTTONS) { + input_report_key(dev, BTN_0, packet[2] & 4); + input_report_key(dev, BTN_1, packet[0] & 0x10); + input_report_key(dev, BTN_2, packet[3] & 4); + input_report_key(dev, BTN_3, packet[0] & 0x20); + } + input_sync(dev); } @@ -393,15 +407,12 @@ static int alps_poll(struct psmouse *psmouse) return 0; } -static int alps_hw_init(struct psmouse *psmouse, int *version) +static int alps_hw_init(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; + const struct alps_model_info *model = priv->i; - priv->i = alps_get_model(psmouse, version); - if (!priv->i) - return -1; - - if ((priv->i->flags & ALPS_PASS) && + if ((model->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, true)) { return -1; } @@ -416,7 +427,7 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) return -1; } - if ((priv->i->flags & ALPS_PASS) && + if ((model->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, false)) { return -1; } @@ -432,12 +443,15 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) static int alps_reconnect(struct psmouse *psmouse) { + const struct alps_model_info *model; + psmouse_reset(psmouse); - if (alps_hw_init(psmouse, NULL)) + model = alps_get_model(psmouse, NULL); + if (!model) return -1; - return 0; + return alps_hw_init(psmouse); } static void alps_disconnect(struct psmouse *psmouse) @@ -452,6 +466,7 @@ static void alps_disconnect(struct psmouse *psmouse) int alps_init(struct psmouse *psmouse) { struct alps_data *priv; + const struct alps_model_info *model; struct input_dev *dev1 = psmouse->dev, *dev2; int version; @@ -463,33 +478,48 @@ int alps_init(struct psmouse *psmouse) priv->dev2 = dev2; psmouse->private = priv; - if (alps_hw_init(psmouse, &version)) + model = alps_get_model(psmouse, &version); + if (!model) + goto init_fail; + + priv->i = model; + + if (alps_hw_init(psmouse)) goto init_fail; dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); - dev1->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); + dev1->keybit[BIT_WORD(BTN_LEFT)] |= + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); - if (priv->i->flags & ALPS_WHEEL) { + if (model->flags & ALPS_WHEEL) { dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); } - if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { + if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); } + if (model->flags & ALPS_FOUR_BUTTONS) { + dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); + dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); + dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); + dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); + } else { + dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); + } + snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); dev2->phys = priv->phys; - dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; + dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; dev2->id.bustype = BUS_I8042; dev2->id.vendor = 0x0002; dev2->id.product = PSMOUSE_ALPS; @@ -497,9 +527,9 @@ int alps_init(struct psmouse *psmouse) dev2->dev.parent = &psmouse->ps2dev.serio->dev; dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - dev2->relbit[BIT_WORD(REL_X)] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y); - dev2->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); + dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); + dev2->keybit[BIT_WORD(BTN_LEFT)] = + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); if (input_register_device(priv->dev2)) goto init_fail; From 0c09b2ac35ff7c5f280e5cf8142ad0822f1c93b3 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Wed, 18 Nov 2009 00:40:48 -0800 Subject: [PATCH 21/51] Input: keyboard - fix theoretical race on vt switch A VT switch can theoretically change fg_console between vc = vc_cons[fg_console].d and kbd = kbd_table + fg_console Fix it by replacing the second fg_console with vc->vc_num. Signed-off-by: Alan Jenkins Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 737be953cc58..747683f055ed 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1136,7 +1136,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u static void kbd_rawcode(unsigned char data) { struct vc_data *vc = vc_cons[fg_console].d; - kbd = kbd_table + fg_console; + kbd = kbd_table + vc->vc_num; if (kbd->kbdmode == VC_RAW) put_queue(vc, data); } @@ -1157,7 +1157,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) tty->driver_data = vc; } - kbd = kbd_table + fg_console; + kbd = kbd_table + vc->vc_num; if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) sysrq_alt = down ? keycode : 0; From ab9122cd3377c9eee85380ea2fe35125c6962a87 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 19 Nov 2009 09:28:25 -0800 Subject: [PATCH 22/51] Input: atmel_tsadcc - rework setting touchscreen capabilities Tiny patch for setting capabilities using input API function. Signed-off-by: Nicolas Ferre Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_tsadcc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 9c7fce4d74d0..5a2af5973cb4 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -242,12 +242,12 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) input_dev->phys = ts_dev->phys; input_dev->dev.parent = &pdev->dev; - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - + __set_bit(EV_ABS, input_dev->evbit); input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0); + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); + /* clk_enable() always returns 0, no need to check it */ clk_enable(ts_dev->clk); From 970435a141b55b2334c6b7e834ed5da7a87daae5 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 19 Nov 2009 09:29:32 -0800 Subject: [PATCH 23/51] Input: atmel_tsadcc - use platform parameters Add a number of plafrom dependent parameters to atmel_tsadcc. The touchscreeen driver can now take into account the slight differences that exist between IPs included in diferent products. This will also allow to adapt its behaivior to the caracteristics of the resistive panel used. Signed-off-by: Nicolas Ferre Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_tsadcc.c | 41 ++++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 5a2af5973cb4..3d9b5166ebe9 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include /* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ @@ -36,7 +38,9 @@ #define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */ #define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */ #define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ +#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */ #define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ +#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */ #define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */ #define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */ #define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */ @@ -84,7 +88,13 @@ #define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */ #define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */ -#define ADC_CLOCK 1000000 +#define ATMEL_TSADCC_XPOS 0x50 +#define ATMEL_TSADCC_Z1DAT 0x54 +#define ATMEL_TSADCC_Z2DAT 0x58 + +#define PRESCALER_VAL(x) ((x) >> 8) + +#define ADC_DEFAULT_CLOCK 100000 struct atmel_tsadcc { struct input_dev *input; @@ -172,6 +182,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) struct atmel_tsadcc *ts_dev; struct input_dev *input_dev; struct resource *res; + struct at91_tsadcc_data *pdata = pdev->dev.platform_data; int err = 0; unsigned int prsc; unsigned int reg; @@ -254,19 +265,37 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) prsc = clk_get_rate(ts_dev->clk); dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); - prsc = prsc / ADC_CLOCK / 2 - 1; + if (!pdata) + goto err_fail; + + if (!pdata->adc_clock) + pdata->adc_clock = ADC_DEFAULT_CLOCK; + + prsc = (prsc / (2 * pdata->adc_clock)) - 1; + + /* saturate if this value is too high */ + if (cpu_is_at91sam9rl()) { + if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL)) + prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL); + } else { + if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL)) + prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL); + } + + dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc); reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE | ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */ ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */ - ((prsc << 8) & ATMEL_TSADCC_PRESCAL) | /* PRESCAL */ - ((0x13 << 16) & ATMEL_TSADCC_STARTUP) | /* STARTUP */ - ((0x0F << 28) & ATMEL_TSADCC_PENDBC); /* PENDBC */ + (prsc << 8) | + ((0x26 << 16) & ATMEL_TSADCC_STARTUP) | + ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC); atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST); atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); - atmel_tsadcc_write(ATMEL_TSADCC_TSR, (0x3 << 24) & ATMEL_TSADCC_TSSHTIM); + atmel_tsadcc_write(ATMEL_TSADCC_TSR, + (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM); atmel_tsadcc_read(ATMEL_TSADCC_SR); atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); From 423c9b0dc3d01e50a4df4e48e8477bfb33638d6e Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 19 Nov 2009 09:31:20 -0800 Subject: [PATCH 24/51] AT91: add platform parameters for atmel_tsadcc in at91sam9rlek Setup platform parameters in at91sam9rl-ek board to be passed to atmel_tsadcc touchscreen. Signed-off-by: Nicolas Ferre Acked-by: Andrew Victor Signed-off-by: Dmitry Torokhov --- arch/arm/mach-at91/at91sam9rl_devices.c | 10 ++++++++-- arch/arm/mach-at91/board-sam9rlek.c | 12 +++++++++++- arch/arm/mach-at91/include/mach/board.h | 7 ++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index d345f5453dbe..53aaa94df75a 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -622,6 +622,7 @@ static void __init at91_add_device_tc(void) { } #if defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) || defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC_MODULE) static u64 tsadcc_dmamask = DMA_BIT_MASK(32); +static struct at91_tsadcc_data tsadcc_data; static struct resource tsadcc_resources[] = { [0] = { @@ -642,22 +643,27 @@ static struct platform_device at91sam9rl_tsadcc_device = { .dev = { .dma_mask = &tsadcc_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &tsadcc_data, }, .resource = tsadcc_resources, .num_resources = ARRAY_SIZE(tsadcc_resources), }; -void __init at91_add_device_tsadcc(void) +void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) { + if (!data) + return; + at91_set_A_periph(AT91_PIN_PA17, 0); /* AD0_XR */ at91_set_A_periph(AT91_PIN_PA18, 0); /* AD1_XL */ at91_set_A_periph(AT91_PIN_PA19, 0); /* AD2_YT */ at91_set_A_periph(AT91_PIN_PA20, 0); /* AD3_TB */ + tsadcc_data = *data; platform_device_register(&at91sam9rl_tsadcc_device); } #else -void __init at91_add_device_tsadcc(void) {} +void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) {} #endif diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c index bd28e989e54e..7ac20f3a2067 100644 --- a/arch/arm/mach-at91/board-sam9rlek.c +++ b/arch/arm/mach-at91/board-sam9rlek.c @@ -242,6 +242,16 @@ static struct gpio_led ek_leds[] = { }; +/* + * Touchscreen + */ +static struct at91_tsadcc_data ek_tsadcc_data = { + .adc_clock = 1000000, + .pendet_debounce = 0x0f, + .ts_sample_hold_time = 0x03, +}; + + /* * GPIO Buttons */ @@ -310,7 +320,7 @@ static void __init ek_board_init(void) /* AC97 */ at91_add_device_ac97(&ek_ac97_data); /* Touch Screen Controller */ - at91_add_device_tsadcc(); + at91_add_device_tsadcc(&ek_tsadcc_data); /* LEDs */ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); /* Push Buttons */ diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index 2f4fcedc02ba..6f1579f8abdd 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -186,7 +186,12 @@ extern void __init at91_add_device_ac97(struct ac97c_platform_data *data); extern void __init at91_add_device_isi(void); /* Touchscreen Controller */ -extern void __init at91_add_device_tsadcc(void); +struct at91_tsadcc_data { + unsigned int adc_clock; + u8 pendet_debounce; + u8 ts_sample_hold_time; +}; +extern void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data); /* CAN */ struct at91_can_data { From 985f37f827f5012f88e286914cdbae87b9f50ed1 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 19 Nov 2009 09:32:52 -0800 Subject: [PATCH 25/51] AT91: add touchscreen support for at91sam9g45ekes New at91sam9g45ekes board provides a LCD with resistive touchscreen. This is the support of this feature by atmel_tsadcc driver. This also sets up platform parameters to be passed to the driver. Signed-off-by: Nicolas Ferre Acked-by: Andrew Victor Signed-off-by: Dmitry Torokhov --- arch/arm/mach-at91/at91sam9g45_devices.c | 51 ++++++++++++++++++++++++ arch/arm/mach-at91/board-sam9m10g45ek.c | 12 ++++++ drivers/input/touchscreen/Kconfig | 2 +- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 332b784050b2..a5a4eb19fbbe 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -809,6 +809,57 @@ static void __init at91_add_device_rtc(void) {} #endif +/* -------------------------------------------------------------------- + * Touchscreen + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) || defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC_MODULE) +static u64 tsadcc_dmamask = DMA_BIT_MASK(32); +static struct at91_tsadcc_data tsadcc_data; + +static struct resource tsadcc_resources[] = { + [0] = { + .start = AT91SAM9G45_BASE_TSC, + .end = AT91SAM9G45_BASE_TSC + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9G45_ID_TSC, + .end = AT91SAM9G45_ID_TSC, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device at91sam9g45_tsadcc_device = { + .name = "atmel_tsadcc", + .id = -1, + .dev = { + .dma_mask = &tsadcc_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &tsadcc_data, + }, + .resource = tsadcc_resources, + .num_resources = ARRAY_SIZE(tsadcc_resources), +}; + +void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) +{ + if (!data) + return; + + at91_set_gpio_input(AT91_PIN_PD20, 0); /* AD0_XR */ + at91_set_gpio_input(AT91_PIN_PD21, 0); /* AD1_XL */ + at91_set_gpio_input(AT91_PIN_PD22, 0); /* AD2_YT */ + at91_set_gpio_input(AT91_PIN_PD23, 0); /* AD3_TB */ + + tsadcc_data = *data; + platform_device_register(&at91sam9g45_tsadcc_device); +} +#else +void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) {} +#endif + + /* -------------------------------------------------------------------- * RTT * -------------------------------------------------------------------- */ diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c index 64c3843f323d..3d6764b3ad7a 100644 --- a/arch/arm/mach-at91/board-sam9m10g45ek.c +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c @@ -228,6 +228,16 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data; #endif +/* + * Touchscreen + */ +static struct at91_tsadcc_data ek_tsadcc_data = { + .adc_clock = 300000, + .pendet_debounce = 0x0d, + .ts_sample_hold_time = 0x0a, +}; + + /* * GPIO Buttons */ @@ -378,6 +388,8 @@ static void __init ek_board_init(void) at91_add_device_i2c(0, NULL, 0); /* LCD Controller */ at91_add_device_lcdc(&ek_lcdc_data); + /* Touch Screen */ + at91_add_device_tsadcc(&ek_tsadcc_data); /* Push Buttons */ ek_add_device_buttons(); /* AC97 */ diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1cd9e8c8efb3..aebea71ff02a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -309,7 +309,7 @@ config TOUCHSCREEN_TOUCHWIN config TOUCHSCREEN_ATMEL_TSADCC tristate "Atmel Touchscreen Interface" - depends on ARCH_AT91SAM9RL + depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 help Say Y here if you have a 4-wire touchscreen connected to the ADC Controller on your Atmel SoC (such as the AT91SAM9RL). From 722232bcd8086b37cd3af7d9e94e7e10b231979e Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 23 Nov 2009 08:10:50 -0800 Subject: [PATCH 26/51] Input: usbtouchscreen - remove unneeded usb_kill_urb usb_kill_urb() in disconnect is not needed as unregistering will cause close() to be called. Signed-off-by: Oliver Neukum Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/usbtouchscreen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 68ece5801a58..eddb628c5459 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -1087,7 +1087,7 @@ static void usbtouch_disconnect(struct usb_interface *intf) dbg("%s - usbtouch is initialized, cleaning up", __func__); usb_set_intfdata(intf, NULL); - usb_kill_urb(usbtouch->irq); + /* this will stop IO via close */ input_unregister_device(usbtouch->input); usb_free_urb(usbtouch->irq); usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); From 30ad7ba0a55ef394c6956c886ddd058173153506 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 23 Nov 2009 08:17:38 -0800 Subject: [PATCH 27/51] Input: ads7846 - fix pressure reporting On Zaurus, hx4700 and others pressure is reported inverted -- the lighter the pressure, the bigger numerical value. Signed-off-by: Pavel Machek Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 09c810999b92..033233d2b5eb 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -608,7 +608,7 @@ static void ads7846_rx(void *ads) input_report_abs(input, ABS_X, x); input_report_abs(input, ABS_Y, y); - input_report_abs(input, ABS_PRESSURE, Rt); + input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt); input_sync(input); #ifdef VERBOSE From 52ce4eaa389eaac01876a4c1b6cacee15005b010 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 23 Nov 2009 08:25:17 -0800 Subject: [PATCH 28/51] Input: ads7846 - switch to using dev_vdbg() Signed-off-by: Pavel Machek Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 033233d2b5eb..52d2ca147d8f 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -29,10 +29,9 @@ #include #include - /* * This code has been heavily tested on a Nokia 770, and lightly - * tested on other ads7846 devices (OSK/Mistral, Lubbock). + * tested on other ads7846 devices (OSK/Mistral, Lubbock, Spitz). * TSC2046 is just newer ads7846 silicon. * Support for ads7843 tested on Atmel at91sam926x-EK. * Support for ads7845 has only been stubbed in. @@ -43,7 +42,7 @@ * have to maintain our own SW IRQ disabled status. This should be * removed as soon as the affected platform's IRQ handling is fixed. * - * app note sbaa036 talks in more detail about accurate sampling... + * App note sbaa036 talks in more detail about accurate sampling... * that ought to help in situations like LCDs inducing noise (which * can also be helped by using synch signals) and more generally. * This driver tries to utilize the measures described in the app @@ -566,10 +565,8 @@ static void ads7846_rx(void *ads) * once more the measurement */ if (packet->tc.ignore || Rt > ts->pressure_max) { -#ifdef VERBOSE - pr_debug("%s: ignored %d pressure %d\n", - dev_name(&ts->spi->dev), packet->tc.ignore, Rt); -#endif + dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n", + packet->tc.ignore, Rt); hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_MODE_REL); return; @@ -598,9 +595,7 @@ static void ads7846_rx(void *ads) if (!ts->pendown) { input_report_key(input, BTN_TOUCH, 1); ts->pendown = 1; -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "DOWN\n"); -#endif + dev_vdbg(&ts->spi->dev, "DOWN\n"); } if (ts->swap_xy) @@ -611,9 +606,7 @@ static void ads7846_rx(void *ads) input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt); input_sync(input); -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt); -#endif + dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt); } hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), @@ -723,9 +716,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) input_sync(input); ts->pendown = 0; -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "UP\n"); -#endif + dev_vdbg(&ts->spi->dev, "UP\n"); } /* measurement cycle ended */ From 6236dfaa908d9e9c84a8c4d029f443104ed2c47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Mon, 23 Nov 2009 08:26:38 -0800 Subject: [PATCH 29/51] Input: do not overwrite the first part of phys string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use strlcat() to append a string to the previously created first part. Signed-off-by: Márton Németh Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/hid/usbhid/usbkbd.c | 2 +- drivers/input/misc/ati_remote.c | 2 +- drivers/input/misc/powermate.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index b342926dd7fc..f843443ba5c3 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c @@ -266,7 +266,7 @@ static int usb_kbd_probe(struct usb_interface *iface, le16_to_cpu(dev->descriptor.idProduct)); usb_make_path(dev, kbd->phys, sizeof(kbd->phys)); - strlcpy(kbd->phys, "/input0", sizeof(kbd->phys)); + strlcat(kbd->phys, "/input0", sizeof(kbd->phys)); input_dev->name = kbd->name; input_dev->phys = kbd->phys; diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c index e290fde35e74..614b65d78fe9 100644 --- a/drivers/input/misc/ati_remote.c +++ b/drivers/input/misc/ati_remote.c @@ -766,7 +766,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de ati_remote->interface = interface; usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); - strlcpy(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); + strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); if (udev->manufacturer) strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index a53c4885fbad..668913d12044 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -338,7 +338,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i pm->input = input_dev; usb_make_path(udev, pm->phys, sizeof(pm->phys)); - strlcpy(pm->phys, "/input0", sizeof(pm->phys)); + strlcat(pm->phys, "/input0", sizeof(pm->phys)); spin_lock_init(&pm->lock); From 721a730eceb009ba61f8eeee31360c02ed8f6aba Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 23 Nov 2009 08:30:18 -0800 Subject: [PATCH 30/51] Input: force feedback - fix function name in comment Function name is input_ff_destroy() and not input_ff_free() Signed-off-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/ff-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 72c63e5dd630..3d7816ccfe75 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -353,7 +353,7 @@ int input_ff_create(struct input_dev *dev, int max_effects) EXPORT_SYMBOL_GPL(input_ff_create); /** - * input_ff_free() - frees force feedback portion of input device + * input_ff_destroy() - frees force feedback portion of input device * @dev: input device supporting force feedback * * This function is only needed in error path as input core will From 2330ed18b27a8f4f10e48e0a1c65ede56e03825c Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Mon, 23 Nov 2009 08:38:16 -0800 Subject: [PATCH 31/51] Input: usbtouchscreen - add support for Zytronic capacitive touchscreen Zytronic USB-attached capacitive touchscreen support within the generic USB touchscreen driver. Signed-off-by: Daniel Silverstone Signed-off-by: Vincent Sanders Signed-off-by: Simtec Linux Team Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 6 ++ drivers/input/touchscreen/usbtouchscreen.c | 73 +++++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index aebea71ff02a..c04fb531d63d 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -430,6 +430,7 @@ config TOUCHSCREEN_USB_COMPOSITE - IdealTEK URTC1000 - GoTop Super_Q2/GogoPen/PenPower tablets - JASTEC USB Touch Controller/DigiTech DTR-02U + - Zytronic controllers Have a look at for a usage description and the required user-space stuff. @@ -502,6 +503,11 @@ config TOUCHSCREEN_USB_E2I bool "e2i Touchscreen controller (e.g. from Mimo 740)" depends on TOUCHSCREEN_USB_COMPOSITE +config TOUCHSCREEN_USB_ZYTRONIC + default y + bool "Zytronic controller" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + config TOUCHSCREEN_TOUCHIT213 tristate "Sahara TouchIT-213 touchscreen" select SERIO diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index eddb628c5459..4474e2339f47 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -14,6 +14,7 @@ * - General Touch * - GoTop Super_Q2/GogoPen/PenPower tablets * - JASTEC USB touch controller/DigiTech DTR-02U + * - Zytronic capacitive touchscreen * * Copyright (C) 2004-2007 by Daniel Ritz * Copyright (C) by Todd E. Johnson (mtouchusb.c) @@ -73,6 +74,15 @@ struct usbtouch_device_info { int min_press, max_press; int rept_size; + /* + * Always service the USB devices irq not just when the input device is + * open. This is useful when devices have a watchdog which prevents us + * from periodically polling the device. Leave this unset unless your + * touchscreen device requires it, as it does consume more of the USB + * bandwidth. + */ + bool irq_always; + void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len); /* @@ -121,6 +131,7 @@ enum { DEVTYPE_GOTOP, DEVTYPE_JASTEC, DEVTYPE_E2I, + DEVTYPE_ZYTRONIC, }; #define USB_DEVICE_HID_CLASS(vend, prod) \ @@ -201,6 +212,11 @@ static struct usb_device_id usbtouch_devices[] = { #ifdef CONFIG_TOUCHSCREEN_USB_E2I {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I}, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC + {USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC}, +#endif + {} }; @@ -621,6 +637,39 @@ static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt) } #endif +/***************************************************************************** + * Zytronic Part + */ +#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC +static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + switch (pkt[0]) { + case 0x3A: /* command response */ + dbg("%s: Command response %d", __func__, pkt[1]); + break; + + case 0xC0: /* down */ + dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7); + dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7); + dev->touch = 1; + dbg("%s: down %d,%d", __func__, dev->x, dev->y); + return 1; + + case 0x80: /* up */ + dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7); + dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7); + dev->touch = 0; + dbg("%s: up %d,%d", __func__, dev->x, dev->y); + return 1; + + default: + dbg("%s: Unknown return %d", __func__, pkt[0]); + break; + } + + return 0; +} +#endif /***************************************************************************** * the different device descriptors @@ -783,6 +832,18 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .read_data = e2i_read_data, }, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC + [DEVTYPE_ZYTRONIC] = { + .min_xc = 0x0, + .max_xc = 0x03ff, + .min_yc = 0x0, + .max_yc = 0x03ff, + .rept_size = 5, + .read_data = zytronic_read_data, + .irq_always = true, + }, +#endif }; @@ -933,8 +994,10 @@ static int usbtouch_open(struct input_dev *input) usbtouch->irq->dev = usbtouch->udev; - if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) - return -EIO; + if (!usbtouch->type->irq_always) { + if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) + return -EIO; + } return 0; } @@ -943,7 +1006,8 @@ static void usbtouch_close(struct input_dev *input) { struct usbtouch_usb *usbtouch = input_get_drvdata(input); - usb_kill_urb(usbtouch->irq); + if (!usbtouch->type->irq_always) + usb_kill_urb(usbtouch->irq); } @@ -1066,6 +1130,9 @@ static int usbtouch_probe(struct usb_interface *intf, usb_set_intfdata(intf, usbtouch); + if (usbtouch->type->irq_always) + usb_submit_urb(usbtouch->irq, GFP_KERNEL); + return 0; out_free_buffers: From f5f96b93e745dd054110d511779e7ec5cfdfdfe6 Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Mon, 23 Nov 2009 09:47:12 -0800 Subject: [PATCH 32/51] Input: add S3C24XX touchscreen driver S3C24XX touchscreen driver, originally written by Arnaud Patard and other contributors. The driver has had substantial testing as well as a number of tidying up passes done by Ben Dooks, as noted: - added kernel-doc comments to most of the routines - removed old code from pre adc framework days - updated device probe code to use platform id list matching - cleaned up debug, since printk() now has timestamp feature - ensure code uses dev_() reporting macros where necessary - remove ABS_PRESSURE reporting, tslib can be fixed - ensure timer is removed on driver exit - move to using dev_pmops for power management Signed-off-by: Arnaud Patard Signed-off-by: Ben Dooks Signed-off-by: Simtec Linux Team Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 3 +- drivers/input/touchscreen/s3c2410_ts.c | 457 +++++++++++++++++++++++++ 3 files changed, 471 insertions(+), 1 deletion(-) create mode 100644 drivers/input/touchscreen/s3c2410_ts.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index c04fb531d63d..acf00896f48a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -145,6 +145,18 @@ config TOUCHSCREEN_FUJITSU To compile this driver as a module, choose M here: the module will be called fujitsu-ts. +config TOUCHSCREEN_S3C2410 + tristate "Samsung S3C2410 touchscreen input driver" + depends on ARCH_S3C2410 + select S3C24XX_ADC + help + Say Y here if you have the s3c2410 touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s3c2410_ts. + config TOUCHSCREEN_GUNZE tristate "Gunze AHL-51S touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 1f5cccd3a16a..f1f59c9e1211 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -26,7 +26,9 @@ obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o +obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o +obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o @@ -42,4 +44,3 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o -obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c new file mode 100644 index 000000000000..6386b441ef85 --- /dev/null +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -0,0 +1,457 @@ +/* + * Samsung S3C24XX touchscreen driver + * + * This program is free software; you can redistribute it and/or modify + * it under the term of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright 2004 Arnaud Patard + * Copyright 2008 Ben Dooks + * Copyright 2009 Simtec Electronics + * + * Additional work by Herbert Pötzl and + * Harald Welte + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0)) + +#define INT_DOWN (0) +#define INT_UP (1 << 8) + +#define WAIT4INT (S3C2410_ADCTSC_YM_SEN | \ + S3C2410_ADCTSC_YP_SEN | \ + S3C2410_ADCTSC_XP_SEN | \ + S3C2410_ADCTSC_XY_PST(3)) + +#define AUTOPST (S3C2410_ADCTSC_YM_SEN | \ + S3C2410_ADCTSC_YP_SEN | \ + S3C2410_ADCTSC_XP_SEN | \ + S3C2410_ADCTSC_AUTO_PST | \ + S3C2410_ADCTSC_XY_PST(0)) + +/* Per-touchscreen data. */ + +/** + * struct s3c2410ts - driver touchscreen state. + * @client: The ADC client we registered with the core driver. + * @dev: The device we are bound to. + * @input: The input device we registered with the input subsystem. + * @clock: The clock for the adc. + * @io: Pointer to the IO base. + * @xp: The accumulated X position data. + * @yp: The accumulated Y position data. + * @irq_tc: The interrupt number for pen up/down interrupt + * @count: The number of samples collected. + * @shift: The log2 of the maximum count to read in one go. + */ +struct s3c2410ts { + struct s3c_adc_client *client; + struct device *dev; + struct input_dev *input; + struct clk *clock; + void __iomem *io; + unsigned long xp; + unsigned long yp; + int irq_tc; + int count; + int shift; +}; + +static struct s3c2410ts ts; + +/** + * s3c2410_ts_connect - configure gpio for s3c2410 systems + * + * Configure the GPIO for the S3C2410 system, where we have external FETs + * connected to the device (later systems such as the S3C2440 integrate + * these into the device). +*/ +static inline void s3c2410_ts_connect(void) +{ + s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON); + s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON); + s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON); + s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON); +} + +/** + * get_down - return the down state of the pen + * @data0: The data read from ADCDAT0 register. + * @data1: The data read from ADCDAT1 register. + * + * Return non-zero if both readings show that the pen is down. + */ +static inline bool get_down(unsigned long data0, unsigned long data1) +{ + /* returns true if both data values show stylus down */ + return (!(data0 & S3C2410_ADCDAT0_UPDOWN) && + !(data1 & S3C2410_ADCDAT0_UPDOWN)); +} + +static void touch_timer_fire(unsigned long data) +{ + unsigned long data0; + unsigned long data1; + bool down; + + data0 = readl(ts.io + S3C2410_ADCDAT0); + data1 = readl(ts.io + S3C2410_ADCDAT1); + + down = get_down(data0, data1); + + if (ts.count == (1 << ts.shift)) { + ts.xp >>= ts.shift; + ts.yp >>= ts.shift; + + dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n", + __func__, ts.xp, ts.yp, ts.count); + + input_report_abs(ts.input, ABS_X, ts.xp); + input_report_abs(ts.input, ABS_Y, ts.yp); + + input_report_key(ts.input, BTN_TOUCH, 1); + input_sync(ts.input); + + ts.xp = 0; + ts.yp = 0; + ts.count = 0; + } + + if (down) { + s3c_adc_start(ts.client, 0, 1 << ts.shift); + } else { + ts.count = 0; + + input_report_key(ts.input, BTN_TOUCH, 0); + input_sync(ts.input); + + writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); + } +} + +static DEFINE_TIMER(touch_timer, touch_timer_fire, 0, 0); + +/** + * stylus_irq - touchscreen stylus event interrupt + * @irq: The interrupt number + * @dev_id: The device ID. + * + * Called when the IRQ_TC is fired for a pen up or down event. + */ +static irqreturn_t stylus_irq(int irq, void *dev_id) +{ + unsigned long data0; + unsigned long data1; + bool down; + + data0 = readl(ts.io + S3C2410_ADCDAT0); + data1 = readl(ts.io + S3C2410_ADCDAT1); + + down = get_down(data0, data1); + + /* TODO we should never get an interrupt with down set while + * the timer is running, but maybe we ought to verify that the + * timer isn't running anyways. */ + + if (down) + s3c_adc_start(ts.client, 0, 1 << ts.shift); + else + dev_info(ts.dev, "%s: count=%d\n", __func__, ts.count); + + return IRQ_HANDLED; +} + +/** + * s3c24xx_ts_conversion - ADC conversion callback + * @client: The client that was registered with the ADC core. + * @data0: The reading from ADCDAT0. + * @data1: The reading from ADCDAT1. + * @left: The number of samples left. + * + * Called when a conversion has finished. + */ +static void s3c24xx_ts_conversion(struct s3c_adc_client *client, + unsigned data0, unsigned data1, + unsigned *left) +{ + dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1); + + ts.xp += data0; + ts.yp += data1; + + ts.count++; + + /* From tests, it seems that it is unlikely to get a pen-up + * event during the conversion process which means we can + * ignore any pen-up events with less than the requisite + * count done. + * + * In several thousand conversions, no pen-ups where detected + * before count completed. + */ +} + +/** + * s3c24xx_ts_select - ADC selection callback. + * @client: The client that was registered with the ADC core. + * @select: The reason for select. + * + * Called when the ADC core selects (or deslects) us as a client. + */ +static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select) +{ + if (select) { + writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, + ts.io + S3C2410_ADCTSC); + } else { + mod_timer(&touch_timer, jiffies+1); + writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC); + } +} + +/** + * s3c2410ts_probe - device core probe entry point + * @pdev: The device we are being bound to. + * + * Initialise, find and allocate any resources we need to run and then + * register with the ADC and input systems. + */ +static int __devinit s3c2410ts_probe(struct platform_device *pdev) +{ + struct s3c2410_ts_mach_info *info; + struct device *dev = &pdev->dev; + struct input_dev *input_dev; + struct resource *res; + int ret = -EINVAL; + + /* Initialise input stuff */ + memset(&ts, 0, sizeof(struct s3c2410ts)); + + ts.dev = dev; + + info = pdev->dev.platform_data; + if (!info) { + dev_err(dev, "no platform data, cannot attach\n"); + return -EINVAL; + } + + dev_dbg(dev, "initialising touchscreen\n"); + + ts.clock = clk_get(dev, "adc"); + if (IS_ERR(ts.clock)) { + dev_err(dev, "cannot get adc clock source\n"); + return -ENOENT; + } + + clk_enable(ts.clock); + dev_dbg(dev, "got and enabled clocks\n"); + + ts.irq_tc = ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "no resource for interrupt\n"); + goto err_clk; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no resource for registers\n"); + ret = -ENOENT; + goto err_clk; + } + + ts.io = ioremap(res->start, resource_size(res)); + if (ts.io == NULL) { + dev_err(dev, "cannot map registers\n"); + ret = -ENOMEM; + goto err_clk; + } + + /* Configure the touchscreen external FETs on the S3C2410 */ + if (!platform_get_device_id(pdev)->driver_data) + s3c2410_ts_connect(); + + ts.client = s3c_adc_register(pdev, s3c24xx_ts_select, + s3c24xx_ts_conversion, 1); + if (IS_ERR(ts.client)) { + dev_err(dev, "failed to register adc client\n"); + ret = PTR_ERR(ts.client); + goto err_iomap; + } + + /* Initialise registers */ + if ((info->delay & 0xffff) > 0) + writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); + + writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(dev, "Unable to allocate the input device !!\n"); + ret = -ENOMEM; + goto err_iomap; + } + + ts.input = input_dev; + ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0); + input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0); + + ts.input->name = "S3C24XX TouchScreen"; + ts.input->id.bustype = BUS_HOST; + ts.input->id.vendor = 0xDEAD; + ts.input->id.product = 0xBEEF; + ts.input->id.version = 0x0102; + + ts.shift = info->oversampling_shift; + + ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED, + "s3c2410_ts_pen", ts.input); + if (ret) { + dev_err(dev, "cannot get TC interrupt\n"); + goto err_inputdev; + } + + dev_info(dev, "driver attached, registering input device\n"); + + /* All went ok, so register to the input system */ + ret = input_register_device(ts.input); + if (ret < 0) { + dev_err(dev, "failed to register input device\n"); + ret = -EIO; + goto err_tcirq; + } + + return 0; + + err_tcirq: + free_irq(ts.irq_tc, ts.input); + err_inputdev: + input_unregister_device(ts.input); + err_iomap: + iounmap(ts.io); + err_clk: + del_timer_sync(&touch_timer); + clk_put(ts.clock); + return ret; +} + +/** + * s3c2410ts_remove - device core removal entry point + * @pdev: The device we are being removed from. + * + * Free up our state ready to be removed. + */ +static int __devexit s3c2410ts_remove(struct platform_device *pdev) +{ + free_irq(ts.irq_tc, ts.input); + del_timer_sync(&touch_timer); + + clk_disable(ts.clock); + clk_put(ts.clock); + + input_unregister_device(ts.input); + iounmap(ts.io); + + return 0; +} + +#ifdef CONFIG_PM +static int s3c2410ts_suspend(struct device *dev) +{ + writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC); + disable_irq(ts.irq_tc); + clk_disable(ts.clock); + + return 0; +} + +static int s3c2410ts_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s3c2410_ts_mach_info *info = pdev->dev.platform_data; + + clk_enable(ts.clock); + + /* Initialise registers */ + if ((info->delay & 0xffff) > 0) + writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); + + writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); + + return 0; +} + +static struct dev_pm_ops s3c_ts_pmops = { + .suspend = s3c2410ts_suspend, + .resume = s3c2410ts_resume, +}; +#endif + +static struct platform_device_id s3cts_driver_ids[] = { + { "s3c2410-ts", 0 }, + { "s3c2440-ts", 1 }, + { } +}; +MODULE_DEVICE_TABLE(platform, s3cts_driver_ids); + +static struct platform_driver s3c_ts_driver = { + .driver = { + .name = "s3c24xx-ts", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &s3c_ts_pmops, +#endif + }, + .id_table = s3cts_driver_ids, + .probe = s3c2410ts_probe, + .remove = __devexit_p(s3c2410ts_remove), +}; + +static int __init s3c2410ts_init(void) +{ + return platform_driver_register(&s3c_ts_driver); +} + +static void __exit s3c2410ts_exit(void) +{ + platform_driver_unregister(&s3c_ts_driver); +} + +module_init(s3c2410ts_init); +module_exit(s3c2410ts_exit); + +MODULE_AUTHOR("Arnaud Patard , " + "Ben Dooks , " + "Simtec Electronics "); +MODULE_DESCRIPTION("S3C24XX Touchscreen driver"); +MODULE_LICENSE("GPL v2"); From 381f3f1ccf380d4d3c46987d04c199842d4c6e1f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 18 Nov 2009 23:10:54 -0800 Subject: [PATCH 33/51] Input: polled device - schedule first poll immediately It does not make sense to wait poll_interval before performing first read after opening the device, schedule the read immediately instead. Signed-off-by: Dmitry Torokhov --- drivers/input/input-polldev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 31874275fed0..40cf0b058927 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -88,8 +88,7 @@ static int input_open_polled_device(struct input_dev *input) if (dev->open) dev->open(dev); - queue_delayed_work(polldev_wq, &dev->work, - msecs_to_jiffies(dev->poll_interval)); + queue_delayed_work(polldev_wq, &dev->work, 0); return 0; } From 11bb4cc7c772963952304398f999fc195b0da285 Mon Sep 17 00:00:00 2001 From: Samu Onkalo Date: Mon, 23 Nov 2009 10:01:33 -0800 Subject: [PATCH 34/51] Input: polled device - do not start polling if interval is zero If the poll interval is set to 0 via new sysfs entry and device is opened after that, polling is started with interval 0. This causes huge CPU load. Same happens if the rate was 0 when the device was closed and then reopened. Signed-off-by: Samu Onkalo Signed-off-by: Dmitry Torokhov --- drivers/input/input-polldev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 40cf0b058927..6a2eb399b988 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -88,7 +88,9 @@ static int input_open_polled_device(struct input_dev *input) if (dev->open) dev->open(dev); - queue_delayed_work(polldev_wq, &dev->work, 0); + /* Only start polling if polling is enabled */ + if (dev->poll_interval > 0) + queue_delayed_work(polldev_wq, &dev->work, 0); return 0; } From dadaae3777cbc1d747d5fd97c3eac94eb9f1a85b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C3=A9veill=C3=A9?= Date: Sun, 29 Nov 2009 23:20:44 -0800 Subject: [PATCH 35/51] Input: xpad - add two new Xbox 360 devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added two new Xbox 360 devices: - HORI Real Arcade Pro.EX - Mad Catz SFIV Fightpad Signed-off-by: Nicolas Léveillé Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 79e3edcced1a..482cb1204e43 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -125,6 +125,7 @@ static const struct xpad_device { { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, + { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX }, @@ -146,6 +147,7 @@ static const struct xpad_device { { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN } }; @@ -212,6 +214,7 @@ static struct usb_device_id xpad_table [] = { XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */ XPAD_XBOX360_VENDOR(0x1bad), /* Rock Band Drums */ + XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ { } }; From dbe1420b4ba398feef035f7cd8181ec2e492228b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20=C5=A0tetiar?= Date: Sun, 29 Nov 2009 23:37:07 -0800 Subject: [PATCH 36/51] Input: usbtouchscreen - add support for ET&T TC5UH touchscreen controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the ET&T TC5UH 5-wire USB touchscreen controller. More info at http://www.etandt.com.tw/board_solution.html Signed-off-by: Petr Å tetiar Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 5 ++++ drivers/input/touchscreen/usbtouchscreen.c | 29 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index acf00896f48a..32fc8ba039aa 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -520,6 +520,11 @@ config TOUCHSCREEN_USB_ZYTRONIC bool "Zytronic controller" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE +config TOUCHSCREEN_USB_ETT_TC5UH + default y + bool "ET&T TC5UH touchscreen controler support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + config TOUCHSCREEN_TOUCHIT213 tristate "Sahara TouchIT-213 touchscreen" select SERIO diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 4474e2339f47..09a5e7341bd5 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -132,6 +132,7 @@ enum { DEVTYPE_JASTEC, DEVTYPE_E2I, DEVTYPE_ZYTRONIC, + DEVTYPE_TC5UH, }; #define USB_DEVICE_HID_CLASS(vend, prod) \ @@ -217,6 +218,10 @@ static struct usb_device_id usbtouch_devices[] = { {USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC}, #endif +#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH + {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH}, +#endif + {} }; @@ -554,6 +559,19 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) } #endif +/***************************************************************************** + * ET&T TC5UH part + */ +#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH +static int tc5uh_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1]; + dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3]; + dev->touch = pkt[0] & 0x01; + + return 1; +} +#endif /***************************************************************************** * IdealTEK URTC1000 Part @@ -844,6 +862,17 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .irq_always = true, }, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH + [DEVTYPE_TC5UH] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .rept_size = 5, + .read_data = tc5uh_read_data, + }, +#endif }; From 21cea58e49cf59e7c77ce2a01be432458e9f99a9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 Nov 2009 23:40:58 -0800 Subject: [PATCH 37/51] Input: keyboard - add locking around event handling Keyboard input handler is multiplexing events form all keyboard-like devices in the system. Because of that per-device lock provided by input core is not enough to prevent clashes in ked_event() and we need our own lock to ensure that only one thread at a time executing kbd_event(). Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 747683f055ed..ca090e57e161 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -132,6 +132,7 @@ int shift_state = 0; */ static struct input_handler kbd_handler; +static DEFINE_SPINLOCK(kbd_event_lock); static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static int dead_key_next; @@ -1296,10 +1297,16 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) static void kbd_event(struct input_handle *handle, unsigned int event_type, unsigned int event_code, int value) { + /* We are called with interrupts disabled, just take the lock */ + spin_lock(&kbd_event_lock); + if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) kbd_rawcode(value); if (event_type == EV_KEY) kbd_keycode(event_code, value, HW_RAW(handle->dev)); + + spin_unlock(&kbd_event_lock); + tasklet_schedule(&keyboard_tasklet); do_poke_blanked_console = 1; schedule_console_callback(); From 6ee88d713fb75ab191515f66edffa4e866386565 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 30 Nov 2009 00:04:02 -0800 Subject: [PATCH 38/51] Input: gpio_keys - scan gpio state at probe and resume time We need to read and report gpio state when we bind the driver to the device and upon resume so that userspace has correct state of the switches (and keys but they are less important since, even if they are happened to be pressed, we'd expect them to be released fairly soon). Signed-off-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 36 +++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 8941a8ba89bf..1aff3b76effd 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -37,10 +37,8 @@ struct gpio_keys_drvdata { struct gpio_button_data data[0]; }; -static void gpio_keys_report_event(struct work_struct *work) +static void gpio_keys_report_event(struct gpio_button_data *bdata) { - struct gpio_button_data *bdata = - container_of(work, struct gpio_button_data, work); struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; @@ -50,6 +48,14 @@ static void gpio_keys_report_event(struct work_struct *work) input_sync(input); } +static void gpio_keys_work_func(struct work_struct *work) +{ + struct gpio_button_data *bdata = + container_of(work, struct gpio_button_data, work); + + gpio_keys_report_event(bdata); +} + static void gpio_keys_timer(unsigned long _data) { struct gpio_button_data *data = (struct gpio_button_data *)_data; @@ -81,7 +87,7 @@ static int __devinit gpio_keys_setup_key(struct device *dev, int irq, error; setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata); - INIT_WORK(&bdata->work, gpio_keys_report_event); + INIT_WORK(&bdata->work, gpio_keys_work_func); error = gpio_request(button->gpio, desc); if (error < 0) { @@ -185,6 +191,11 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) goto fail2; } + /* get current state of buttons */ + for (i = 0; i < pdata->nbuttons; i++) + gpio_keys_report_event(&ddata->data[i]); + input_sync(input); + device_init_wakeup(&pdev->dev, wakeup); return 0; @@ -253,18 +264,21 @@ static int gpio_keys_suspend(struct device *dev) static int gpio_keys_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; int i; - if (device_may_wakeup(&pdev->dev)) { - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - if (button->wakeup) { - int irq = gpio_to_irq(button->gpio); - disable_irq_wake(irq); - } + for (i = 0; i < pdata->nbuttons; i++) { + + struct gpio_keys_button *button = &pdata->buttons[i]; + if (button->wakeup && device_may_wakeup(&pdev->dev)) { + int irq = gpio_to_irq(button->gpio); + disable_irq_wake(irq); } + + gpio_keys_report_event(&ddata->data[i]); } + input_sync(ddata->input); return 0; } From 66d2a5952eab875f1286e04f738ef029afdaf013 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 1 Dec 2009 21:54:35 -0800 Subject: [PATCH 39/51] Input: keyboard - fix lack of locking when traversing handler->h_list Keyboard handler should not attempt to traverse handler->h_list on its own, without any locking, otherwise it races with registering and unregistering of input handles which leads to crashes. Introduce input_handler_for_each_handle() helper that allows safely iterate over all handles attached to a particular handler and switch keyboard handler to use it. Reported-by: Jim Paradis Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 200 +++++++++++++++++++++------------------- drivers/input/input.c | 37 +++++++- include/linux/input.h | 10 +- 3 files changed, 147 insertions(+), 100 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index ca090e57e161..ff8e9345f3c9 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -46,8 +46,6 @@ extern void ctrl_alt_del(void); -#define to_handle_h(n) container_of(n, struct input_handle, h_node) - /* * Exported functions/variables */ @@ -191,78 +189,85 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier); * etc.). So this means that scancodes for the extra function keys won't * be valid for the first event device, but will be for the second. */ + +struct getset_keycode_data { + unsigned int scancode; + unsigned int keycode; + int error; +}; + +static int getkeycode_helper(struct input_handle *handle, void *data) +{ + struct getset_keycode_data *d = data; + + d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode); + + return d->error == 0; /* stop as soon as we successfully get one */ +} + int getkeycode(unsigned int scancode) { - struct input_handle *handle; - int keycode; - int error = -ENODEV; + struct getset_keycode_data d = { scancode, 0, -ENODEV }; - list_for_each_entry(handle, &kbd_handler.h_list, h_node) { - error = input_get_keycode(handle->dev, scancode, &keycode); - if (!error) - return keycode; - } + input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper); - return error; + return d.error ?: d.keycode; +} + +static int setkeycode_helper(struct input_handle *handle, void *data) +{ + struct getset_keycode_data *d = data; + + d->error = input_set_keycode(handle->dev, d->scancode, d->keycode); + + return d->error == 0; /* stop as soon as we successfully set one */ } int setkeycode(unsigned int scancode, unsigned int keycode) { - struct input_handle *handle; - int error = -ENODEV; + struct getset_keycode_data d = { scancode, keycode, -ENODEV }; - list_for_each_entry(handle, &kbd_handler.h_list, h_node) { - error = input_set_keycode(handle->dev, scancode, keycode); - if (!error) - break; - } + input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper); - return error; + return d.error; } /* * Making beeps and bells. */ + +static int kd_sound_helper(struct input_handle *handle, void *data) +{ + unsigned int *hz = data; + struct input_dev *dev = handle->dev; + + if (test_bit(EV_SND, dev->evbit)) { + if (test_bit(SND_TONE, dev->sndbit)) + input_inject_event(handle, EV_SND, SND_TONE, *hz); + if (test_bit(SND_BELL, handle->dev->sndbit)) + input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0); + } + + return 0; +} + static void kd_nosound(unsigned long ignored) { - struct input_handle *handle; + static unsigned int zero; - list_for_each_entry(handle, &kbd_handler.h_list, h_node) { - if (test_bit(EV_SND, handle->dev->evbit)) { - if (test_bit(SND_TONE, handle->dev->sndbit)) - input_inject_event(handle, EV_SND, SND_TONE, 0); - if (test_bit(SND_BELL, handle->dev->sndbit)) - input_inject_event(handle, EV_SND, SND_BELL, 0); - } - } + input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper); } static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); void kd_mksound(unsigned int hz, unsigned int ticks) { - struct list_head *node; + del_timer_sync(&kd_mksound_timer); - del_timer(&kd_mksound_timer); + input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper); - if (hz) { - list_for_each_prev(node, &kbd_handler.h_list) { - struct input_handle *handle = to_handle_h(node); - if (test_bit(EV_SND, handle->dev->evbit)) { - if (test_bit(SND_TONE, handle->dev->sndbit)) { - input_inject_event(handle, EV_SND, SND_TONE, hz); - break; - } - if (test_bit(SND_BELL, handle->dev->sndbit)) { - input_inject_event(handle, EV_SND, SND_BELL, 1); - break; - } - } - } - if (ticks) - mod_timer(&kd_mksound_timer, jiffies + ticks); - } else - kd_nosound(0); + if (hz && ticks) + mod_timer(&kd_mksound_timer, jiffies + ticks); } EXPORT_SYMBOL(kd_mksound); @@ -270,27 +275,34 @@ EXPORT_SYMBOL(kd_mksound); * Setting the keyboard rate. */ +static int kbd_rate_helper(struct input_handle *handle, void *data) +{ + struct input_dev *dev = handle->dev; + struct kbd_repeat *rep = data; + + if (test_bit(EV_REP, dev->evbit)) { + + if (rep[0].delay > 0) + input_inject_event(handle, + EV_REP, REP_DELAY, rep[0].delay); + if (rep[0].period > 0) + input_inject_event(handle, + EV_REP, REP_PERIOD, rep[0].period); + + rep[1].delay = dev->rep[REP_DELAY]; + rep[1].period = dev->rep[REP_PERIOD]; + } + + return 0; +} + int kbd_rate(struct kbd_repeat *rep) { - struct list_head *node; - unsigned int d = 0; - unsigned int p = 0; + struct kbd_repeat data[2] = { *rep }; - list_for_each(node, &kbd_handler.h_list) { - struct input_handle *handle = to_handle_h(node); - struct input_dev *dev = handle->dev; + input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper); + *rep = data[1]; /* Copy currently used settings */ - if (test_bit(EV_REP, dev->evbit)) { - if (rep->delay > 0) - input_inject_event(handle, EV_REP, REP_DELAY, rep->delay); - if (rep->period > 0) - input_inject_event(handle, EV_REP, REP_PERIOD, rep->period); - d = dev->rep[REP_DELAY]; - p = dev->rep[REP_PERIOD]; - } - } - rep->delay = d; - rep->period = p; return 0; } @@ -998,36 +1010,36 @@ static inline unsigned char getleds(void) return leds; } -/* - * This routine is the bottom half of the keyboard interrupt - * routine, and runs with all interrupts enabled. It does - * console changing, led setting and copy_to_cooked, which can - * take a reasonably long time. - * - * Aside from timing (which isn't really that important for - * keyboard interrupts as they happen often), using the software - * interrupt routines for this thing allows us to easily mask - * this when we don't want any of the above to happen. - * This allows for easy and efficient race-condition prevention - * for kbd_start => input_inject_event(dev, EV_LED, ...) => ... - */ +static int kbd_update_leds_helper(struct input_handle *handle, void *data) +{ + unsigned char leds = *(unsigned char *)data; + if (test_bit(EV_LED, handle->dev->evbit)) { + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_SYN, SYN_REPORT, 0); + } + + return 0; +} + +/* + * This is the tasklet that updates LED state on all keyboards + * attached to the box. The reason we use tasklet is that we + * need to handle the scenario when keyboard handler is not + * registered yet but we already getting updates form VT to + * update led state. + */ static void kbd_bh(unsigned long dummy) { - struct list_head *node; unsigned char leds = getleds(); if (leds != ledstate) { - list_for_each(node, &kbd_handler.h_list) { - struct input_handle *handle = to_handle_h(node); - input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); - input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_inject_event(handle, EV_SYN, SYN_REPORT, 0); - } + input_handler_for_each_handle(&kbd_handler, &leds, + kbd_update_leds_helper); + ledstate = leds; } - - ledstate = leds; } DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); @@ -1370,15 +1382,11 @@ static void kbd_disconnect(struct input_handle *handle) */ static void kbd_start(struct input_handle *handle) { - unsigned char leds = ledstate; - tasklet_disable(&keyboard_tasklet); - if (leds != 0xff) { - input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); - input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_inject_event(handle, EV_SYN, SYN_REPORT, 0); - } + + if (ledstate != 0xff) + kbd_update_leds_helper(handle, &ledstate); + tasklet_enable(&keyboard_tasklet); } diff --git a/drivers/input/input.c b/drivers/input/input.c index cc763c96fada..5d6421bde4ba 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1650,6 +1650,38 @@ void input_unregister_handler(struct input_handler *handler) } EXPORT_SYMBOL(input_unregister_handler); +/** + * input_handler_for_each_handle - handle iterator + * @handler: input handler to iterate + * @data: data for the callback + * @fn: function to be called for each handle + * + * Iterate over @bus's list of devices, and call @fn for each, passing + * it @data and stop when @fn returns a non-zero value. The function is + * using RCU to traverse the list and therefore may be usind in atonic + * contexts. The @fn callback is invoked from RCU critical section and + * thus must not sleep. + */ +int input_handler_for_each_handle(struct input_handler *handler, void *data, + int (*fn)(struct input_handle *, void *)) +{ + struct input_handle *handle; + int retval = 0; + + rcu_read_lock(); + + list_for_each_entry_rcu(handle, &handler->h_list, h_node) { + retval = fn(handle, data); + if (retval) + break; + } + + rcu_read_unlock(); + + return retval; +} +EXPORT_SYMBOL(input_handler_for_each_handle); + /** * input_register_handle - register a new input handle * @handle: handle to register @@ -1683,7 +1715,7 @@ int input_register_handle(struct input_handle *handle) * we can't be racing with input_unregister_handle() * and so separate lock is not needed here. */ - list_add_tail(&handle->h_node, &handler->h_list); + list_add_tail_rcu(&handle->h_node, &handler->h_list); if (handler->start) handler->start(handle); @@ -1706,7 +1738,7 @@ void input_unregister_handle(struct input_handle *handle) { struct input_dev *dev = handle->dev; - list_del_init(&handle->h_node); + list_del_rcu(&handle->h_node); /* * Take dev->mutex to prevent race with input_release_device(). @@ -1714,6 +1746,7 @@ void input_unregister_handle(struct input_handle *handle) mutex_lock(&dev->mutex); list_del_rcu(&handle->d_node); mutex_unlock(&dev->mutex); + synchronize_rcu(); } EXPORT_SYMBOL(input_unregister_handle); diff --git a/include/linux/input.h b/include/linux/input.h index 56d8e048c646..db563bbac9dd 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1021,9 +1021,12 @@ struct ff_effect { * @keycodesize: size of elements in keycode table * @keycode: map of scancodes to keycodes for this device * @setkeycode: optional method to alter current keymap, used to implement - * sparse keymaps. If not supplied default mechanism will be used + * sparse keymaps. If not supplied default mechanism will be used. + * The method is being called while holding event_lock and thus must + * not sleep * @getkeycode: optional method to retrieve current keymap. If not supplied - * default mechanism will be used + * default mechanism will be used. The method is being called while + * holding event_lock and thus must not sleep * @ff: force feedback structure associated with the device if device * supports force feedback effects * @repeat_key: stores key code of the last key pressed; used to implement @@ -1295,6 +1298,9 @@ void input_unregister_device(struct input_dev *); int __must_check input_register_handler(struct input_handler *); void input_unregister_handler(struct input_handler *); +int input_handler_for_each_handle(struct input_handler *, void *data, + int (*fn)(struct input_handle *, void *)); + int input_register_handle(struct input_handle *); void input_unregister_handle(struct input_handle *); From f72a28aba92d5a599c8a772e443aa8f079b3091f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 3 Dec 2009 22:24:15 -0800 Subject: [PATCH 40/51] Input: matrix-keypad - switch to using dev_pm_ops Acked-by: Rafael J. Wysocki Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/matrix_keypad.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 91cfe5170265..34f4a29d4973 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -213,8 +213,9 @@ static void matrix_keypad_stop(struct input_dev *dev) } #ifdef CONFIG_PM -static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t state) +static int matrix_keypad_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct matrix_keypad *keypad = platform_get_drvdata(pdev); const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i; @@ -228,8 +229,9 @@ static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t stat return 0; } -static int matrix_keypad_resume(struct platform_device *pdev) +static int matrix_keypad_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct matrix_keypad *keypad = platform_get_drvdata(pdev); const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i; @@ -242,9 +244,9 @@ static int matrix_keypad_resume(struct platform_device *pdev) return 0; } -#else -#define matrix_keypad_suspend NULL -#define matrix_keypad_resume NULL + +static const SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops, + matrix_keypad_suspend, matrix_keypad_resume); #endif static int __devinit init_matrix_gpio(struct platform_device *pdev, @@ -417,11 +419,12 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev) static struct platform_driver matrix_keypad_driver = { .probe = matrix_keypad_probe, .remove = __devexit_p(matrix_keypad_remove), - .suspend = matrix_keypad_suspend, - .resume = matrix_keypad_resume, .driver = { .name = "matrix-keypad", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &matrix_keypad_pm_ops, +#endif }, }; From 7705d548cbe33f18ea7713b9a07aa11047aaeca4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 3 Dec 2009 23:21:14 -0800 Subject: [PATCH 41/51] Input: psmouse - do not carry DMI data around DMI tables use considerable amount of memory. Mark them as __initconst so they will be discarded once module is loaded. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/lifebook.c | 20 ++++++++++++++------ drivers/input/mouse/lifebook.h | 4 ++++ drivers/input/mouse/psmouse-base.c | 3 +++ drivers/input/mouse/synaptics.c | 23 ++++++++++++++++------- drivers/input/mouse/synaptics.h | 1 + 5 files changed, 38 insertions(+), 13 deletions(-) diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 54b7f64d6e62..cd81cefdc1c5 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -25,11 +25,13 @@ struct lifebook_data { char phys[32]; }; +static bool lifebook_present; + static const char *desired_serio_phys; -static int lifebook_set_serio_phys(const struct dmi_system_id *d) +static int lifebook_limit_serio3(const struct dmi_system_id *d) { - desired_serio_phys = d->driver_data; + desired_serio_phys = "isa0060/serio3"; return 0; } @@ -41,7 +43,8 @@ static int lifebook_set_6byte_proto(const struct dmi_system_id *d) return 0; } -static const struct dmi_system_id lifebook_dmi_table[] = { +static const struct dmi_system_id __initconst lifebook_dmi_table[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) { .ident = "FLORA-ie 55mi", .matches = { @@ -83,8 +86,7 @@ static const struct dmi_system_id lifebook_dmi_table[] = { .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), }, - .callback = lifebook_set_serio_phys, - .driver_data = "isa0060/serio3", + .callback = lifebook_limit_serio3, }, { .ident = "Panasonic CF-28", @@ -116,8 +118,14 @@ static const struct dmi_system_id lifebook_dmi_table[] = { }, }, { } +#endif }; +void __init lifebook_module_init(void) +{ + lifebook_present = dmi_check_system(lifebook_dmi_table); +} + static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) { struct lifebook_data *priv = psmouse->private; @@ -243,7 +251,7 @@ static void lifebook_disconnect(struct psmouse *psmouse) int lifebook_detect(struct psmouse *psmouse, bool set_properties) { - if (!dmi_check_system(lifebook_dmi_table)) + if (!lifebook_present) return -1; if (desired_serio_phys && diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h index 407cb226bc0a..4c4326c6f504 100644 --- a/drivers/input/mouse/lifebook.h +++ b/drivers/input/mouse/lifebook.h @@ -12,9 +12,13 @@ #define _LIFEBOOK_H #ifdef CONFIG_MOUSE_PS2_LIFEBOOK +void lifebook_module_init(void); int lifebook_detect(struct psmouse *psmouse, bool set_properties); int lifebook_init(struct psmouse *psmouse); #else +inline void lifebook_module_init(void) +{ +} inline int lifebook_detect(struct psmouse *psmouse, bool set_properties) { return -ENOSYS; diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index acd16707696e..fd0bc094616a 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1696,6 +1696,9 @@ static int __init psmouse_init(void) { int err; + lifebook_module_init(); + synaptics_module_init(); + kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); if (!kpsmoused_wq) { printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index f4a61252bcc9..36d6df4c0a78 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -629,9 +630,10 @@ static int synaptics_reconnect(struct psmouse *psmouse) return 0; } -#if defined(__i386__) -#include -static const struct dmi_system_id toshiba_dmi_table[] = { +static bool impaired_toshiba_kbc; + +static const struct dmi_system_id __initconst toshiba_dmi_table[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) { .ident = "Toshiba Satellite", .matches = { @@ -664,8 +666,13 @@ static const struct dmi_system_id toshiba_dmi_table[] = { }, { } -}; #endif +}; + +void __init synaptics_module_init(void) +{ + impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); +} int synaptics_init(struct psmouse *psmouse) { @@ -718,18 +725,16 @@ int synaptics_init(struct psmouse *psmouse) if (SYN_CAP_PASS_THROUGH(priv->capabilities)) synaptics_pt_create(psmouse); -#if defined(__i386__) /* * Toshiba's KBC seems to have trouble handling data from * Synaptics as full rate, switch to lower rate which is roughly * thye same as rate of standard PS/2 mouse. */ - if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) { + if (psmouse->rate >= 80 && impaired_toshiba_kbc) { printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", dmi_get_system_info(DMI_PRODUCT_NAME)); psmouse->rate = 40; } -#endif return 0; @@ -740,6 +745,10 @@ int synaptics_init(struct psmouse *psmouse) #else /* CONFIG_MOUSE_PS2_SYNAPTICS */ +void __init synaptics_module_init(void) +{ +} + int synaptics_init(struct psmouse *psmouse) { return -ENOSYS; diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 871f6fe377f9..838e7f2c9b30 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -105,6 +105,7 @@ struct synaptics_data { int scroll; }; +void synaptics_module_init(void); int synaptics_detect(struct psmouse *psmouse, bool set_properties); int synaptics_init(struct psmouse *psmouse); void synaptics_reset(struct psmouse *psmouse); From 75757507e014fa074d25d2883c4ab604999584bd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Dec 2009 10:24:19 -0800 Subject: [PATCH 42/51] DMI: allow omitting ident strings in DMI tables The purpose of dmi->ident is twofold - it may be used by DMI callback functions when composing log messages; it is also used to determine end of DMI table in dmi_check_system() and dmi_first_match(). However, in case when callbacks are not interested in using ident at all it just wastes memory. Let's make entries with empty first match slot serve as end-of-table markers instead. Acked-by: Jean Delvare Signed-off-by: Dmitry Torokhov --- drivers/firmware/dmi_scan.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 938100f14b16..3a2ccb09e2f8 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -429,7 +429,7 @@ static bool dmi_matches(const struct dmi_system_id *dmi) for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { int s = dmi->matches[i].slot; if (s == DMI_NONE) - continue; + break; if (dmi_ident[s] && strstr(dmi_ident[s], dmi->matches[i].substr)) continue; @@ -439,6 +439,15 @@ static bool dmi_matches(const struct dmi_system_id *dmi) return true; } +/** + * dmi_is_end_of_table - check for end-of-table marker + * @dmi: pointer to the dmi_system_id structure to check + */ +static bool dmi_is_end_of_table(const struct dmi_system_id *dmi) +{ + return dmi->matches[0].slot == DMI_NONE; +} + /** * dmi_check_system - check system DMI data * @list: array of dmi_system_id structures to match against @@ -457,7 +466,7 @@ int dmi_check_system(const struct dmi_system_id *list) int count = 0; const struct dmi_system_id *d; - for (d = list; d->ident; d++) + for (d = list; !dmi_is_end_of_table(d); d++) if (dmi_matches(d)) { count++; if (d->callback && d->callback(d)) @@ -484,7 +493,7 @@ const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) { const struct dmi_system_id *d; - for (d = list; d->ident; d++) + for (d = list; !dmi_is_end_of_table(d); d++) if (dmi_matches(d)) return d; From f909b1df0a068f30e252d8dc3e9d45ca25bf266f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Dec 2009 10:24:19 -0800 Subject: [PATCH 43/51] Input: i8042 - remove identification strings from DMI tables The driver does not reference identification strings in DMI tables and since these strings are no longer required by DMI core we can safely remove them and save some memory. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 143 ++++++++++++-------------- 1 file changed, 66 insertions(+), 77 deletions(-) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 2bcf1ace27c0..7fbffe431bc5 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -67,10 +67,12 @@ static inline void i8042_write_command(int val) #include -static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { { - /* AUX LOOP command does not raise AUX IRQ */ - .ident = "Arima-Rioworks HDAMB", + /* + * Arima-Rioworks HDAMB - + * AUX LOOP command does not raise AUX IRQ + */ .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"), DMI_MATCH(DMI_BOARD_NAME, "HDAMB"), @@ -78,7 +80,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "ASUS G1S", + /* ASUS G1S */ .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_BOARD_NAME, "G1S"), @@ -86,8 +88,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - /* AUX LOOP command does not raise AUX IRQ */ - .ident = "ASUS P65UP5", + /* ASUS P65UP5 - AUX LOOP command does not raise AUX IRQ */ .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"), @@ -95,7 +96,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Compaq Proliant 8500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), @@ -103,7 +103,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Compaq Proliant DL760", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), @@ -111,7 +110,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "OQO Model 01", + /* OQO Model 01 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "OQO"), DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), @@ -119,8 +118,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - /* AUX LOOP does not work properly */ - .ident = "ULI EV4873", + /* ULI EV4873 - AUX LOOP does not work properly */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ULI"), DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"), @@ -128,7 +126,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Microsoft Virtual Machine", + /* Microsoft Virtual Machine */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), @@ -136,7 +134,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Medion MAM 2070", + /* Medion MAM 2070 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"), @@ -144,7 +142,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Blue FB5601", + /* Blue FB5601 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "blue"), DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"), @@ -152,7 +150,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "Gigabyte M912", + /* Gigabyte M912 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_PRODUCT_NAME, "M912"), @@ -160,7 +158,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }, }, { - .ident = "HP DV9700", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), @@ -177,72 +174,72 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { * ... apparently some Toshibas don't like MUX mode either and * die horrible death on reboot. */ -static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { { - .ident = "Fujitsu Lifebook P7010/P7010D", + /* Fujitsu Lifebook P7010/P7010D */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "P7010"), }, }, { - .ident = "Fujitsu Lifebook P7010", + /* Fujitsu Lifebook P7010 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"), }, }, { - .ident = "Fujitsu Lifebook P5020D", + /* Fujitsu Lifebook P5020D */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"), }, }, { - .ident = "Fujitsu Lifebook S2000", + /* Fujitsu Lifebook S2000 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), }, }, { - .ident = "Fujitsu Lifebook S6230", + /* Fujitsu Lifebook S6230 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), }, }, { - .ident = "Fujitsu T70H", + /* Fujitsu T70H */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), }, }, { - .ident = "Fujitsu-Siemens Lifebook T3010", + /* Fujitsu-Siemens Lifebook T3010 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), }, }, { - .ident = "Fujitsu-Siemens Lifebook E4010", + /* Fujitsu-Siemens Lifebook E4010 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), }, }, { - .ident = "Fujitsu-Siemens Amilo Pro 2010", + /* Fujitsu-Siemens Amilo Pro 2010 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"), }, }, { - .ident = "Fujitsu-Siemens Amilo Pro 2030", + /* Fujitsu-Siemens Amilo Pro 2030 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), @@ -253,7 +250,7 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { * No data is coming from the touchscreen unless KBC * is in legacy mode. */ - .ident = "Panasonic CF-29", + /* Panasonic CF-29 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), @@ -261,10 +258,10 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, { /* - * Errors on MUX ports are reported without raising AUXDATA + * HP Pavilion DV4017EA - + * errors on MUX ports are reported without raising AUXDATA * causing "spurious NAK" messages. */ - .ident = "HP Pavilion DV4017EA", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"), @@ -272,9 +269,9 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, { /* - * Like DV4017EA does not raise AUXERR for errors on MUX ports. + * HP Pavilion ZT1000 - + * like DV4017EA does not raise AUXERR for errors on MUX ports. */ - .ident = "HP Pavilion ZT1000", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"), @@ -283,44 +280,41 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, { /* - * Like DV4017EA does not raise AUXERR for errors on MUX ports. + * HP Pavilion DV4270ca - + * like DV4017EA does not raise AUXERR for errors on MUX ports. */ - .ident = "HP Pavilion DV4270ca", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"), }, }, { - .ident = "Toshiba P10", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), }, }, { - .ident = "Toshiba Equium A110", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), }, }, { - .ident = "Alienware Sentia", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), }, }, { - .ident = "Sharp Actius MM20", + /* Sharp Actius MM20 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SHARP"), DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"), }, }, { - .ident = "Sony Vaio FS-115b", + /* Sony Vaio FS-115b */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), @@ -328,73 +322,72 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, { /* - * Reset and GET ID commands issued via KBD port are + * Sony Vaio FZ-240E - + * reset and GET ID commands issued via KBD port are * sometimes being delivered to AUX3. */ - .ident = "Sony Vaio FZ-240E", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"), }, }, { - .ident = "Amoi M636/A737", + /* Amoi M636/A737 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."), DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), }, }, { - .ident = "Lenovo 3000 n100", + /* Lenovo 3000 n100 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "076804U"), }, }, { - .ident = "Acer Aspire 1360", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), }, }, { - .ident = "Gericom Bellagio", + /* Gericom Bellagio */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), }, }, { - .ident = "IBM 2656", + /* IBM 2656 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), DMI_MATCH(DMI_PRODUCT_NAME, "2656"), }, }, { - .ident = "Dell XPS M1530", + /* Dell XPS M1530 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"), }, }, { - .ident = "Compal HEL80I", + /* Compal HEL80I */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"), DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), }, }, { - .ident = "Dell Vostro 1510", + /* Dell Vostro 1510 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), }, }, { - .ident = "Acer Aspire 5536", + /* Acer Aspire 5536 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"), @@ -404,65 +397,65 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { { } }; -static struct dmi_system_id __initdata i8042_dmi_reset_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { { - .ident = "MSI Wind U-100", + /* MSI Wind U-100 */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "U-100"), DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), }, }, { - .ident = "LG Electronics X110", + /* LG Electronics X110 */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "X110"), DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."), }, }, { - .ident = "Acer Aspire One 150", + /* Acer Aspire One 150 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), }, }, { - .ident = "Advent 4211", + /* Advent 4211 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"), DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"), }, }, { - .ident = "Medion Akoya Mini E1210", + /* Medion Akoya Mini E1210 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), DMI_MATCH(DMI_PRODUCT_NAME, "E1210"), }, }, { - .ident = "Mivvy M310", + /* Mivvy M310 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"), DMI_MATCH(DMI_PRODUCT_NAME, "N10"), }, }, { - .ident = "Dell Vostro 1320", + /* Dell Vostro 1320 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"), }, }, { - .ident = "Dell Vostro 1520", + /* Dell Vostro 1520 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"), }, }, { - .ident = "Dell Vostro 1720", + /* Dell Vostro 1720 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"), @@ -472,16 +465,16 @@ static struct dmi_system_id __initdata i8042_dmi_reset_table[] = { }; #ifdef CONFIG_PNP -static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_nopnp_table[] = { { - .ident = "Intel MBO Desktop D845PESV", + /* Intel MBO Desktop D845PESV */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "D845PESV"), DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), }, }, { - .ident = "MSI Wind U-100", + /* MSI Wind U-100 */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "U-100"), DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), @@ -490,27 +483,23 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { { } }; -static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = { { - .ident = "Portable", .matches = { DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ }, }, { - .ident = "Laptop", .matches = { DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */ }, }, { - .ident = "Notebook", .matches = { DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ }, }, { - .ident = "Sub-Notebook", .matches = { DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ }, @@ -525,58 +514,58 @@ static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = { * Originally, this was just confined to older laptops, but a few Acer laptops * have turned up in 2007 that also need this again. */ -static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { +static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = { { - .ident = "Acer Aspire 5630", + /* Acer Aspire 5630 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), }, }, { - .ident = "Acer Aspire 5650", + /* Acer Aspire 5650 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), }, }, { - .ident = "Acer Aspire 5680", + /* Acer Aspire 5680 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), }, }, { - .ident = "Acer Aspire 5720", + /* Acer Aspire 5720 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"), }, }, { - .ident = "Acer Aspire 9110", + /* Acer Aspire 9110 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), }, }, { - .ident = "Acer TravelMate 660", + /* Acer TravelMate 660 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), }, }, { - .ident = "Acer TravelMate 2490", + /* Acer TravelMate 2490 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), }, }, { - .ident = "Acer TravelMate 4280", + /* Acer TravelMate 4280 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"), From c45fc81ec6a9bd6cca42e60b35b31f9df822860b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Dec 2009 10:24:19 -0800 Subject: [PATCH 44/51] Input: atkbd - remove identification strings from DMI table The driver does not reference identification strings in DMI table and since these strings are no longer required by DMI core we can safely remove them and save some memory. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 28e6110d1ff8..a3573570c52f 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -1567,9 +1567,8 @@ static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id) return 0; } -static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { +static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { { - .ident = "Dell Laptop", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ @@ -1578,7 +1577,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_dell_laptop_forced_release_keys, }, { - .ident = "Dell Laptop", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ @@ -1587,7 +1585,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_dell_laptop_forced_release_keys, }, { - .ident = "HP 2133", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"), @@ -1596,7 +1593,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_hp_forced_release_keys, }, { - .ident = "HP Pavilion ZV6100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), @@ -1605,7 +1601,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "HP Presario R4000", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"), @@ -1614,7 +1609,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "HP Presario R4100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"), @@ -1623,7 +1617,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "HP Presario R4200", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"), @@ -1632,7 +1625,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "Inventec Symphony", + /* Inventec Symphony */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), @@ -1641,7 +1634,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "Samsung NC10", + /* Samsung NC10 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), @@ -1650,7 +1643,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_samsung_forced_release_keys, }, { - .ident = "Samsung NC20", + /* Samsung NC20 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), DMI_MATCH(DMI_PRODUCT_NAME, "NC20"), @@ -1659,7 +1652,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_samsung_forced_release_keys, }, { - .ident = "Samsung SQ45S70S", + /* Samsung SQ45S70S */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), @@ -1668,7 +1661,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_samsung_forced_release_keys, }, { - .ident = "Fujitsu Amilo PA 1510", + /* Fujitsu Amilo PA 1510 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"), @@ -1677,7 +1670,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_volume_forced_release_keys, }, { - .ident = "Fujitsu Amilo Pi 3525", + /* Fujitsu Amilo Pi 3525 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"), @@ -1686,7 +1679,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_amilo_pi3525_forced_release_keys, }, { - .ident = "Fujitsu Amilo Xi 3650", + /* Fujitsu Amilo Xi 3650 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"), @@ -1695,7 +1688,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_amilo_xi3650_forced_release_keys, }, { - .ident = "Soltech Corporation TA12", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "TA12"), @@ -1704,7 +1696,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkdb_soltech_ta12_forced_release_keys, }, { - .ident = "OQO Model 01+", + /* OQO Model 01+ */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "OQO"), DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), From 9961e25976493f4d50704dafc0e8ff8365181538 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Dec 2009 10:24:20 -0800 Subject: [PATCH 45/51] Input: psmouse - remove identification strings from DMI tables The driver does not reference identification strings in DMI tables and since these strings are no longer required by DMI core we can safely remove them and save some memory. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/lifebook.c | 22 +++++++++++----------- drivers/input/mouse/synaptics.c | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index cd81cefdc1c5..2e6bdfea0165 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -46,50 +46,50 @@ static int lifebook_set_6byte_proto(const struct dmi_system_id *d) static const struct dmi_system_id __initconst lifebook_dmi_table[] = { #if defined(CONFIG_DMI) && defined(CONFIG_X86) { - .ident = "FLORA-ie 55mi", + /* FLORA-ie 55mi */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"), }, }, { - .ident = "LifeBook B", + /* LifeBook B */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"), }, }, { - .ident = "Lifebook B", + /* Lifebook B */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"), }, }, { - .ident = "Lifebook B-2130", + /* Lifebook B-2130 */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "ZEPHYR"), }, }, { - .ident = "Lifebook B213x/B2150", + /* Lifebook B213x/B2150 */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"), }, }, { - .ident = "Zephyr", + /* Zephyr */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"), }, }, { - .ident = "CF-18", + /* Panasonic CF-18 */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), }, .callback = lifebook_limit_serio3, }, { - .ident = "Panasonic CF-28", + /* Panasonic CF-28 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"), @@ -97,7 +97,7 @@ static const struct dmi_system_id __initconst lifebook_dmi_table[] = { .callback = lifebook_set_6byte_proto, }, { - .ident = "Panasonic CF-29", + /* Panasonic CF-29 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), @@ -105,14 +105,14 @@ static const struct dmi_system_id __initconst lifebook_dmi_table[] = { .callback = lifebook_set_6byte_proto, }, { - .ident = "CF-72", + /* Panasonic CF-72 */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"), }, .callback = lifebook_set_6byte_proto, }, { - .ident = "Lifebook B142", + /* Lifebook B142 */ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"), }, diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 36d6df4c0a78..05689e732191 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -635,21 +635,21 @@ static bool impaired_toshiba_kbc; static const struct dmi_system_id __initconst toshiba_dmi_table[] = { #if defined(CONFIG_DMI) && defined(CONFIG_X86) { - .ident = "Toshiba Satellite", + /* Toshiba Satellite */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"), }, }, { - .ident = "Toshiba Dynabook", + /* Toshiba Dynabook */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"), }, }, { - .ident = "Toshiba Portege M300", + /* Toshiba Portege M300 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"), @@ -657,7 +657,7 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = { }, { - .ident = "Toshiba Portege M300", + /* Toshiba Portege M300 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"), From a9b0d0e57de88030527a95edea2722851897b7dd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Dec 2009 10:24:19 -0800 Subject: [PATCH 46/51] Input: wistron - remove identification strings from DMI table The driver does not reference identification strings in DMI table and since these strings are no longer required by DMI core we can safely remove them and save some memory. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 76 +++++++++++++++---------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 00eb9d651d97..f9d2bc87b355 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -644,10 +644,10 @@ static struct key_entry keymap_prestigio[] __initdata = { * a list of buttons and their key codes (reported when loading this module * with force=1) and the output of dmidecode to $MODULE_AUTHOR. */ -static struct dmi_system_id dmi_ids[] __initdata = { +static const struct dmi_system_id __initconst dmi_ids[] = { { + /* Fujitsu-Siemens Amilo Pro V2000 */ .callback = dmi_matched, - .ident = "Fujitsu-Siemens Amilo Pro V2000", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"), @@ -655,8 +655,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Fujitsu-Siemens Amilo Pro Edition V3505 */ .callback = dmi_matched, - .ident = "Fujitsu-Siemens Amilo Pro Edition V3505", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"), @@ -664,8 +664,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v3505 }, { + /* Fujitsu-Siemens Amilo M7400 */ .callback = dmi_matched, - .ident = "Fujitsu-Siemens Amilo M7400", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "), @@ -673,8 +673,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Maxdata Pro 7000 DX */ .callback = dmi_matched, - .ident = "Maxdata Pro 7000 DX", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"), DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"), @@ -682,8 +682,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Fujitsu N3510 */ .callback = dmi_matched, - .ident = "Fujitsu N3510", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "N3510"), @@ -691,8 +691,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fujitsu_n3510 }, { + /* Acer Aspire 1500 */ .callback = dmi_matched, - .ident = "Acer Aspire 1500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"), @@ -700,8 +700,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_1500 }, { + /* Acer Aspire 1600 */ .callback = dmi_matched, - .ident = "Acer Aspire 1600", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"), @@ -709,8 +709,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_1600 }, { + /* Acer Aspire 3020 */ .callback = dmi_matched, - .ident = "Acer Aspire 3020", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"), @@ -718,8 +718,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_5020 }, { + /* Acer Aspire 5020 */ .callback = dmi_matched, - .ident = "Acer Aspire 5020", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"), @@ -727,8 +727,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_5020 }, { + /* Acer TravelMate 2100 */ .callback = dmi_matched, - .ident = "Acer TravelMate 2100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"), @@ -736,8 +736,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_5020 }, { + /* Acer TravelMate 2410 */ .callback = dmi_matched, - .ident = "Acer TravelMate 2410", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"), @@ -745,8 +745,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_2410 }, { + /* Acer TravelMate C300 */ .callback = dmi_matched, - .ident = "Acer TravelMate C300", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"), @@ -754,8 +754,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_300 }, { + /* Acer TravelMate C100 */ .callback = dmi_matched, - .ident = "Acer TravelMate C100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"), @@ -763,8 +763,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_300 }, { + /* Acer TravelMate C110 */ .callback = dmi_matched, - .ident = "Acer TravelMate C110", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"), @@ -772,8 +772,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_110 }, { + /* Acer TravelMate 380 */ .callback = dmi_matched, - .ident = "Acer TravelMate 380", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"), @@ -781,8 +781,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_380 }, { + /* Acer TravelMate 370 */ .callback = dmi_matched, - .ident = "Acer TravelMate 370", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"), @@ -790,8 +790,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */ }, { + /* Acer TravelMate 220 */ .callback = dmi_matched, - .ident = "Acer TravelMate 220", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"), @@ -799,8 +799,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_220 }, { + /* Acer TravelMate 260 */ .callback = dmi_matched, - .ident = "Acer TravelMate 260", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"), @@ -808,8 +808,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_220 }, { + /* Acer TravelMate 230 */ .callback = dmi_matched, - .ident = "Acer TravelMate 230", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"), @@ -818,8 +818,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_230 }, { + /* Acer TravelMate 280 */ .callback = dmi_matched, - .ident = "Acer TravelMate 280", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"), @@ -827,8 +827,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_230 }, { + /* Acer TravelMate 240 */ .callback = dmi_matched, - .ident = "Acer TravelMate 240", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"), @@ -836,8 +836,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_240 }, { + /* Acer TravelMate 250 */ .callback = dmi_matched, - .ident = "Acer TravelMate 250", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"), @@ -845,8 +845,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_240 }, { + /* Acer TravelMate 2424NWXCi */ .callback = dmi_matched, - .ident = "Acer TravelMate 2424NWXCi", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"), @@ -854,8 +854,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_240 }, { + /* Acer TravelMate 350 */ .callback = dmi_matched, - .ident = "Acer TravelMate 350", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"), @@ -863,8 +863,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_350 }, { + /* Acer TravelMate 360 */ .callback = dmi_matched, - .ident = "Acer TravelMate 360", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), @@ -872,8 +872,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_360 }, { + /* Acer TravelMate 610 */ .callback = dmi_matched, - .ident = "Acer TravelMate 610", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ACER"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"), @@ -881,8 +881,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_610 }, { + /* Acer TravelMate 620 */ .callback = dmi_matched, - .ident = "Acer TravelMate 620", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"), @@ -890,8 +890,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_630 }, { + /* Acer TravelMate 630 */ .callback = dmi_matched, - .ident = "Acer TravelMate 630", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"), @@ -899,8 +899,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_630 }, { + /* AOpen 1559AS */ .callback = dmi_matched, - .ident = "AOpen 1559AS", .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "E2U"), DMI_MATCH(DMI_BOARD_NAME, "E2U"), @@ -908,8 +908,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_aopen_1559as }, { + /* Medion MD 9783 */ .callback = dmi_matched, - .ident = "Medion MD 9783", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"), @@ -917,8 +917,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_ms2111 }, { + /* Medion MD 40100 */ .callback = dmi_matched, - .ident = "Medion MD 40100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"), @@ -926,8 +926,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md40100 }, { + /* Medion MD 2900 */ .callback = dmi_matched, - .ident = "Medion MD 2900", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"), @@ -935,8 +935,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md2900 }, { + /* Medion MD 42200 */ .callback = dmi_matched, - .ident = "Medion MD 42200", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Medion"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"), @@ -944,8 +944,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Medion MD 96500 */ .callback = dmi_matched, - .ident = "Medion MD 96500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"), @@ -953,8 +953,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md96500 }, { + /* Medion MD 95400 */ .callback = dmi_matched, - .ident = "Medion MD 95400", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"), @@ -962,8 +962,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md96500 }, { + /* Fujitsu Siemens Amilo D7820 */ .callback = dmi_matched, - .ident = "Fujitsu Siemens Amilo D7820", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */ DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"), @@ -971,8 +971,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_d88x0 }, { + /* Fujitsu Siemens Amilo D88x0 */ .callback = dmi_matched, - .ident = "Fujitsu Siemens Amilo D88x0", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"), From 6a47081c37b7dd7810ce19e156c1a3bf11987e9a Mon Sep 17 00:00:00 2001 From: Jari Vanhala Date: Fri, 4 Dec 2009 10:24:21 -0800 Subject: [PATCH 47/51] Input: fix memory leak in force feedback core Effects were allocated, but not freed anywhere. Signed-off-by: Jari Vanhala Signed-off-by: Dmitry Torokhov --- drivers/input/ff-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 572d0a712d2a..b2f07aa1604b 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -369,6 +369,7 @@ void input_ff_destroy(struct input_dev *dev) if (ff->destroy) ff->destroy(ff); kfree(ff->private); + kfree(ff->effects); kfree(ff); dev->ff = NULL; } From 36203c4f3d091b5f6c082663bd1f74273798043a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Dec 2009 10:22:23 -0800 Subject: [PATCH 48/51] Input: add generic support for sparse keymaps More and more devices choose to reimplement support for sparse keymaps first introduced by wistron driver. Move it into a library module so it can be easily used by interested parties. Reviewed-by: Anisse Astier Signed-off-by: Dmitry Torokhov --- Documentation/DocBook/device-drivers.tmpl | 4 + drivers/input/Kconfig | 28 ++- drivers/input/Makefile | 1 + drivers/input/input-polldev.c | 14 +- drivers/input/sparse-keymap.c | 250 ++++++++++++++++++++++ include/linux/input/sparse-keymap.h | 62 ++++++ 6 files changed, 347 insertions(+), 12 deletions(-) create mode 100644 drivers/input/sparse-keymap.c create mode 100644 include/linux/input/sparse-keymap.h diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index e994d1d9fbe6..f9a6e2c75f12 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -306,6 +306,10 @@ X!Idrivers/video/console/fonts.c Matrix keyboars/keypads !Iinclude/linux/input/matrix_keypad.h + Sparse keymap support +!Iinclude/linux/input/sparse-keymap.h +!Edrivers/input/sparse-keymap.c + diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index cd50c00ab20f..50af91ebd075 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -8,7 +8,7 @@ menu "Input device support" config INPUT tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED default y - ---help--- + help Say Y here if you have any input device (mouse, keyboard, tablet, joystick, steering wheel ...) connected to your system and want it to be available to applications. This includes standard PS/2 @@ -27,8 +27,7 @@ if INPUT config INPUT_FF_MEMLESS tristate "Support for memoryless force-feedback devices" - default n - ---help--- + help Say Y here if you have memoryless force-feedback input device such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual Power 2, or similar. You will also need to enable hardware-specific @@ -52,12 +51,25 @@ config INPUT_POLLDEV To compile this driver as a module, choose M here: the module will be called input-polldev. +config INPUT_SPARSEKMAP + tristate "Sparse keymap support library" + help + Say Y here if you are using a driver for an input + device that uses sparse keymap. This option is only + useful for out-of-tree drivers since in-tree drivers + select it automatically. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sparse-keymap. + comment "Userland interfaces" config INPUT_MOUSEDEV tristate "Mouse interface" if EMBEDDED default y - ---help--- + help Say Y here if you want your mouse to be accessible as char devices 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated IntelliMouse Explorer PS/2 mouse. That way, all user space @@ -73,7 +85,7 @@ config INPUT_MOUSEDEV_PSAUX bool "Provide legacy /dev/psaux device" default y depends on INPUT_MOUSEDEV - ---help--- + help Say Y here if you want your mouse also be accessible as char device 10:1 - /dev/psaux. The data available through /dev/psaux is exactly the same as the data from /dev/input/mice. @@ -103,7 +115,7 @@ config INPUT_MOUSEDEV_SCREEN_Y config INPUT_JOYDEV tristate "Joystick interface" - ---help--- + help Say Y here if you want your joystick or gamepad to be accessible as char device 13:0+ - /dev/input/jsX device. @@ -125,7 +137,7 @@ config INPUT_EVDEV config INPUT_EVBUG tristate "Event debugging" - ---help--- + help Say Y here if you have a problem with the input subsystem and want all events (keypresses, mouse movements), to be output to the system log. While this is useful for debugging, it's also @@ -140,7 +152,7 @@ config INPUT_EVBUG config INPUT_APMPOWER tristate "Input Power Event -> APM Bridge" if EMBEDDED depends on INPUT && APM_EMULATION - ---help--- + help Say Y here if you want suspend key events to trigger a user requested suspend through APM. This is useful on embedded systems where such behaviour is desired without userspace diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 4c9c745a7020..7ad212d31f99 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -9,6 +9,7 @@ input-core-objs := input.o input-compat.o ff-core.o obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o +obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 6a2eb399b988..aa6713b4a988 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -212,7 +212,7 @@ EXPORT_SYMBOL(input_allocate_polled_device); * @dev: device to free * * The function frees memory allocated for polling device and drops - * reference to the associated input device (if present). + * reference to the associated input device. */ void input_free_polled_device(struct input_polled_dev *dev) { @@ -258,6 +258,15 @@ int input_register_polled_device(struct input_polled_dev *dev) return error; } + /* + * Take extra reference to the underlying input device so + * that it survives call to input_unregister_polled_device() + * and is deleted only after input_free_polled_device() + * has been invoked. This is needed to ease task of freeing + * sparse keymaps. + */ + input_get_device(input); + return 0; } EXPORT_SYMBOL(input_register_polled_device); @@ -269,8 +278,6 @@ EXPORT_SYMBOL(input_register_polled_device); * The function unregisters previously registered polled input * device from input layer. Polling is stopped and device is * ready to be freed with call to input_free_polled_device(). - * Callers should not attempt to access dev->input pointer - * after calling this function. */ void input_unregister_polled_device(struct input_polled_dev *dev) { @@ -278,7 +285,6 @@ void input_unregister_polled_device(struct input_polled_dev *dev) &input_polldev_attribute_group); input_unregister_device(dev->input); - dev->input = NULL; } EXPORT_SYMBOL(input_unregister_polled_device); diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c new file mode 100644 index 000000000000..fbd3987af57f --- /dev/null +++ b/drivers/input/sparse-keymap.c @@ -0,0 +1,250 @@ +/* + * Generic support for sparse keymaps + * + * Copyright (c) 2009 Dmitry Torokhov + * + * Derived from wistron button driver: + * Copyright (C) 2005 Miloslav Trmac + * Copyright (C) 2005 Bernhard Rosenkraenzer + * Copyright (C) 2005 Dmitry Torokhov + * + * 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 +#include + +MODULE_AUTHOR("Dmitry Torokhov "); +MODULE_DESCRIPTION("Generic support for sparse keymaps"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); + +/** + * sparse_keymap_entry_from_scancode - perform sparse keymap lookup + * @dev: Input device using sparse keymap + * @code: Scan code + * + * This function is used to perform &struct key_entry lookup in an + * input device using sparse keymap. + */ +struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev, + unsigned int code) +{ + struct key_entry *key; + + for (key = dev->keycode; key->type != KE_END; key++) + if (code == key->code) + return key; + + return NULL; +} +EXPORT_SYMBOL(sparse_keymap_entry_from_scancode); + +/** + * sparse_keymap_entry_from_keycode - perform sparse keymap lookup + * @dev: Input device using sparse keymap + * @keycode: Key code + * + * This function is used to perform &struct key_entry lookup in an + * input device using sparse keymap. + */ +struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, + unsigned int keycode) +{ + struct key_entry *key; + + for (key = dev->keycode; key->type != KE_END; key++) + if (key->type == KE_KEY && keycode == key->keycode) + return key; + + return NULL; +} +EXPORT_SYMBOL(sparse_keymap_entry_from_keycode); + +static int sparse_keymap_getkeycode(struct input_dev *dev, + int scancode, int *keycode) +{ + const struct key_entry *key = + sparse_keymap_entry_from_scancode(dev, scancode); + + if (key && key->type == KE_KEY) { + *keycode = key->keycode; + return 0; + } + + return -EINVAL; +} + +static int sparse_keymap_setkeycode(struct input_dev *dev, + int scancode, int keycode) +{ + struct key_entry *key; + int old_keycode; + + if (keycode < 0 || keycode > KEY_MAX) + return -EINVAL; + + key = sparse_keymap_entry_from_scancode(dev, scancode); + if (key && key->type == KE_KEY) { + old_keycode = key->keycode; + key->keycode = keycode; + set_bit(keycode, dev->keybit); + if (!sparse_keymap_entry_from_keycode(dev, old_keycode)) + clear_bit(old_keycode, dev->keybit); + return 0; + } + + return -EINVAL; +} + +/** + * sparse_keymap_setup - set up sparse keymap for an input device + * @dev: Input device + * @keymap: Keymap in form of array of &key_entry structures ending + * with %KE_END type entry + * @setup: Function that can be used to adjust keymap entries + * depending on device's deeds, may be %NULL + * + * The function calculates size and allocates copy of the original + * keymap after which sets up input device event bits appropriately. + * Before destroying input device allocated keymap should be freed + * with a call to sparse_keymap_free(). + */ +int sparse_keymap_setup(struct input_dev *dev, + const struct key_entry *keymap, + int (*setup)(struct input_dev *, struct key_entry *)) +{ + size_t map_size = 1; /* to account for the last KE_END entry */ + const struct key_entry *e; + struct key_entry *map, *entry; + int i; + int error; + + for (e = keymap; e->type != KE_END; e++) + map_size++; + + map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL); + if (!map) + return -ENOMEM; + + memcpy(map, keymap, map_size * sizeof (struct key_entry)); + + for (i = 0; i < map_size; i++) { + entry = &map[i]; + + if (setup) { + error = setup(dev, entry); + if (error) + goto err_out; + } + + switch (entry->type) { + case KE_KEY: + __set_bit(EV_KEY, dev->evbit); + __set_bit(entry->keycode, dev->keybit); + break; + + case KE_SW: + __set_bit(EV_SW, dev->evbit); + __set_bit(entry->sw.code, dev->swbit); + break; + } + } + + dev->keycode = map; + dev->keycodemax = map_size; + dev->getkeycode = sparse_keymap_getkeycode; + dev->setkeycode = sparse_keymap_setkeycode; + + return 0; + + err_out: + kfree(keymap); + return error; + +} +EXPORT_SYMBOL(sparse_keymap_setup); + +/** + * sparse_keymap_free - free memory allocated for sparse keymap + * @dev: Input device using sparse keymap + * + * This function is used to free memory allocated by sparse keymap + * in an input device that was set up by sparse_keymap_setup(). + */ +void sparse_keymap_free(struct input_dev *dev) +{ + kfree(dev->keycode); + dev->keycode = NULL; + dev->keycodemax = 0; + dev->getkeycode = NULL; + dev->setkeycode = NULL; +} +EXPORT_SYMBOL(sparse_keymap_free); + +/** + * sparse_keymap_report_entry - report event corresponding to given key entry + * @dev: Input device for which event should be reported + * @ke: key entry describing event + * @value: Value that should be reported (ignored by %KE_SW entries) + * @autorelease: Signals whether release event should be emitted for %KE_KEY + * entries right after reporting press event, ignored by all other + * entries + * + * This function is used to report input event described by given + * &struct key_entry. + */ +void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke, + unsigned int value, bool autorelease) +{ + switch (ke->type) { + case KE_KEY: + input_report_key(dev, ke->keycode, value); + input_sync(dev); + if (value && autorelease) { + input_report_key(dev, ke->keycode, 0); + input_sync(dev); + } + break; + + case KE_SW: + value = ke->sw.value; + /* fall through */ + + case KE_VSW: + input_report_switch(dev, ke->sw.code, value); + break; + } +} +EXPORT_SYMBOL(sparse_keymap_report_entry); + +/** + * sparse_keymap_report_event - report event corresponding to given scancode + * @dev: Input device using sparse keymap + * @code: Scan code + * @value: Value that should be reported (ignored by %KE_SW entries) + * @autorelease: Signals whether release event should be emitted for %KE_KEY + * entries right after reporting press event, ignored by all other + * entries + * + * This function is used to perform lookup in an input device using sparse + * keymap and report corresponding event. Returns %true if lookup was + * successful and %false otherwise. + */ +bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code, + unsigned int value, bool autorelease) +{ + const struct key_entry *ke = + sparse_keymap_entry_from_scancode(dev, code); + + if (ke) { + sparse_keymap_report_entry(dev, ke, value, autorelease); + return true; + } + + return false; +} +EXPORT_SYMBOL(sparse_keymap_report_event); + diff --git a/include/linux/input/sparse-keymap.h b/include/linux/input/sparse-keymap.h new file mode 100644 index 000000000000..52db62064c6e --- /dev/null +++ b/include/linux/input/sparse-keymap.h @@ -0,0 +1,62 @@ +#ifndef _SPARSE_KEYMAP_H +#define _SPARSE_KEYMAP_H + +/* + * Copyright (c) 2009 Dmitry Torokhov + * + * 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. + */ + +#define KE_END 0 /* Indicates end of keymap */ +#define KE_KEY 1 /* Ordinary key/button */ +#define KE_SW 2 /* Switch (predetermined value) */ +#define KE_VSW 3 /* Switch (value supplied at runtime) */ +#define KE_IGNORE 4 /* Known entry that should be ignored */ +#define KE_LAST KE_IGNORE + +/** + * struct key_entry - keymap entry for use in sparse keymap + * @type: Type of the key entry (KE_KEY, KE_SW, KE_VSW, KE_END); + * drivers are allowed to extend the list with their own + * private definitions. + * @code: Device-specific data identifying the button/switch + * @keycode: KEY_* code assigned to a key/button + * @sw.code: SW_* code assigned to a switch + * @sw.value: Value that should be sent in an input even when KE_SW + * switch is toggled. KE_VSW switches ignore this field and + * expect driver to supply value for the event. + * + * This structure defines an entry in a sparse keymap used by some + * input devices for which traditional table-based approach is not + * suitable. + */ +struct key_entry { + int type; /* See KE_* above */ + u32 code; + union { + u16 keycode; /* For KE_KEY */ + struct { /* For KE_SW, KE_VSW */ + u8 code; + u8 value; /* For KE_SW, ignored by KE_VSW */ + } sw; + }; +}; + +struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev, + unsigned int code); +struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, + unsigned int code); +int sparse_keymap_setup(struct input_dev *dev, + const struct key_entry *keymap, + int (*setup)(struct input_dev *, struct key_entry *)); +void sparse_keymap_free(struct input_dev *dev); + +void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke, + unsigned int value, bool autorelease); + +bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code, + unsigned int value, bool autorelease); + +#endif /* _SPARSE_KEYMAP_H */ From e97af4cbbe500e6a3f4e189fe9324c5b99192dd6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Dec 2009 10:22:24 -0800 Subject: [PATCH 49/51] Input: wistron_btns - switch to using sparse keymap library The keymap manipulation code was split into a library module, so let's make us of it. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 1 + drivers/input/misc/wistron_btns.c | 180 ++++++++---------------------- 2 files changed, 46 insertions(+), 135 deletions(-) diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index a9bb2544b2de..d25ecbb87bfc 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -80,6 +80,7 @@ config INPUT_WISTRON_BTNS tristate "x86 Wistron laptop button interface" depends on X86 && !X86_64 select INPUT_POLLDEV + select INPUT_SPARSEKMAP select NEW_LEDS select LEDS_CLASS select CHECK_SIGNATURE diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index f9d2bc87b355..38da6ab04384 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -224,19 +225,8 @@ static void bios_set_state(u8 subsys, int enable) /* Hardware database */ -struct key_entry { - char type; /* See KE_* below */ - u8 code; - union { - u16 keycode; /* For KE_KEY */ - struct { /* For KE_SW */ - u8 code; - u8 value; - } sw; - }; -}; - -enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; +#define KE_WIFI (KE_LAST + 1) +#define KE_BLUETOOTH (KE_LAST + 2) #define FE_MAIL_LED 0x01 #define FE_WIFI_LED 0x02 @@ -1037,21 +1027,6 @@ static unsigned long jiffies_last_press; static bool wifi_enabled; static bool bluetooth_enabled; -static void report_key(struct input_dev *dev, unsigned int keycode) -{ - input_report_key(dev, keycode, 1); - input_sync(dev); - input_report_key(dev, keycode, 0); - input_sync(dev); -} - -static void report_switch(struct input_dev *dev, unsigned int code, int value) -{ - input_report_switch(dev, code, value); - input_sync(dev); -} - - /* led management */ static void wistron_mail_led_set(struct led_classdev *led_cdev, enum led_brightness value) @@ -1128,43 +1103,13 @@ static inline void wistron_led_resume(void) led_classdev_resume(&wistron_wifi_led); } -static struct key_entry *wistron_get_entry_by_scancode(int code) -{ - struct key_entry *key; - - for (key = keymap; key->type != KE_END; key++) - if (code == key->code) - return key; - - return NULL; -} - -static struct key_entry *wistron_get_entry_by_keycode(int keycode) -{ - struct key_entry *key; - - for (key = keymap; key->type != KE_END; key++) - if (key->type == KE_KEY && keycode == key->keycode) - return key; - - return NULL; -} - static void handle_key(u8 code) { - const struct key_entry *key = wistron_get_entry_by_scancode(code); + const struct key_entry *key = + sparse_keymap_entry_from_scancode(wistron_idev->input, code); if (key) { switch (key->type) { - case KE_KEY: - report_key(wistron_idev->input, key->keycode); - break; - - case KE_SW: - report_switch(wistron_idev->input, - key->sw.code, key->sw.value); - break; - case KE_WIFI: if (have_wifi) { wifi_enabled = !wifi_enabled; @@ -1180,7 +1125,9 @@ static void handle_key(u8 code) break; default: - BUG(); + sparse_keymap_report_entry(wistron_idev->input, + key, 1, true); + break; } jiffies_last_press = jiffies; } else @@ -1220,42 +1167,39 @@ static void wistron_poll(struct input_polled_dev *dev) dev->poll_interval = POLL_INTERVAL_DEFAULT; } -static int wistron_getkeycode(struct input_dev *dev, int scancode, int *keycode) +static int __devinit wistron_setup_keymap(struct input_dev *dev, + struct key_entry *entry) { - const struct key_entry *key = wistron_get_entry_by_scancode(scancode); + switch (entry->type) { - if (key && key->type == KE_KEY) { - *keycode = key->keycode; - return 0; + /* if wifi or bluetooth are not available, create normal keys */ + case KE_WIFI: + if (!have_wifi) { + entry->type = KE_KEY; + entry->keycode = KEY_WLAN; + } + break; + + case KE_BLUETOOTH: + if (!have_bluetooth) { + entry->type = KE_KEY; + entry->keycode = KEY_BLUETOOTH; + } + break; + + case KE_END: + if (entry->code & FE_UNTESTED) + printk(KERN_WARNING "Untested laptop multimedia keys, " + "please report success or failure to " + "eric.piel@tremplin-utc.net\n"); + break; } - return -EINVAL; -} - -static int wistron_setkeycode(struct input_dev *dev, int scancode, int keycode) -{ - struct key_entry *key; - int old_keycode; - - if (keycode < 0 || keycode > KEY_MAX) - return -EINVAL; - - key = wistron_get_entry_by_scancode(scancode); - if (key && key->type == KE_KEY) { - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!wistron_get_entry_by_keycode(old_keycode)) - clear_bit(old_keycode, dev->keybit); - return 0; - } - - return -EINVAL; + return 0; } static int __devinit setup_input_dev(void) { - struct key_entry *key; struct input_dev *input_dev; int error; @@ -1273,56 +1217,21 @@ static int __devinit setup_input_dev(void) input_dev->id.bustype = BUS_HOST; input_dev->dev.parent = &wistron_device->dev; - input_dev->getkeycode = wistron_getkeycode; - input_dev->setkeycode = wistron_setkeycode; - - for (key = keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, input_dev->evbit); - set_bit(key->keycode, input_dev->keybit); - break; - - case KE_SW: - set_bit(EV_SW, input_dev->evbit); - set_bit(key->sw.code, input_dev->swbit); - break; - - /* if wifi or bluetooth are not available, create normal keys */ - case KE_WIFI: - if (!have_wifi) { - key->type = KE_KEY; - key->keycode = KEY_WLAN; - key--; - } - break; - - case KE_BLUETOOTH: - if (!have_bluetooth) { - key->type = KE_KEY; - key->keycode = KEY_BLUETOOTH; - key--; - } - break; - - default: - break; - } - } - - /* reads information flags on KE_END */ - if (key->code & FE_UNTESTED) - printk(KERN_WARNING "Untested laptop multimedia keys, " - "please report success or failure to eric.piel" - "@tremplin-utc.net\n"); + error = sparse_keymap_setup(input_dev, keymap, wistron_setup_keymap); + if (error) + goto err_free_dev; error = input_register_polled_device(wistron_idev); - if (error) { - input_free_polled_device(wistron_idev); - return error; - } + if (error) + goto err_free_keymap; return 0; + + err_free_keymap: + sparse_keymap_free(input_dev); + err_free_dev: + input_free_polled_device(wistron_idev); + return error; } /* Driver core */ @@ -1371,6 +1280,7 @@ static int __devexit wistron_remove(struct platform_device *dev) { wistron_led_remove(); input_unregister_polled_device(wistron_idev); + sparse_keymap_free(wistron_idev->input); input_free_polled_device(wistron_idev); bios_detach(); From 6604072798da52547111cc06afacb8d9f2a907cf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Dec 2009 10:22:25 -0800 Subject: [PATCH 50/51] Input: dm355evm_kbd - switch to using sparse keymap library Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 1 + drivers/input/misc/dm355evm_keys.c | 150 +++++++++++------------------ 2 files changed, 57 insertions(+), 94 deletions(-) diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index d25ecbb87bfc..16ec5233441c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -282,6 +282,7 @@ config INPUT_RB532_BUTTON config INPUT_DM355EVM tristate "TI DaVinci DM355 EVM Keypad and IR Remote" depends on MFD_DM355EVM_MSP + select INPUT_SPARSEKMAP help Supports the pushbuttons and IR remote used with the DM355 EVM board. diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index f2b67dc81d80..766c06911f41 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -33,12 +34,8 @@ struct dm355evm_keys { int irq; }; -/* These initial keycodes can be remapped by dm355evm_setkeycode(). */ -static struct { - u16 event; - u16 keycode; -} dm355evm_keys[] = { - +/* These initial keycodes can be remapped */ +static const struct key_entry dm355evm_keys[] = { /* * Pushbuttons on the EVM board ... note that the labels for these * are SW10/SW11/etc on the PC board. The left/right orientation @@ -47,11 +44,11 @@ static struct { * is to the right. (That is, rotate the board counter-clockwise * by 90 degrees from the SW10/etc and "DM355 EVM" labels.) */ - { 0x00d8, KEY_OK, }, /* SW12 */ - { 0x00b8, KEY_UP, }, /* SW13 */ - { 0x00e8, KEY_DOWN, }, /* SW11 */ - { 0x0078, KEY_LEFT, }, /* SW14 */ - { 0x00f0, KEY_RIGHT, }, /* SW10 */ + { KE_KEY, 0x00d8, { KEY_OK } }, /* SW12 */ + { KE_KEY, 0x00b8, { KEY_UP } }, /* SW13 */ + { KE_KEY, 0x00e8, { KEY_DOWN } }, /* SW11 */ + { KE_KEY, 0x0078, { KEY_LEFT } }, /* SW14 */ + { KE_KEY, 0x00f0, { KEY_RIGHT } }, /* SW10 */ /* * IR buttons ... codes assigned to match the universal remote @@ -65,35 +62,35 @@ static struct { * RC5 codes are 14 bits, with two start bits (0x3 prefix) * and a toggle bit (masked out below). */ - { 0x300c, KEY_POWER, }, /* NOTE: docs omit this */ - { 0x3000, KEY_NUMERIC_0, }, - { 0x3001, KEY_NUMERIC_1, }, - { 0x3002, KEY_NUMERIC_2, }, - { 0x3003, KEY_NUMERIC_3, }, - { 0x3004, KEY_NUMERIC_4, }, - { 0x3005, KEY_NUMERIC_5, }, - { 0x3006, KEY_NUMERIC_6, }, - { 0x3007, KEY_NUMERIC_7, }, - { 0x3008, KEY_NUMERIC_8, }, - { 0x3009, KEY_NUMERIC_9, }, - { 0x3022, KEY_ENTER, }, - { 0x30ec, KEY_MODE, }, /* "tv/vcr/..." */ - { 0x300f, KEY_SELECT, }, /* "info" */ - { 0x3020, KEY_CHANNELUP, }, /* "up" */ - { 0x302e, KEY_MENU, }, /* "in/out" */ - { 0x3011, KEY_VOLUMEDOWN, }, /* "left" */ - { 0x300d, KEY_MUTE, }, /* "ok" */ - { 0x3010, KEY_VOLUMEUP, }, /* "right" */ - { 0x301e, KEY_SUBTITLE, }, /* "cc" */ - { 0x3021, KEY_CHANNELDOWN, }, /* "down" */ - { 0x3022, KEY_PREVIOUS, }, - { 0x3026, KEY_SLEEP, }, - { 0x3172, KEY_REWIND, }, /* NOTE: docs wrongly say 0x30ca */ - { 0x3175, KEY_PLAY, }, - { 0x3174, KEY_FASTFORWARD, }, - { 0x3177, KEY_RECORD, }, - { 0x3176, KEY_STOP, }, - { 0x3169, KEY_PAUSE, }, + { KE_KEY, 0x300c, { KEY_POWER } }, /* NOTE: docs omit this */ + { KE_KEY, 0x3000, { KEY_NUMERIC_0 } }, + { KE_KEY, 0x3001, { KEY_NUMERIC_1 } }, + { KE_KEY, 0x3002, { KEY_NUMERIC_2 } }, + { KE_KEY, 0x3003, { KEY_NUMERIC_3 } }, + { KE_KEY, 0x3004, { KEY_NUMERIC_4 } }, + { KE_KEY, 0x3005, { KEY_NUMERIC_5 } }, + { KE_KEY, 0x3006, { KEY_NUMERIC_6 } }, + { KE_KEY, 0x3007, { KEY_NUMERIC_7 } }, + { KE_KEY, 0x3008, { KEY_NUMERIC_8 } }, + { KE_KEY, 0x3009, { KEY_NUMERIC_9 } }, + { KE_KEY, 0x3022, { KEY_ENTER } }, + { KE_KEY, 0x30ec, { KEY_MODE } }, /* "tv/vcr/..." */ + { KE_KEY, 0x300f, { KEY_SELECT } }, /* "info" */ + { KE_KEY, 0x3020, { KEY_CHANNELUP } }, /* "up" */ + { KE_KEY, 0x302e, { KEY_MENU } }, /* "in/out" */ + { KE_KEY, 0x3011, { KEY_VOLUMEDOWN } }, /* "left" */ + { KE_KEY, 0x300d, { KEY_MUTE } }, /* "ok" */ + { KE_KEY, 0x3010, { KEY_VOLUMEUP } }, /* "right" */ + { KE_KEY, 0x301e, { KEY_SUBTITLE } }, /* "cc" */ + { KE_KEY, 0x3021, { KEY_CHANNELDOWN } },/* "down" */ + { KE_KEY, 0x3022, { KEY_PREVIOUS } }, + { KE_KEY, 0x3026, { KEY_SLEEP } }, + { KE_KEY, 0x3172, { KEY_REWIND } }, /* NOTE: docs wrongly say 0x30ca */ + { KE_KEY, 0x3175, { KEY_PLAY } }, + { KE_KEY, 0x3174, { KEY_FASTFORWARD } }, + { KE_KEY, 0x3177, { KEY_RECORD } }, + { KE_KEY, 0x3176, { KEY_STOP } }, + { KE_KEY, 0x3169, { KEY_PAUSE } }, }; /* @@ -105,19 +102,18 @@ static struct { */ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) { - struct dm355evm_keys *keys = _keys; - int status; + static u16 last_event; + struct dm355evm_keys *keys = _keys; + const struct key_entry *ke; + unsigned int keycode; + int status; + u16 event; /* For simplicity we ignore INPUT_COUNT and just read * events until we get the "queue empty" indicator. * Reading INPUT_LOW decrements the count. */ for (;;) { - static u16 last_event; - u16 event; - int keycode; - int i; - status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH); if (status < 0) { dev_dbg(keys->dev, "input high err %d\n", @@ -156,14 +152,9 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) /* ignore the RC5 toggle bit */ event &= ~0x0800; - /* find the key, or leave it as unknown */ - keycode = KEY_UNKNOWN; - for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { - if (dm355evm_keys[i].event != event) - continue; - keycode = dm355evm_keys[i].keycode; - break; - } + /* find the key, or report it as unknown */ + ke = sparse_keymap_entry_from_scancode(keys->input, event); + keycode = ke ? ke->keycode : KEY_UNKNOWN; dev_dbg(keys->dev, "input event 0x%04x--> keycode %d\n", event, keycode); @@ -174,38 +165,10 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) input_report_key(keys->input, keycode, 0); input_sync(keys->input); } + return IRQ_HANDLED; } -static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode) -{ - u16 old_keycode; - unsigned i; - - if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) - return -EINVAL; - - old_keycode = dm355evm_keys[index].keycode; - dm355evm_keys[index].keycode = keycode; - set_bit(keycode, dev->keybit); - - for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { - if (dm355evm_keys[index].keycode == old_keycode) - goto done; - } - clear_bit(old_keycode, dev->keybit); -done: - return 0; -} - -static int dm355evm_getkeycode(struct input_dev *dev, int index, int *keycode) -{ - if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) - return -EINVAL; - - return dm355evm_keys[index].keycode; -} - /*----------------------------------------------------------------------*/ static int __devinit dm355evm_keys_probe(struct platform_device *pdev) @@ -213,7 +176,6 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev) struct dm355evm_keys *keys; struct input_dev *input; int status; - int i; /* allocate instance struct and input dev */ keys = kzalloc(sizeof *keys, GFP_KERNEL); @@ -242,31 +204,30 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev) input->id.product = 0x0355; input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV); - input->evbit[0] = BIT(EV_KEY); - for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) - __set_bit(dm355evm_keys[i].keycode, input->keybit); - - input->setkeycode = dm355evm_setkeycode; - input->getkeycode = dm355evm_getkeycode; + status = sparse_keymap_setup(input, dm355evm_keys, NULL); + if (status) + goto fail1; /* REVISIT: flush the event queue? */ status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq, IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys); if (status < 0) - goto fail1; + goto fail2; /* register */ status = input_register_device(input); if (status < 0) - goto fail2; + goto fail3; platform_set_drvdata(pdev, keys); return 0; -fail2: +fail3: free_irq(keys->irq, keys); +fail2: + sparse_keymap_free(input); fail1: input_free_device(input); kfree(keys); @@ -280,6 +241,7 @@ static int __devexit dm355evm_keys_remove(struct platform_device *pdev) struct dm355evm_keys *keys = platform_get_drvdata(pdev); free_irq(keys->irq, keys); + sparse_keymap_free(keys->input); input_unregister_device(keys->input); kfree(keys); From 1f26978afd123deb22dd3c7dc75771a02f6e03f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 6 Dec 2009 11:42:09 -0800 Subject: [PATCH 51/51] Input: appletouch - give up maintainership I no longer have a machine with this, and as such am not really able to help out with this driver any more. Remove the entire appletouch section and let the driver fall under the general input subsystem. Signed-off-by: Johannes Berg Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 7 ------- 1 file changed, 7 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 4f96ac81089c..85e1734f9a50 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -486,13 +486,6 @@ S: Maintained F: drivers/net/appletalk/ F: net/appletalk/ -APPLETOUCH TOUCHPAD DRIVER -M: Johannes Berg -L: linux-input@vger.kernel.org -S: Maintained -F: Documentation/input/appletouch.txt -F: drivers/input/mouse/appletouch.c - ARC FRAMEBUFFER DRIVER M: Jaya Kumar S: Maintained