Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Linus Torvalds [Thu, 10 Dec 2009 03:52:01 +0000 (19:52 -0800)]
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (51 commits)
  Input: appletouch - give up maintainership
  Input: dm355evm_kbd - switch to using sparse keymap library
  Input: wistron_btns - switch to using sparse keymap library
  Input: add generic support for sparse keymaps
  Input: fix memory leak in force feedback core
  Input: wistron - remove identification strings from DMI table
  Input: psmouse - remove identification strings from DMI tables
  Input: atkbd - remove identification strings from DMI table
  Input: i8042 - remove identification strings from DMI tables
  DMI: allow omitting ident strings in DMI tables
  Input: psmouse - do not carry DMI data around
  Input: matrix-keypad - switch to using dev_pm_ops
  Input: keyboard - fix lack of locking when traversing handler->h_list
  Input: gpio_keys - scan gpio state at probe and resume time
  Input: keyboard - add locking around event handling
  Input: usbtouchscreen - add support for ET&T TC5UH touchscreen controller
  Input: xpad - add two new Xbox 360 devices
  Input: polled device - do not start polling if interval is zero
  Input: polled device - schedule first poll immediately
  Input: add S3C24XX touchscreen driver
  ...

63 files changed:
Documentation/DocBook/device-drivers.tmpl
MAINTAINERS
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/include/mach/board.h
arch/arm/mach-davinci/include/mach/keyscan.h [new file with mode: 0644]
drivers/char/keyboard.c
drivers/firmware/dmi_scan.c
drivers/hid/usbhid/usbkbd.c
drivers/input/Kconfig
drivers/input/Makefile
drivers/input/ff-core.c
drivers/input/input-polldev.c
drivers/input/input.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/davinci_keyscan.c [new file with mode: 0644]
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/lkkbd.c
drivers/input/keyboard/matrix_keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/ati_remote.c
drivers/input/misc/dm355evm_keys.c
drivers/input/misc/powermate.c
drivers/input/misc/wistron_btns.c
drivers/input/mouse/alps.c
drivers/input/mouse/elantech.c
drivers/input/mouse/hgpk.c
drivers/input/mouse/lifebook.c
drivers/input/mouse/lifebook.h
drivers/input/mouse/logips2pp.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/sentelic.c
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.h
drivers/input/mouse/synaptics_i2c.c
drivers/input/mouse/touchkit_ps2.c
drivers/input/mouse/trackpoint.c
drivers/input/mouse/vsxxxaa.c
drivers/input/serio/Kconfig
drivers/input/serio/Makefile
drivers/input/serio/altera_ps2.c [new file with mode: 0644]
drivers/input/serio/i8042-x86ia64io.h
drivers/input/sparse-keymap.c [new file with mode: 0644]
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/atmel_tsadcc.c
drivers/input/touchscreen/dynapro.c [new file with mode: 0644]
drivers/input/touchscreen/s3c2410_ts.c [new file with mode: 0644]
drivers/input/touchscreen/ucb1400_ts.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/mfd/ucb1400_core.c
include/linux/input-polldev.h
include/linux/input.h
include/linux/input/matrix_keypad.h
include/linux/input/sparse-keymap.h [new file with mode: 0644]
include/linux/serio.h
include/linux/ucb1400.h

index 94a20fe..f9a6e2c 100644 (file)
@@ -293,10 +293,23 @@ X!Idrivers/video/console/fonts.c
 
   <chapter id="input_subsystem">
      <title>Input Subsystem</title>
+     <sect1><title>Input core</title>
 !Iinclude/linux/input.h
 !Edrivers/input/input.c
 !Edrivers/input/ff-core.c
 !Edrivers/input/ff-memless.c
+     </sect1>
+     <sect1><title>Polled input devices</title>
+!Iinclude/linux/input-polldev.h
+!Edrivers/input/input-polldev.c
+     </sect1>
+     <sect1><title>Matrix keyboars/keypads</title>
+!Iinclude/linux/input/matrix_keypad.h
+     </sect1>
+     <sect1><title>Sparse keymap support</title>
+!Iinclude/linux/input/sparse-keymap.h
+!Edrivers/input/sparse-keymap.c
+     </sect1>
   </chapter>
 
   <chapter id="spi">
index f7b0ced..107a5a5 100644 (file)
@@ -486,13 +486,6 @@ S: Maintained
 F:     drivers/net/appletalk/
 F:     net/appletalk/
 
-APPLETOUCH TOUCHPAD DRIVER
-M:     Johannes Berg <johannes@sipsolutions.net>
-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 <jayalk@intworks.biz>
 S:     Maintained
index a57af3e..809114d 100644 (file)
@@ -866,6 +866,57 @@ static void __init at91_add_device_rtc(void) {}
 
 
 /* --------------------------------------------------------------------
+ *  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
  * -------------------------------------------------------------------- */
 
index d345f54..53aaa94 100644 (file)
@@ -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
 
 
index 1cf4d86..98f9f4b 100644 (file)
@@ -229,6 +229,16 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data;
 
 
 /*
+ * Touchscreen
+ */
+static struct at91_tsadcc_data ek_tsadcc_data = {
+       .adc_clock              = 300000,
+       .pendet_debounce        = 0x0d,
+       .ts_sample_hold_time    = 0x0a,
+};
+
+
+/*
  * GPIO Buttons
  */
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
@@ -379,6 +389,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 */
index bd28e98..7ac20f3 100644 (file)
@@ -243,6 +243,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
  */
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
@@ -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 */
index 2295d80..bb6f6a7 100644 (file)
@@ -187,7 +187,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 {
diff --git a/arch/arm/mach-davinci/include/mach/keyscan.h b/arch/arm/mach-davinci/include/mach/keyscan.h
new file mode 100644 (file)
index 0000000..b4e21a2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DAVINCI_KEYSCAN_H
+#define DAVINCI_KEYSCAN_H
+
+#include <linux/io.h>
+
+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
+
index 950837c..5619007 100644 (file)
@@ -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
  */
@@ -132,6 +130,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;
@@ -190,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 void kd_nosound(unsigned long ignored)
+
+static int kd_sound_helper(struct input_handle *handle, void *data)
 {
-       struct input_handle *handle;
+       unsigned int *hz = data;
+       struct input_dev *dev = handle->dev;
 
-       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);
-               }
+       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)
+{
+       static unsigned int zero;
+
+       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);
 
@@ -269,27 +275,34 @@ EXPORT_SYMBOL(kd_mksound);
  * Setting the keyboard rate.
  */
 
-int kbd_rate(struct kbd_repeat *rep)
+static int kbd_rate_helper(struct input_handle *handle, void *data)
 {
-       struct list_head *node;
-       unsigned int d = 0;
-       unsigned int p = 0;
-
-       list_for_each(node, &kbd_handler.h_list) {
-               struct input_handle *handle = to_handle_h(node);
-               struct input_dev *dev = handle->dev;
-
-               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];
-               }
+       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];
        }
-       rep->delay  = d;
-       rep->period = p;
+
+       return 0;
+}
+
+int kbd_rate(struct kbd_repeat *rep)
+{
+       struct kbd_repeat data[2] = { *rep };
+
+       input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
+       *rep = data[1]; /* Copy currently used settings */
+
        return 0;
 }
 
@@ -997,36 +1010,36 @@ static inline unsigned char getleds(void)
        return leds;
 }
 
+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 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, ...) => ...
+ * 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);
@@ -1136,7 +1149,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 +1170,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;
@@ -1296,10 +1309,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();
@@ -1363,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);
 }
 
index 938100f..3a2ccb0 100644 (file)
@@ -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;
@@ -440,6 +440,15 @@ static bool dmi_matches(const struct dmi_system_id *dmi)
 }
 
 /**
+ *     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
  *             All non-null elements of the list must match
@@ -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;
 
index b342926..f843443 100644 (file)
@@ -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;
index cd50c00..50af91e 100644 (file)
@@ -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
index 4c9c745..7ad212d 100644 (file)
@@ -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
index 38df81f..b2f07aa 100644 (file)
@@ -353,7 +353,7 @@ int input_ff_create(struct input_dev *dev, int max_effects)
 EXPORT_SYMBOL_GPL(input_ff_create);
 
 /**
- * input_ff_free() - frees force feedback portion of input device
+ * input_ff_destroy() - frees force feedback portion of input device
  * @dev: input device supporting force feedback
  *
  * This function is only needed in error path as input core will
@@ -369,6 +369,7 @@ void input_ff_destroy(struct input_dev *dev)
                if (ff->destroy)
                        ff->destroy(ff);
                kfree(ff->private);
+               kfree(ff->effects);
                kfree(ff);
                dev->ff = NULL;
        }
index 0d3ce7a..aa6713b 100644 (file)
@@ -56,14 +56,10 @@ static void input_polldev_stop_workqueue(void)
        mutex_unlock(&polldev_mutex);
 }
 
-static void input_polled_device_work(struct work_struct *work)
+static void input_polldev_queue_work(struct input_polled_dev *dev)
 {
-       struct input_polled_dev *dev =
-               container_of(work, struct input_polled_dev, work.work);
        unsigned long delay;
 
-       dev->poll(dev);
-
        delay = msecs_to_jiffies(dev->poll_interval);
        if (delay >= HZ)
                delay = round_jiffies_relative(delay);
@@ -71,6 +67,15 @@ static void input_polled_device_work(struct work_struct *work)
        queue_delayed_work(polldev_wq, &dev->work, delay);
 }
 
+static void input_polled_device_work(struct work_struct *work)
+{
+       struct input_polled_dev *dev =
+               container_of(work, struct input_polled_dev, work.work);
+
+       dev->poll(dev);
+       input_polldev_queue_work(dev);
+}
+
 static int input_open_polled_device(struct input_dev *input)
 {
        struct input_polled_dev *dev = input_get_drvdata(input);
@@ -80,11 +85,12 @@ static int input_open_polled_device(struct input_dev *input)
        if (error)
                return error;
 
-       if (dev->flush)
-               dev->flush(dev);
+       if (dev->open)
+               dev->open(dev);
 
-       queue_delayed_work(polldev_wq, &dev->work,
-                          msecs_to_jiffies(dev->poll_interval));
+       /* Only start polling if polling is enabled */
+       if (dev->poll_interval > 0)
+               queue_delayed_work(polldev_wq, &dev->work, 0);
 
        return 0;
 }
@@ -95,8 +101,88 @@ static void input_close_polled_device(struct input_dev *input)
 
        cancel_delayed_work_sync(&dev->work);
        input_polldev_stop_workqueue();
+
+       if (dev->close)
+               dev->close(dev);
 }
 
+/* SYSFS interface */
+
+static ssize_t input_polldev_get_poll(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct input_polled_dev *polldev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", polldev->poll_interval);
+}
+
+static ssize_t input_polldev_set_poll(struct device *dev,
+                               struct device_attribute *attr, const char *buf,
+                               size_t count)
+{
+       struct input_polled_dev *polldev = dev_get_drvdata(dev);
+       struct input_dev *input = polldev->input;
+       unsigned long interval;
+
+       if (strict_strtoul(buf, 0, &interval))
+               return -EINVAL;
+
+       if (interval < polldev->poll_interval_min)
+               return -EINVAL;
+
+       if (interval > polldev->poll_interval_max)
+               return -EINVAL;
+
+       mutex_lock(&input->mutex);
+
+       polldev->poll_interval = interval;
+
+       if (input->users) {
+               cancel_delayed_work_sync(&polldev->work);
+               if (polldev->poll_interval > 0)
+                       input_polldev_queue_work(polldev);
+       }
+
+       mutex_unlock(&input->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll,
+                                           input_polldev_set_poll);
+
+
+static ssize_t input_polldev_get_max(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct input_polled_dev *polldev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", polldev->poll_interval_max);
+}
+
+static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL);
+
+static ssize_t input_polldev_get_min(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct input_polled_dev *polldev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", polldev->poll_interval_min);
+}
+
+static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL);
+
+static struct attribute *sysfs_attrs[] = {
+       &dev_attr_poll.attr,
+       &dev_attr_max.attr,
+       &dev_attr_min.attr,
+       NULL
+};
+
+static struct attribute_group input_polldev_attribute_group = {
+       .attrs = sysfs_attrs
+};
+
 /**
  * input_allocate_polled_device - allocated memory polled device
  *
@@ -126,7 +212,7 @@ EXPORT_SYMBOL(input_allocate_polled_device);
  * @dev: device to free
  *
  * The function frees memory allocated for polling device and drops
- * reference to the associated input device (if present).
+ * reference to the associated input device.
  */
 void input_free_polled_device(struct input_polled_dev *dev)
 {
@@ -150,15 +236,38 @@ EXPORT_SYMBOL(input_free_polled_device);
 int input_register_polled_device(struct input_polled_dev *dev)
 {
        struct input_dev *input = dev->input;
+       int error;
 
        input_set_drvdata(input, dev);
        INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
        if (!dev->poll_interval)
                dev->poll_interval = 500;
+       if (!dev->poll_interval_max)
+               dev->poll_interval_max = dev->poll_interval;
        input->open = input_open_polled_device;
        input->close = input_close_polled_device;
 
-       return input_register_device(input);
+       error = input_register_device(input);
+       if (error)
+               return error;
+
+       error = sysfs_create_group(&input->dev.kobj,
+                                  &input_polldev_attribute_group);
+       if (error) {
+               input_unregister_device(input);
+               return error;
+       }
+
+       /*
+        * Take extra reference to the underlying input device so
+        * that it survives call to input_unregister_polled_device()
+        * and is deleted only after input_free_polled_device()
+        * has been invoked. This is needed to ease task of freeing
+        * sparse keymaps.
+        */
+       input_get_device(input);
+
+       return 0;
 }
 EXPORT_SYMBOL(input_register_polled_device);
 
@@ -169,13 +278,13 @@ EXPORT_SYMBOL(input_register_polled_device);
  * The function unregisters previously registered polled input
  * device from input layer. Polling is stopped and device is
  * ready to be freed with call to input_free_polled_device().
- * Callers should not attempt to access dev->input pointer
- * after calling this function.
  */
 void input_unregister_polled_device(struct input_polled_dev *dev)
 {
+       sysfs_remove_group(&dev->input->dev.kobj,
+                          &input_polldev_attribute_group);
+
        input_unregister_device(dev->input);
-       dev->input = NULL;
 }
 EXPORT_SYMBOL(input_unregister_polled_device);
 
index 2266ecb..5c16001 100644 (file)
@@ -1658,6 +1658,38 @@ void input_unregister_handler(struct input_handler *handler)
 EXPORT_SYMBOL(input_unregister_handler);
 
 /**
+ * input_handler_for_each_handle - handle iterator
+ * @handler: input handler to iterate
+ * @data: data for the callback
+ * @fn: function to be called for each handle
+ *
+ * Iterate over @bus's list of devices, and call @fn for each, passing
+ * it @data and stop when @fn returns a non-zero value. The function is
+ * using RCU to traverse the list and therefore may be usind in atonic
+ * contexts. The @fn callback is invoked from RCU critical section and
+ * thus must not sleep.
+ */
+int input_handler_for_each_handle(struct input_handler *handler, void *data,
+                                 int (*fn)(struct input_handle *, void *))
+{
+       struct input_handle *handle;
+       int retval = 0;
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(handle, &handler->h_list, h_node) {
+               retval = fn(handle, data);
+               if (retval)
+                       break;
+       }
+
+       rcu_read_unlock();
+
+       return retval;
+}
+EXPORT_SYMBOL(input_handler_for_each_handle);
+
+/**
  * input_register_handle - register a new input handle
  * @handle: handle to register
  *
@@ -1690,7 +1722,7 @@ int input_register_handle(struct input_handle *handle)
         * we can't be racing with input_unregister_handle()
         * and so separate lock is not needed here.
         */
-       list_add_tail(&handle->h_node, &handler->h_list);
+       list_add_tail_rcu(&handle->h_node, &handler->h_list);
 
        if (handler->start)
                handler->start(handle);
@@ -1713,7 +1745,7 @@ void input_unregister_handle(struct input_handle *handle)
 {
        struct input_dev *dev = handle->dev;
 
-       list_del_init(&handle->h_node);
+       list_del_rcu(&handle->h_node);
 
        /*
         * Take dev->mutex to prevent race with input_release_device().
@@ -1721,6 +1753,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);
index 79e3edc..482cb12 100644 (file)
@@ -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 */
        { }
 };
 
index ee98b1b..203b88a 100644 (file)
@@ -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)
index babad5e..68c0172 100644 (file)
@@ -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
index 28e6110..a357357 100644 (file)
@@ -1567,9 +1567,8 @@ static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
        return 0;
 }
 
-static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
+static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
        {
-               .ident = "Dell Laptop",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                        DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
@@ -1578,7 +1577,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_dell_laptop_forced_release_keys,
        },
        {
-               .ident = "Dell Laptop",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
                        DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
@@ -1587,7 +1585,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_dell_laptop_forced_release_keys,
        },
        {
-               .ident = "HP 2133",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"),
@@ -1596,7 +1593,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_hp_forced_release_keys,
        },
        {
-               .ident = "HP Pavilion ZV6100",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
@@ -1605,7 +1601,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_volume_forced_release_keys,
        },
        {
-               .ident = "HP Presario R4000",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
@@ -1614,7 +1609,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_volume_forced_release_keys,
        },
        {
-               .ident = "HP Presario R4100",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
@@ -1623,7 +1617,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_volume_forced_release_keys,
        },
        {
-               .ident = "HP Presario R4200",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
@@ -1632,7 +1625,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_volume_forced_release_keys,
        },
        {
-               .ident = "Inventec Symphony",
+               /* Inventec Symphony */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
@@ -1641,7 +1634,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_volume_forced_release_keys,
        },
        {
-               .ident = "Samsung NC10",
+               /* Samsung NC10 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
@@ -1650,7 +1643,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_samsung_forced_release_keys,
        },
        {
-               .ident = "Samsung NC20",
+               /* Samsung NC20 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "NC20"),
@@ -1659,7 +1652,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_samsung_forced_release_keys,
        },
        {
-               .ident = "Samsung SQ45S70S",
+               /* Samsung SQ45S70S */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
@@ -1668,7 +1661,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_samsung_forced_release_keys,
        },
        {
-               .ident = "Fujitsu Amilo PA 1510",
+               /* Fujitsu Amilo PA 1510 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
@@ -1677,7 +1670,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_volume_forced_release_keys,
        },
        {
-               .ident = "Fujitsu Amilo Pi 3525",
+               /* Fujitsu Amilo Pi 3525 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"),
@@ -1686,7 +1679,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_amilo_pi3525_forced_release_keys,
        },
        {
-               .ident = "Fujitsu Amilo Xi 3650",
+               /* Fujitsu Amilo Xi 3650 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"),
@@ -1695,7 +1688,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkbd_amilo_xi3650_forced_release_keys,
        },
        {
-               .ident = "Soltech Corporation TA12",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TA12"),
@@ -1704,7 +1696,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .driver_data = atkdb_soltech_ta12_forced_release_keys,
        },
        {
-               .ident = "OQO Model 01+",
+               /* OQO Model 01+ */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c
new file mode 100644 (file)
index 0000000..6e52d85
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * DaVinci Key Scan Driver for TI platforms
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
+ *
+ * Intial Code: Sandeep Paulraj <s-paulraj@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/keyscan.h>
+
+/* Key scan registers */
+#define DAVINCI_KEYSCAN_KEYCTRL                0x0000
+#define DAVINCI_KEYSCAN_INTENA         0x0004
+#define DAVINCI_KEYSCAN_INTFLAG                0x0008
+#define DAVINCI_KEYSCAN_INTCLR         0x000c
+#define DAVINCI_KEYSCAN_STRBWIDTH      0x0010
+#define DAVINCI_KEYSCAN_INTERVAL       0x0014
+#define DAVINCI_KEYSCAN_CONTTIME       0x0018
+#define DAVINCI_KEYSCAN_CURRENTST      0x001c
+#define DAVINCI_KEYSCAN_PREVSTATE      0x0020
+#define DAVINCI_KEYSCAN_EMUCTRL                0x0024
+#define DAVINCI_KEYSCAN_IODFTCTRL      0x002c
+
+/* Key Control Register (KEYCTRL) */
+#define DAVINCI_KEYSCAN_KEYEN          0x00000001
+#define DAVINCI_KEYSCAN_PREVMODE       0x00000002
+#define DAVINCI_KEYSCAN_CHATOFF                0x00000004
+#define DAVINCI_KEYSCAN_AUTODET                0x00000008
+#define DAVINCI_KEYSCAN_SCANMODE       0x00000010
+#define DAVINCI_KEYSCAN_OUTTYPE                0x00000020
+
+/* Masks for the interrupts */
+#define DAVINCI_KEYSCAN_INT_CONT       0x00000008
+#define DAVINCI_KEYSCAN_INT_OFF                0x00000004
+#define DAVINCI_KEYSCAN_INT_ON         0x00000002
+#define DAVINCI_KEYSCAN_INT_CHANGE     0x00000001
+#define DAVINCI_KEYSCAN_INT_ALL                0x0000000f
+
+struct davinci_ks {
+       struct input_dev                *input;
+       struct davinci_ks_platform_data *pdata;
+       int                             irq;
+       void __iomem                    *base;
+       resource_size_t                 pbase;
+       size_t                          base_size;
+       unsigned short                  keymap[];
+};
+
+/* Initializing the kp Module */
+static int __init davinci_ks_initialize(struct davinci_ks *davinci_ks)
+{
+       struct device *dev = &davinci_ks->input->dev;
+       struct davinci_ks_platform_data *pdata = davinci_ks->pdata;
+       u32 matrix_ctrl;
+
+       /* Enable all interrupts */
+       __raw_writel(DAVINCI_KEYSCAN_INT_ALL,
+                    davinci_ks->base + DAVINCI_KEYSCAN_INTENA);
+
+       /* Clear interrupts if any */
+       __raw_writel(DAVINCI_KEYSCAN_INT_ALL,
+                    davinci_ks->base + DAVINCI_KEYSCAN_INTCLR);
+
+       /* Setup the scan period = strobe + interval */
+       __raw_writel(pdata->strobe,
+                    davinci_ks->base + DAVINCI_KEYSCAN_STRBWIDTH);
+       __raw_writel(pdata->interval,
+                    davinci_ks->base + DAVINCI_KEYSCAN_INTERVAL);
+       __raw_writel(0x01,
+                    davinci_ks->base + DAVINCI_KEYSCAN_CONTTIME);
+
+       /* Define matrix type */
+       switch (pdata->matrix_type) {
+       case DAVINCI_KEYSCAN_MATRIX_4X4:
+               matrix_ctrl = 0;
+               break;
+       case DAVINCI_KEYSCAN_MATRIX_5X3:
+               matrix_ctrl = (1 << 6);
+               break;
+       default:
+               dev_err(dev->parent, "wrong matrix type\n");
+               return -EINVAL;
+       }
+
+       /* Enable key scan module and set matrix type */
+       __raw_writel(DAVINCI_KEYSCAN_AUTODET | DAVINCI_KEYSCAN_KEYEN |
+                    matrix_ctrl, davinci_ks->base + DAVINCI_KEYSCAN_KEYCTRL);
+
+       return 0;
+}
+
+static irqreturn_t davinci_ks_interrupt(int irq, void *dev_id)
+{
+       struct davinci_ks *davinci_ks = dev_id;
+       struct device *dev = &davinci_ks->input->dev;
+       unsigned short *keymap = davinci_ks->keymap;
+       int keymapsize = davinci_ks->pdata->keymapsize;
+       u32 prev_status, new_status, changed;
+       bool release;
+       int keycode = KEY_UNKNOWN;
+       int i;
+
+       /* Disable interrupt */
+       __raw_writel(0x0, davinci_ks->base + DAVINCI_KEYSCAN_INTENA);
+
+       /* Reading previous and new status of the key scan */
+       prev_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_PREVSTATE);
+       new_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_CURRENTST);
+
+       changed = prev_status ^ new_status;
+
+       if (changed) {
+               /*
+                * It goes through all bits in 'changed' to ensure
+                * that no key changes are being missed
+                */
+               for (i = 0 ; i < keymapsize; i++) {
+                       if ((changed>>i) & 0x1) {
+                               keycode = keymap[i];
+                               release = (new_status >> i) & 0x1;
+                               dev_dbg(dev->parent, "key %d %s\n", keycode,
+                                       release ? "released" : "pressed");
+                               input_report_key(davinci_ks->input, keycode,
+                                                !release);
+                               input_sync(davinci_ks->input);
+                       }
+               }
+               /* Clearing interrupt */
+               __raw_writel(DAVINCI_KEYSCAN_INT_ALL,
+                            davinci_ks->base + DAVINCI_KEYSCAN_INTCLR);
+       }
+
+       /* Enable interrupts */
+       __raw_writel(0x1, davinci_ks->base + DAVINCI_KEYSCAN_INTENA);
+
+       return IRQ_HANDLED;
+}
+
+static int __init davinci_ks_probe(struct platform_device *pdev)
+{
+       struct davinci_ks *davinci_ks;
+       struct input_dev *key_dev;
+       struct resource *res, *mem;
+       struct device *dev = &pdev->dev;
+       struct davinci_ks_platform_data *pdata = pdev->dev.platform_data;
+       int error, i;
+
+       if (!pdata->keymap) {
+               dev_dbg(dev, "no keymap from pdata\n");
+               return -EINVAL;
+       }
+
+       davinci_ks = kzalloc(sizeof(struct davinci_ks) +
+               sizeof(unsigned short) * pdata->keymapsize, GFP_KERNEL);
+       if (!davinci_ks) {
+               dev_dbg(dev, "could not allocate memory for private data\n");
+               return -ENOMEM;
+       }
+
+       memcpy(davinci_ks->keymap, pdata->keymap,
+               sizeof(unsigned short) * pdata->keymapsize);
+
+       key_dev = input_allocate_device();
+       if (!key_dev) {
+               dev_dbg(dev, "could not allocate input device\n");
+               error = -ENOMEM;
+               goto fail1;
+       }
+
+       davinci_ks->input = key_dev;
+
+       davinci_ks->irq = platform_get_irq(pdev, 0);
+       if (davinci_ks->irq < 0) {
+               dev_err(dev, "no key scan irq\n");
+               error = davinci_ks->irq;
+               goto fail2;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "no mem resource\n");
+               error = -EINVAL;
+               goto fail2;
+       }
+
+       davinci_ks->pbase = res->start;
+       davinci_ks->base_size = resource_size(res);
+
+       mem = request_mem_region(davinci_ks->pbase, davinci_ks->base_size,
+                                pdev->name);
+       if (!mem) {
+               dev_err(dev, "key scan registers at %08x are not free\n",
+                       davinci_ks->pbase);
+               error = -EBUSY;
+               goto fail2;
+       }
+
+       davinci_ks->base = ioremap(davinci_ks->pbase, davinci_ks->base_size);
+       if (!davinci_ks->base) {
+               dev_err(dev, "can't ioremap MEM resource.\n");
+               error = -ENOMEM;
+               goto fail3;
+       }
+
+       /* Enable auto repeat feature of Linux input subsystem */
+       if (pdata->rep)
+               __set_bit(EV_REP, key_dev->evbit);
+
+       /* Setup input device */
+       __set_bit(EV_KEY, key_dev->evbit);
+
+       /* Setup the platform data */
+       davinci_ks->pdata = pdata;
+
+       for (i = 0; i < davinci_ks->pdata->keymapsize; i++)
+               __set_bit(davinci_ks->pdata->keymap[i], key_dev->keybit);
+
+       key_dev->name = "davinci_keyscan";
+       key_dev->phys = "davinci_keyscan/input0";
+       key_dev->dev.parent = &pdev->dev;
+       key_dev->id.bustype = BUS_HOST;
+       key_dev->id.vendor = 0x0001;
+       key_dev->id.product = 0x0001;
+       key_dev->id.version = 0x0001;
+       key_dev->keycode = davinci_ks->keymap;
+       key_dev->keycodesize = sizeof(davinci_ks->keymap[0]);
+       key_dev->keycodemax = davinci_ks->pdata->keymapsize;
+
+       error = input_register_device(davinci_ks->input);
+       if (error < 0) {
+               dev_err(dev, "unable to register davinci key scan device\n");
+               goto fail4;
+       }
+
+       error = request_irq(davinci_ks->irq, davinci_ks_interrupt,
+                         IRQF_DISABLED, pdev->name, davinci_ks);
+       if (error < 0) {
+               dev_err(dev, "unable to register davinci key scan interrupt\n");
+               goto fail5;
+       }
+
+       error = davinci_ks_initialize(davinci_ks);
+       if (error < 0) {
+               dev_err(dev, "unable to initialize davinci key scan device\n");
+               goto fail6;
+       }
+
+       platform_set_drvdata(pdev, davinci_ks);
+       return 0;
+
+fail6:
+       free_irq(davinci_ks->irq, davinci_ks);
+fail5:
+       input_unregister_device(davinci_ks->input);
+       key_dev = NULL;
+fail4:
+       iounmap(davinci_ks->base);
+fail3:
+       release_mem_region(davinci_ks->pbase, davinci_ks->base_size);
+fail2:
+       input_free_device(key_dev);
+fail1:
+       kfree(davinci_ks);
+
+       return error;
+}
+
+static int __devexit davinci_ks_remove(struct platform_device *pdev)
+{
+       struct davinci_ks *davinci_ks = platform_get_drvdata(pdev);
+
+       free_irq(davinci_ks->irq, davinci_ks);
+
+       input_unregister_device(davinci_ks->input);
+
+       iounmap(davinci_ks->base);
+       release_mem_region(davinci_ks->pbase, davinci_ks->base_size);
+
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(davinci_ks);
+
+       return 0;
+}
+
+static struct platform_driver davinci_ks_driver = {
+       .driver = {
+               .name = "davinci_keyscan",
+               .owner = THIS_MODULE,
+       },
+       .remove = __devexit_p(davinci_ks_remove),
+};
+
+static int __init davinci_ks_init(void)
+{
+       return platform_driver_probe(&davinci_ks_driver, davinci_ks_probe);
+}
+module_init(davinci_ks_init);
+
+static void __exit davinci_ks_exit(void)
+{
+       platform_driver_unregister(&davinci_ks_driver);
+}
+module_exit(davinci_ks_exit);
+
+MODULE_AUTHOR("Miguel Aguilar");
+MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver");
+MODULE_LICENSE("GPL");
index 77d1309..1aff3b7 100644 (file)
@@ -23,8 +23,7 @@
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
-
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 
 struct gpio_button_data {
        struct gpio_keys_button *button;
@@ -38,10 +37,8 @@ struct gpio_keys_drvdata {
        struct gpio_button_data data[0];
 };
 
-static void gpio_keys_report_event(struct work_struct *work)
+static void gpio_keys_report_event(struct gpio_button_data *bdata)
 {
-       struct gpio_button_data *bdata =
-               container_of(work, struct gpio_button_data, work);
        struct gpio_keys_button *button = bdata->button;
        struct input_dev *input = bdata->input;
        unsigned int type = button->type ?: EV_KEY;
@@ -51,6 +48,14 @@ static void gpio_keys_report_event(struct work_struct *work)
        input_sync(input);
 }
 
+static void gpio_keys_work_func(struct work_struct *work)
+{
+       struct gpio_button_data *bdata =
+               container_of(work, struct gpio_button_data, work);
+
+       gpio_keys_report_event(bdata);
+}
+
 static void gpio_keys_timer(unsigned long _data)
 {
        struct gpio_button_data *data = (struct gpio_button_data *)_data;
@@ -74,10 +79,62 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static int __devinit gpio_keys_setup_key(struct device *dev,
+                                        struct gpio_button_data *bdata,
+                                        struct gpio_keys_button *button)
+{
+       char *desc = button->desc ? button->desc : "gpio_keys";
+       int irq, error;
+
+       setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
+       INIT_WORK(&bdata->work, gpio_keys_work_func);
+
+       error = gpio_request(button->gpio, desc);
+       if (error < 0) {
+               dev_err(dev, "failed to request GPIO %d, error %d\n",
+                       button->gpio, error);
+               goto fail2;
+       }
+
+       error = gpio_direction_input(button->gpio);
+       if (error < 0) {
+               dev_err(dev, "failed to configure"
+                       " direction for GPIO %d, error %d\n",
+                       button->gpio, error);
+               goto fail3;
+       }
+
+       irq = gpio_to_irq(button->gpio);
+       if (irq < 0) {
+               error = irq;
+               dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n",
+                       button->gpio, error);
+               goto fail3;
+       }
+
+       error = request_irq(irq, gpio_keys_isr,
+                           IRQF_SHARED |
+                           IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                           desc, bdata);
+       if (error) {
+               dev_err(dev, "Unable to claim irq %d; error %d\n",
+                       irq, error);
+               goto fail3;
+       }
+
+       return 0;
+
+fail3:
+       gpio_free(button->gpio);
+fail2:
+       return error;
+}
+
 static int __devinit gpio_keys_probe(struct platform_device *pdev)
 {
        struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
        struct gpio_keys_drvdata *ddata;
+       struct device *dev = &pdev->dev;
        struct input_dev *input;
        int i, error;
        int wakeup = 0;
@@ -87,6 +144,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                        GFP_KERNEL);
        input = input_allocate_device();
        if (!ddata || !input) {
+               dev_err(dev, "failed to allocate state\n");
                error = -ENOMEM;
                goto fail1;
        }
@@ -111,52 +169,14 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
        for (i = 0; i < pdata->nbuttons; i++) {
                struct gpio_keys_button *button = &pdata->buttons[i];
                struct gpio_button_data *bdata = &ddata->data[i];
-               int irq;
                unsigned int type = button->type ?: EV_KEY;
 
                bdata->input = input;
                bdata->button = button;
-               setup_timer(&bdata->timer,
-                           gpio_keys_timer, (unsigned long)bdata);
-               INIT_WORK(&bdata->work, gpio_keys_report_event);
-
-               error = gpio_request(button->gpio, button->desc ?: "gpio_keys");
-               if (error < 0) {
-                       pr_err("gpio-keys: failed to request GPIO %d,"
-                               " error %d\n", button->gpio, error);
-                       goto fail2;
-               }
-
-               error = gpio_direction_input(button->gpio);
-               if (error < 0) {
-                       pr_err("gpio-keys: failed to configure input"
-                               " direction for GPIO %d, error %d\n",
-                               button->gpio, error);
-                       gpio_free(button->gpio);
-                       goto fail2;
-               }
-
-               irq = gpio_to_irq(button->gpio);
-               if (irq < 0) {
-                       error = irq;
-                       pr_err("gpio-keys: Unable to get irq number"
-                               " for GPIO %d, error %d\n",
-                               button->gpio, error);
-                       gpio_free(button->gpio);
-                       goto fail2;
-               }
 
-               error = request_irq(irq, gpio_keys_isr,
-                                   IRQF_SHARED |
-                                   IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                                   button->desc ? button->desc : "gpio_keys",
-                                   bdata);
-               if (error) {
-                       pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
-                               irq, error);
-                       gpio_free(button->gpio);
+               error = gpio_keys_setup_key(dev, bdata, button);
+               if (error)
                        goto fail2;
-               }
 
                if (button->wakeup)
                        wakeup = 1;
@@ -166,11 +186,16 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 
        error = input_register_device(input);
        if (error) {
-               pr_err("gpio-keys: Unable to register input device, "
+               dev_err(dev, "Unable to register input device, "
                        "error: %d\n", error);
                goto fail2;
        }
 
+       /* get current state of buttons */
+       for (i = 0; i < pdata->nbuttons; i++)
+               gpio_keys_report_event(&ddata->data[i]);
+       input_sync(input);
+
        device_init_wakeup(&pdev->dev, wakeup);
 
        return 0;
@@ -239,18 +264,21 @@ static int gpio_keys_suspend(struct device *dev)
 static int gpio_keys_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
        struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
        int i;
 
-       if (device_may_wakeup(&pdev->dev)) {
-               for (i = 0; i < pdata->nbuttons; i++) {
-                       struct gpio_keys_button *button = &pdata->buttons[i];
-                       if (button->wakeup) {
-                               int irq = gpio_to_irq(button->gpio);
-                               disable_irq_wake(irq);
-                       }
+       for (i = 0; i < pdata->nbuttons; i++) {
+
+               struct gpio_keys_button *button = &pdata->buttons[i];
+               if (button->wakeup && device_may_wakeup(&pdev->dev)) {
+                       int irq = gpio_to_irq(button->gpio);
+                       disable_irq_wake(irq);
                }
+
+               gpio_keys_report_event(&ddata->data[i]);
        }
+       input_sync(ddata->input);
 
        return 0;
 }
index f9847e0..fa9bb6d 100644 (file)
@@ -72,9 +72,9 @@
 
 #define DRIVER_DESC    "LK keyboard driver"
 
-MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
 
 /*
  * Known parameters:
@@ -85,27 +85,27 @@ MODULE_LICENSE ("GPL");
  * Please notice that there's not yet an API to set these at runtime.
  */
 static int bell_volume = 100; /* % */
-module_param (bell_volume, int, 0);
-MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%");
+module_param(bell_volume, int, 0);
+MODULE_PARM_DESC(bell_volume, "Bell volume (in %). default is 100%");
 
 static int keyclick_volume = 100; /* % */
-module_param (keyclick_volume, int, 0);
-MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%");
+module_param(keyclick_volume, int, 0);
+MODULE_PARM_DESC(keyclick_volume, "Keyclick volume (in %), default is 100%");
 
 static int ctrlclick_volume = 100; /* % */
-module_param (ctrlclick_volume, int, 0);
-MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
+module_param(ctrlclick_volume, int, 0);
+MODULE_PARM_DESC(ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
 
 static int lk201_compose_is_alt;
-module_param (lk201_compose_is_alt, int, 0);
-MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key "
-               "will act as an Alt key");
+module_param(lk201_compose_is_alt, int, 0);
+MODULE_PARM_DESC(lk201_compose_is_alt,
+                "If set non-zero, LK201' Compose key will act as an Alt key");
 
 
 
 #undef LKKBD_DEBUG
 #ifdef LKKBD_DEBUG
-#define DBG(x...) printk (x)
+#define DBG(x...) printk(x)
 #else
 #define DBG(x...) do {} while (0)
 #endif
@@ -122,7 +122,7 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key "
 #define LK_MODE_DOWN           0x80
 #define LK_MODE_AUTODOWN       0x82
 #define LK_MODE_UPDOWN         0x86
-#define LK_CMD_SET_MODE(mode,div)      ((mode) | ((div) << 3))
+#define LK_CMD_SET_MODE(mode, div)     ((mode) | ((div) << 3))
 
 /* Misc commands */
 #define LK_CMD_ENABLE_KEYCLICK 0x1b
@@ -152,11 +152,8 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key "
 
 #define LK_NUM_KEYCODES                256
 #define LK_NUM_IGNORE_BYTES    6
-typedef u_int16_t lk_keycode_t;
 
-
-
-static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
+static unsigned short lkkbd_keycode[LK_NUM_KEYCODES] = {
        [0x56] = KEY_F1,
        [0x57] = KEY_F2,
        [0x58] = KEY_F3,
@@ -268,7 +265,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
 };
 
 #define CHECK_LED(LK, VAR_ON, VAR_OFF, LED, BITS) do {         \
-       if (test_bit (LED, (LK)->dev->led))                     \
+       if (test_bit(LED, (LK)->dev->led))                      \
                VAR_ON |= BITS;                                 \
        else                                                    \
                VAR_OFF |= BITS;                                \
@@ -278,7 +275,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
  * Per-keyboard data
  */
 struct lkkbd {
-       lk_keycode_t keycode[LK_NUM_KEYCODES];
+       unsigned short keycode[LK_NUM_KEYCODES];
        int ignore_bytes;
        unsigned char id[LK_NUM_IGNORE_BYTES];
        struct input_dev *dev;
@@ -301,26 +298,25 @@ static struct {
        unsigned char *name;
 } lk_response[] = {
 #define RESPONSE(x) { .value = (x), .name = #x, }
-       RESPONSE (LK_STUCK_KEY),
-       RESPONSE (LK_SELFTEST_FAILED),
-       RESPONSE (LK_ALL_KEYS_UP),
-       RESPONSE (LK_METRONOME),
-       RESPONSE (LK_OUTPUT_ERROR),
-       RESPONSE (LK_INPUT_ERROR),
-       RESPONSE (LK_KBD_LOCKED),
-       RESPONSE (LK_KBD_TEST_MODE_ACK),
-       RESPONSE (LK_PREFIX_KEY_DOWN),
-       RESPONSE (LK_MODE_CHANGE_ACK),
-       RESPONSE (LK_RESPONSE_RESERVED),
+       RESPONSE(LK_STUCK_KEY),
+       RESPONSE(LK_SELFTEST_FAILED),
+       RESPONSE(LK_ALL_KEYS_UP),
+       RESPONSE(LK_METRONOME),
+       RESPONSE(LK_OUTPUT_ERROR),
+       RESPONSE(LK_INPUT_ERROR),
+       RESPONSE(LK_KBD_LOCKED),
+       RESPONSE(LK_KBD_TEST_MODE_ACK),
+       RESPONSE(LK_PREFIX_KEY_DOWN),
+       RESPONSE(LK_MODE_CHANGE_ACK),
+       RESPONSE(LK_RESPONSE_RESERVED),
 #undef RESPONSE
 };
 
-static unsigned char *
-response_name (unsigned char value)
+static unsigned char *response_name(unsigned char value)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE (lk_response); i++)
+       for (i = 0; i < ARRAY_SIZE(lk_response); i++)
                if (lk_response[i].value == value)
                        return lk_response[i].name;
 
@@ -331,8 +327,7 @@ response_name (unsigned char value)
 /*
  * Calculate volume parameter byte for a given volume.
  */
-static unsigned char
-volume_to_hw (int volume_percent)
+static unsigned char volume_to_hw(int volume_percent)
 {
        unsigned char ret = 0;
 
@@ -363,8 +358,7 @@ volume_to_hw (int volume_percent)
        return ret;
 }
 
-static void
-lkkbd_detection_done (struct lkkbd *lk)
+static void lkkbd_detection_done(struct lkkbd *lk)
 {
        int i;
 
@@ -377,190 +371,202 @@ lkkbd_detection_done (struct lkkbd *lk)
         * Print keyboard name and modify Compose=Alt on user's request.
         */
        switch (lk->id[4]) {
-               case 1:
-                       strlcpy (lk->name, "DEC LK201 keyboard",
-                                sizeof (lk->name));
-
-                       if (lk201_compose_is_alt)
-                               lk->keycode[0xb1] = KEY_LEFTALT;
-                       break;
-
-               case 2:
-                       strlcpy (lk->name, "DEC LK401 keyboard",
-                                sizeof (lk->name));
-                       break;
-
-               default:
-                       strlcpy (lk->name, "Unknown DEC keyboard",
-                                sizeof (lk->name));
-                       printk (KERN_ERR "lkkbd: keyboard on %s is unknown, "
-                                       "please report to Jan-Benedict Glaw "
-                                       "<jbglaw@lug-owl.de>\n", lk->phys);
-                       printk (KERN_ERR "lkkbd: keyboard ID'ed as:");
-                       for (i = 0; i < LK_NUM_IGNORE_BYTES; i++)
-                               printk (" 0x%02x", lk->id[i]);
-                       printk ("\n");
-                       break;
+       case 1:
+               strlcpy(lk->name, "DEC LK201 keyboard", sizeof(lk->name));
+
+               if (lk201_compose_is_alt)
+                       lk->keycode[0xb1] = KEY_LEFTALT;
+               break;
+
+       case 2:
+               strlcpy(lk->name, "DEC LK401 keyboard", sizeof(lk->name));
+               break;
+
+       default:
+               strlcpy(lk->name, "Unknown DEC keyboard", sizeof(lk->name));
+               printk(KERN_ERR
+                       "lkkbd: keyboard on %s is unknown, please report to "
+                       "Jan-Benedict Glaw <jbglaw@lug-owl.de>\n", lk->phys);
+               printk(KERN_ERR "lkkbd: keyboard ID'ed as:");
+               for (i = 0; i < LK_NUM_IGNORE_BYTES; i++)
+                       printk(" 0x%02x", lk->id[i]);
+               printk("\n");
+               break;
        }
-       printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n",
-                       lk->phys, lk->name);
+
+       printk(KERN_INFO "lkkbd: keyboard on %s identified as: %s\n",
+               lk->phys, lk->name);
 
        /*
         * Report errors during keyboard boot-up.
         */
        switch (lk->id[2]) {
-               case 0x00:
-                       /* All okay */
-                       break;
-
-               case LK_STUCK_KEY:
-                       printk (KERN_ERR "lkkbd: Stuck key on keyboard at "
-                                       "%s\n", lk->phys);
-                       break;
-
-               case LK_SELFTEST_FAILED:
-                       printk (KERN_ERR "lkkbd: Selftest failed on keyboard "
-                                       "at %s, keyboard may not work "
-                                       "properly\n", lk->phys);
-                       break;
-
-               default:
-                       printk (KERN_ERR "lkkbd: Unknown error %02x on "
-                                       "keyboard at %s\n", lk->id[2],
-                                       lk->phys);
-                       break;
+       case 0x00:
+               /* All okay */
+               break;
+
+       case LK_STUCK_KEY:
+               printk(KERN_ERR "lkkbd: Stuck key on keyboard at %s\n",
+                       lk->phys);
+               break;
+
+       case LK_SELFTEST_FAILED:
+               printk(KERN_ERR
+                       "lkkbd: Selftest failed on keyboard at %s, "
+                       "keyboard may not work properly\n", lk->phys);
+               break;
+
+       default:
+               printk(KERN_ERR
+                       "lkkbd: Unknown error %02x on keyboard at %s\n",
+                       lk->id[2], lk->phys);
+               break;
        }
 
        /*
         * Try to hint user if there's a stuck key.
         */
        if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0)
-               printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode "
-                               "is 0x%04x\n", lk->id[3],
-                               lk->keycode[lk->id[3]]);
-
-       return;
+               printk(KERN_ERR
+                       "Scancode of stuck key is 0x%02x, keycode is 0x%04x\n",
+                       lk->id[3], lk->keycode[lk->id[3]]);
 }
 
 /*
  * lkkbd_interrupt() is called by the low level driver when a character
  * is received.
  */
-static irqreturn_t
-lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags)
+static irqreturn_t lkkbd_interrupt(struct serio *serio,
+                                  unsigned char data, unsigned int flags)
 {
-       struct lkkbd *lk = serio_get_drvdata (serio);
+       struct lkkbd *lk = serio_get_drvdata(serio);
+       struct input_dev *input_dev = lk->dev;
+       unsigned int keycode;
        int i;
 
-       DBG (KERN_INFO "Got byte 0x%02x\n", data);
+       DBG(KERN_INFO "Got byte 0x%02x\n", data);
 
        if (lk->ignore_bytes > 0) {
-               DBG (KERN_INFO "Ignoring a byte on %s\n", lk->name);
+               DBG(KERN_INFO "Ignoring a byte on %s\n", lk->name);
                lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
 
                if (lk->ignore_bytes == 0)
-                       lkkbd_detection_done (lk);
+                       lkkbd_detection_done(lk);
 
                return IRQ_HANDLED;
        }
 
        switch (data) {
-               case LK_ALL_KEYS_UP:
-                       for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++)
-                               if (lk->keycode[i] != KEY_RESERVED)
-                                       input_report_key (lk->dev, lk->keycode[i], 0);
-                       input_sync (lk->dev);
-                       break;
-
-               case 0x01:
-                       DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n");
-                       lk->ignore_bytes = LK_NUM_IGNORE_BYTES;
-                       lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
-                       schedule_work (&lk->tq);
-                       break;
-
-               case LK_METRONOME:
-               case LK_OUTPUT_ERROR:
-               case LK_INPUT_ERROR:
-               case LK_KBD_LOCKED:
-               case LK_KBD_TEST_MODE_ACK:
-               case LK_PREFIX_KEY_DOWN:
-               case LK_MODE_CHANGE_ACK:
-               case LK_RESPONSE_RESERVED:
-                       DBG (KERN_INFO "Got %s and don't know how to handle...\n",
-                                       response_name (data));
-                       break;
-
-               default:
-                       if (lk->keycode[data] != KEY_RESERVED) {
-                               if (!test_bit (lk->keycode[data], lk->dev->key))
-                                       input_report_key (lk->dev, lk->keycode[data], 1);
-                               else
-                                       input_report_key (lk->dev, lk->keycode[data], 0);
-                               input_sync (lk->dev);
-                        } else
-                                printk (KERN_WARNING "%s: Unknown key with "
-                                               "scancode 0x%02x on %s.\n",
-                                               __FILE__, data, lk->name);
+       case LK_ALL_KEYS_UP:
+               for (i = 0; i < ARRAY_SIZE(lkkbd_keycode); i++)
+                       input_report_key(input_dev, lk->keycode[i], 0);
+               input_sync(input_dev);
+               break;
+
+       case 0x01:
+               DBG(KERN_INFO "Got 0x01, scheduling re-initialization\n");
+               lk->ignore_bytes = LK_NUM_IGNORE_BYTES;
+               lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
+               schedule_work(&lk->tq);
+               break;
+
+       case LK_METRONOME:
+       case LK_OUTPUT_ERROR:
+       case LK_INPUT_ERROR:
+       case LK_KBD_LOCKED:
+       case LK_KBD_TEST_MODE_ACK:
+       case LK_PREFIX_KEY_DOWN:
+       case LK_MODE_CHANGE_ACK:
+       case LK_RESPONSE_RESERVED:
+               DBG(KERN_INFO "Got %s and don't know how to handle...\n",
+                       response_name(data));
+               break;
+
+       default:
+               keycode = lk->keycode[data];
+               if (keycode != KEY_RESERVED) {
+                       input_report_key(input_dev, keycode,
+                                        !test_bit(keycode, input_dev->key));
+                       input_sync(input_dev);
+               } else {
+                       printk(KERN_WARNING
+                               "%s: Unknown key with scancode 0x%02x on %s.\n",
+                               __FILE__, data, lk->name);
+               }
        }
 
        return IRQ_HANDLED;
 }
 
+static void lkkbd_toggle_leds(struct lkkbd *lk)
+{
+       struct serio *serio = lk->serio;
+       unsigned char leds_on = 0;
+       unsigned char leds_off = 0;
+
+       CHECK_LED(lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK);
+       CHECK_LED(lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE);
+       CHECK_LED(lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
+       CHECK_LED(lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
+       if (leds_on != 0) {
+               serio_write(serio, LK_CMD_LED_ON);
+               serio_write(serio, leds_on);
+       }
+       if (leds_off != 0) {
+               serio_write(serio, LK_CMD_LED_OFF);
+               serio_write(serio, leds_off);
+       }
+}
+
+static void lkkbd_toggle_keyclick(struct lkkbd *lk, bool on)
+{
+       struct serio *serio = lk->serio;
+
+       if (on) {
+               DBG("%s: Activating key clicks\n", __func__);
+               serio_write(serio, LK_CMD_ENABLE_KEYCLICK);
+               serio_write(serio, volume_to_hw(lk->keyclick_volume));
+               serio_write(serio, LK_CMD_ENABLE_CTRCLICK);
+               serio_write(serio, volume_to_hw(lk->ctrlclick_volume));
+       } else {
+               DBG("%s: Deactivating key clicks\n", __func__);
+               serio_write(serio, LK_CMD_DISABLE_KEYCLICK);
+               serio_write(serio, LK_CMD_DISABLE_CTRCLICK);
+       }
+
+}
+
 /*
  * lkkbd_event() handles events from the input module.
  */
-static int
-lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
-               int value)
+static int lkkbd_event(struct input_dev *dev,
+                       unsigned int type, unsigned int code, int value)
 {
-       struct lkkbd *lk = input_get_drvdata (dev);
-       unsigned char leds_on = 0;
-       unsigned char leds_off = 0;
+       struct lkkbd *lk = input_get_drvdata(dev);
 
        switch (type) {
-               case EV_LED:
-                       CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK);
-                       CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE);
-                       CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
-                       CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
-                       if (leds_on != 0) {
-                               serio_write (lk->serio, LK_CMD_LED_ON);
-                               serio_write (lk->serio, leds_on);
-                       }
-                       if (leds_off != 0) {
-                               serio_write (lk->serio, LK_CMD_LED_OFF);
-                               serio_write (lk->serio, leds_off);
-                       }
+       case EV_LED:
+               lkkbd_toggle_leds(lk);
+               return 0;
+
+       case EV_SND:
+               switch (code) {
+               case SND_CLICK:
+                       lkkbd_toggle_keyclick(lk, value);
                        return 0;
 
-               case EV_SND:
-                       switch (code) {
-                               case SND_CLICK:
-                                       if (value == 0) {
-                                               DBG ("%s: Deactivating key clicks\n", __func__);
-                                               serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
-                                               serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
-                                       } else {
-                                               DBG ("%s: Activating key clicks\n", __func__);
-                                               serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
-                                               serio_write (lk->serio, volume_to_hw (lk->keyclick_volume));
-                                               serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
-                                               serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
-                                       }
-                                       return 0;
-
-                               case SND_BELL:
-                                       if (value != 0)
-                                               serio_write (lk->serio, LK_CMD_SOUND_BELL);
-
-                                       return 0;
-                       }
-                       break;
-
-               default:
-                       printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n",
-                                       __func__, type, code, value);
+               case SND_BELL:
+                       if (value != 0)
+                               serio_write(lk->serio, LK_CMD_SOUND_BELL);
+
+                       return 0;
+               }
+
+               break;
+
+       default:
+               printk(KERN_ERR "%s(): Got unknown type %d, code %d, value %d\n",
+                       __func__, type, code, value);
        }
 
        return -1;
@@ -570,79 +576,56 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
  * lkkbd_reinit() sets leds and beeps to a state the computer remembers they
  * were in.
  */
-static void
-lkkbd_reinit (struct work_struct *work)
+static void lkkbd_reinit(struct work_struct *work)
 {
        struct lkkbd *lk = container_of(work, struct lkkbd, tq);
        int division;
-       unsigned char leds_on = 0;
-       unsigned char leds_off = 0;
 
        /* Ask for ID */
-       serio_write (lk->serio, LK_CMD_REQUEST_ID);
+       serio_write(lk->serio, LK_CMD_REQUEST_ID);
 
        /* Reset parameters */
-       serio_write (lk->serio, LK_CMD_SET_DEFAULTS);
+       serio_write(lk->serio, LK_CMD_SET_DEFAULTS);
 
        /* Set LEDs */
-       CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK);
-       CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE);
-       CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
-       CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
-       if (leds_on != 0) {
-               serio_write (lk->serio, LK_CMD_LED_ON);
-               serio_write (lk->serio, leds_on);
-       }
-       if (leds_off != 0) {
-               serio_write (lk->serio, LK_CMD_LED_OFF);
-               serio_write (lk->serio, leds_off);
-       }
+       lkkbd_toggle_leds(lk);
 
        /*
         * Try to activate extended LK401 mode. This command will
         * only work with a LK401 keyboard and grants access to
         * LAlt, RAlt, RCompose and RShift.
         */
-       serio_write (lk->serio, LK_CMD_ENABLE_LK401);
+       serio_write(lk->serio, LK_CMD_ENABLE_LK401);
 
        /* Set all keys to UPDOWN mode */
        for (division = 1; division <= 14; division++)
-               serio_write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN,
-                                       division));
+               serio_write(lk->serio,
+                           LK_CMD_SET_MODE(LK_MODE_UPDOWN, division));
 
        /* Enable bell and set volume */
-       serio_write (lk->serio, LK_CMD_ENABLE_BELL);
-       serio_write (lk->serio, volume_to_hw (lk->bell_volume));
+       serio_write(lk->serio, LK_CMD_ENABLE_BELL);
+       serio_write(lk->serio, volume_to_hw(lk->bell_volume));
 
        /* Enable/disable keyclick (and possibly set volume) */
-       if (test_bit (SND_CLICK, lk->dev->snd)) {
-               serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
-               serio_write (lk->serio, volume_to_hw (lk->keyclick_volume));
-               serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
-               serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
-       } else {
-               serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
-               serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
-       }
+       lkkbd_toggle_keyclick(lk, test_bit(SND_CLICK, lk->dev->snd));
 
        /* Sound the bell if needed */
-       if (test_bit (SND_BELL, lk->dev->snd))
-               serio_write (lk->serio, LK_CMD_SOUND_BELL);
+       if (test_bit(SND_BELL, lk->dev->snd))
+               serio_write(lk->serio, LK_CMD_SOUND_BELL);
 }
 
 /*
  * lkkbd_connect() probes for a LK keyboard and fills the necessary structures.
  */
-static int
-lkkbd_connect (struct serio *serio, struct serio_driver *drv)
+static int lkkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
        struct lkkbd *lk;
        struct input_dev *input_dev;
        int i;
        int err;
 
-       lk = kzalloc (sizeof (struct lkkbd), GFP_KERNEL);
-       input_dev = input_allocate_device ();
+       lk = kzalloc(sizeof(struct lkkbd), GFP_KERNEL);
+       input_dev = input_allocate_device();
        if (!lk || !input_dev) {
                err = -ENOMEM;
                goto fail1;
@@ -650,14 +633,14 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
 
        lk->serio = serio;
        lk->dev = input_dev;
-       INIT_WORK (&lk->tq, lkkbd_reinit);
+       INIT_WORK(&lk->tq, lkkbd_reinit);
        lk->bell_volume = bell_volume;
        lk->keyclick_volume = keyclick_volume;
        lk->ctrlclick_volume = ctrlclick_volume;
-       memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES);
+       memcpy(lk->keycode, lkkbd_keycode, sizeof(lk->keycode));
 
-       strlcpy (lk->name, "DEC LK keyboard", sizeof(lk->name));
-       snprintf (lk->phys, sizeof(lk->phys), "%s/input0", serio->phys);
+       strlcpy(lk->name, "DEC LK keyboard", sizeof(lk->name));
+       snprintf(lk->phys, sizeof(lk->phys), "%s/input0", serio->phys);
 
        input_dev->name = lk->name;
        input_dev->phys = lk->phys;
@@ -668,62 +651,61 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
        input_dev->dev.parent = &serio->dev;
        input_dev->event = lkkbd_event;
 
-       input_set_drvdata (input_dev, lk);
+       input_set_drvdata(input_dev, lk);
 
-       set_bit (EV_KEY, input_dev->evbit);
-       set_bit (EV_LED, input_dev->evbit);
-       set_bit (EV_SND, input_dev->evbit);
-       set_bit (EV_REP, input_dev->evbit);
-       set_bit (LED_CAPSL, input_dev->ledbit);
-       set_bit (LED_SLEEP, input_dev->ledbit);
-       set_bit (LED_COMPOSE, input_dev->ledbit);
-       set_bit (LED_SCROLLL, input_dev->ledbit);
-       set_bit (SND_BELL, input_dev->sndbit);
-       set_bit (SND_CLICK, input_dev->sndbit);
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(EV_LED, input_dev->evbit);
+       __set_bit(EV_SND, input_dev->evbit);
+       __set_bit(EV_REP, input_dev->evbit);
+       __set_bit(LED_CAPSL, input_dev->ledbit);
+       __set_bit(LED_SLEEP, input_dev->ledbit);
+       __set_bit(LED_COMPOSE, input_dev->ledbit);
+       __set_bit(LED_SCROLLL, input_dev->ledbit);
+       __set_bit(SND_BELL, input_dev->sndbit);
+       __set_bit(SND_CLICK, input_dev->sndbit);
 
        input_dev->keycode = lk->keycode;
-       input_dev->keycodesize = sizeof (lk_keycode_t);
-       input_dev->keycodemax = LK_NUM_KEYCODES;
+       input_dev->keycodesize = sizeof(lk->keycode[0]);
+       input_dev->keycodemax = ARRAY_SIZE(lk->keycode);
 
        for (i = 0; i < LK_NUM_KEYCODES; i++)
-               __set_bit (lk->keycode[i], input_dev->keybit);
+               __set_bit(lk->keycode[i], input_dev->keybit);
        __clear_bit(KEY_RESERVED, input_dev->keybit);
 
-       serio_set_drvdata (serio, lk);
+       serio_set_drvdata(serio, lk);
 
-       err = serio_open (serio, drv);
+       err = serio_open(serio, drv);
        if (err)
                goto fail2;
 
-       err = input_register_device (lk->dev);
+       err = input_register_device(lk->dev);
        if (err)
                goto fail3;
 
-       serio_write (lk->serio, LK_CMD_POWERCYCLE_RESET);
+       serio_write(lk->serio, LK_CMD_POWERCYCLE_RESET);
 
        return 0;
 
- fail3:        serio_close (serio);
- fail2:        serio_set_drvdata (serio, NULL);
- fail1:        input_free_device (input_dev);
-       kfree (lk);
+ fail3:        serio_close(serio);
+ fail2:        serio_set_drvdata(serio, NULL);
+ fail1:        input_free_device(input_dev);
+       kfree(lk);
        return err;
 }
 
 /*
  * lkkbd_disconnect() unregisters and closes behind us.
  */
-static void
-lkkbd_disconnect (struct serio *serio)
+static void lkkbd_disconnect(struct serio *serio)
 {
-       struct lkkbd *lk = serio_get_drvdata (serio);
-
-       input_get_device (lk->dev);
-       input_unregister_device (lk->dev);
-       serio_close (serio);
-       serio_set_drvdata (serio, NULL);
-       input_put_device (lk->dev);
-       kfree (lk);
+       struct lkkbd *lk = serio_get_drvdata(serio);
+
+       input_get_device(lk->dev);
+       input_unregister_device(lk->dev);
+       serio_close(serio);
+       serio_set_drvdata(serio, NULL);
+       input_put_device(lk->dev);
+       kfree(lk);
 }
 
 static struct serio_device_id lkkbd_serio_ids[] = {
@@ -752,18 +734,16 @@ static struct serio_driver lkkbd_drv = {
 /*
  * The functions for insering/removing us as a module.
  */
-static int __init
-lkkbd_init (void)
+static int __init lkkbd_init(void)
 {
        return serio_register_driver(&lkkbd_drv);
 }
 
-static void __exit
-lkkbd_exit (void)
+static void __exit lkkbd_exit(void)
 {
        serio_unregister_driver(&lkkbd_drv);
 }
 
-module_init (lkkbd_init);
-module_exit (lkkbd_exit);
+module_init(lkkbd_init);
+module_exit(lkkbd_exit);
 
index 91cfe51..34f4a29 100644 (file)
@@ -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
        },
 };
 
index a9bb254..16ec523 100644 (file)
@@ -80,6 +80,7 @@ config INPUT_WISTRON_BTNS
        tristate "x86 Wistron laptop button interface"
        depends on X86 && !X86_64
        select INPUT_POLLDEV
+       select INPUT_SPARSEKMAP
        select NEW_LEDS
        select LEDS_CLASS
        select CHECK_SIGNATURE
@@ -281,6 +282,7 @@ config INPUT_RB532_BUTTON
 config INPUT_DM355EVM
        tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
        depends on MFD_DM355EVM_MSP
+       select INPUT_SPARSEKMAP
        help
          Supports the pushbuttons and IR remote used with
          the DM355 EVM board.
index e290fde..614b65d 100644 (file)
@@ -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));
index f2b67dc..766c069 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 
@@ -33,12 +34,8 @@ struct dm355evm_keys {
        int                     irq;
 };
 
-/* These initial keycodes can be remapped by dm355evm_setkeycode(). */
-static struct {
-       u16     event;
-       u16     keycode;
-} dm355evm_keys[] = {
-
+/* These initial keycodes can be remapped */
+static const struct key_entry dm355evm_keys[] = {
        /*
         * Pushbuttons on the EVM board ... note that the labels for these
         * are SW10/SW11/etc on the PC board.  The left/right orientation
@@ -47,11 +44,11 @@ static struct {
         * is to the right.  (That is, rotate the board counter-clockwise
         * by 90 degrees from the SW10/etc and "DM355 EVM" labels.)
         */
-       { 0x00d8, KEY_OK, },            /* SW12 */
-       { 0x00b8, KEY_UP, },            /* SW13 */
-       { 0x00e8, KEY_DOWN, },          /* SW11 */
-       { 0x0078, KEY_LEFT, },          /* SW14 */
-       { 0x00f0, KEY_RIGHT, },         /* SW10 */
+       { KE_KEY, 0x00d8, { KEY_OK } },         /* SW12 */
+       { KE_KEY, 0x00b8, { KEY_UP } },         /* SW13 */
+       { KE_KEY, 0x00e8, { KEY_DOWN } },       /* SW11 */
+       { KE_KEY, 0x0078, { KEY_LEFT } },       /* SW14 */
+       { KE_KEY, 0x00f0, { KEY_RIGHT } },      /* SW10 */
 
        /*
         * IR buttons ... codes assigned to match the universal remote
@@ -65,35 +62,35 @@ static struct {
         * RC5 codes are 14 bits, with two start bits (0x3 prefix)
         * and a toggle bit (masked out below).
         */
-       { 0x300c, KEY_POWER, },         /* NOTE: docs omit this */
-       { 0x3000, KEY_NUMERIC_0, },
-       { 0x3001, KEY_NUMERIC_1, },
-       { 0x3002, KEY_NUMERIC_2, },
-       { 0x3003, KEY_NUMERIC_3, },
-       { 0x3004, KEY_NUMERIC_4, },
-       { 0x3005, KEY_NUMERIC_5, },
-       { 0x3006, KEY_NUMERIC_6, },
-       { 0x3007, KEY_NUMERIC_7, },
-       { 0x3008, KEY_NUMERIC_8, },
-       { 0x3009, KEY_NUMERIC_9, },
-       { 0x3022, KEY_ENTER, },
-       { 0x30ec, KEY_MODE, },          /* "tv/vcr/..." */
-       { 0x300f, KEY_SELECT, },        /* "info" */
-       { 0x3020, KEY_CHANNELUP, },     /* "up" */
-       { 0x302e, KEY_MENU, },          /* "in/out" */
-       { 0x3011, KEY_VOLUMEDOWN, },    /* "left" */
-       { 0x300d, KEY_MUTE, },          /* "ok" */
-       { 0x3010, KEY_VOLUMEUP, },      /* "right" */
-       { 0x301e, KEY_SUBTITLE, },      /* "cc" */
-       { 0x3021, KEY_CHANNELDOWN, },   /* "down" */
-       { 0x3022, KEY_PREVIOUS, },
-       { 0x3026, KEY_SLEEP, },
-       { 0x3172, KEY_REWIND, },        /* NOTE: docs wrongly say 0x30ca */
-       { 0x3175, KEY_PLAY, },
-       { 0x3174, KEY_FASTFORWARD, },
-       { 0x3177, KEY_RECORD, },
-       { 0x3176, KEY_STOP, },
-       { 0x3169, KEY_PAUSE, },
+       { KE_KEY, 0x300c, { KEY_POWER } },      /* NOTE: docs omit this */
+       { KE_KEY, 0x3000, { KEY_NUMERIC_0 } },
+       { KE_KEY, 0x3001, { KEY_NUMERIC_1 } },
+       { KE_KEY, 0x3002, { KEY_NUMERIC_2 } },
+       { KE_KEY, 0x3003, { KEY_NUMERIC_3 } },
+       { KE_KEY, 0x3004, { KEY_NUMERIC_4 } },
+       { KE_KEY, 0x3005, { KEY_NUMERIC_5 } },
+       { KE_KEY, 0x3006, { KEY_NUMERIC_6 } },
+       { KE_KEY, 0x3007, { KEY_NUMERIC_7 } },
+       { KE_KEY, 0x3008, { KEY_NUMERIC_8 } },
+       { KE_KEY, 0x3009, { KEY_NUMERIC_9 } },
+       { KE_KEY, 0x3022, { KEY_ENTER } },
+       { KE_KEY, 0x30ec, { KEY_MODE } },       /* "tv/vcr/..." */
+       { KE_KEY, 0x300f, { KEY_SELECT } },     /* "info" */
+       { KE_KEY, 0x3020, { KEY_CHANNELUP } },  /* "up" */
+       { KE_KEY, 0x302e, { KEY_MENU } },       /* "in/out" */
+       { KE_KEY, 0x3011, { KEY_VOLUMEDOWN } }, /* "left" */
+       { KE_KEY, 0x300d, { KEY_MUTE } },       /* "ok" */
+       { KE_KEY, 0x3010, { KEY_VOLUMEUP } },   /* "right" */
+       { KE_KEY, 0x301e, { KEY_SUBTITLE } },   /* "cc" */
+       { KE_KEY, 0x3021, { KEY_CHANNELDOWN } },/* "down" */
+       { KE_KEY, 0x3022, { KEY_PREVIOUS } },
+       { KE_KEY, 0x3026, { KEY_SLEEP } },
+       { KE_KEY, 0x3172, { KEY_REWIND } },     /* NOTE: docs wrongly say 0x30ca */
+       { KE_KEY, 0x3175, { KEY_PLAY } },
+       { KE_KEY, 0x3174, { KEY_FASTFORWARD } },
+       { KE_KEY, 0x3177, { KEY_RECORD } },
+       { KE_KEY, 0x3176, { KEY_STOP } },
+       { KE_KEY, 0x3169, { KEY_PAUSE } },
 };
 
 /*
@@ -105,19 +102,18 @@ static struct {
  */
 static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
 {
-       struct dm355evm_keys    *keys = _keys;
-       int                     status;
+       static u16 last_event;
+       struct dm355evm_keys *keys = _keys;
+       const struct key_entry *ke;
+       unsigned int keycode;
+       int status;
+       u16 event;
 
        /* For simplicity we ignore INPUT_COUNT and just read
         * events until we get the "queue empty" indicator.
         * Reading INPUT_LOW decrements the count.
         */
        for (;;) {
-               static u16      last_event;
-               u16             event;
-               int             keycode;
-               int             i;
-
                status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH);
                if (status < 0) {
                        dev_dbg(keys->dev, "input high err %d\n",
@@ -156,14 +152,9 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
                /* ignore the RC5 toggle bit */
                event &= ~0x0800;
 
-               /* find the key, or leave it as unknown */
-               keycode = KEY_UNKNOWN;
-               for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) {
-                       if (dm355evm_keys[i].event != event)
-                               continue;
-                       keycode = dm355evm_keys[i].keycode;
-                       break;
-               }
+               /* find the key, or report it as unknown */
+               ke = sparse_keymap_entry_from_scancode(keys->input, event);
+               keycode = ke ? ke->keycode : KEY_UNKNOWN;
                dev_dbg(keys->dev,
                        "input event 0x%04x--> keycode %d\n",
                        event, keycode);
@@ -174,36 +165,8 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
                input_report_key(keys->input, keycode, 0);
                input_sync(keys->input);
        }
-       return IRQ_HANDLED;
-}
 
-static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode)
-{
-       u16             old_keycode;
-       unsigned        i;
-
-       if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys))
-               return -EINVAL;
-
-       old_keycode = dm355evm_keys[index].keycode;
-       dm355evm_keys[index].keycode = keycode;
-       set_bit(keycode, dev->keybit);
-
-       for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) {
-               if (dm355evm_keys[index].keycode == old_keycode)
-                       goto done;
-       }
-       clear_bit(old_keycode, dev->keybit);
-done:
-       return 0;
-}
-
-static int dm355evm_getkeycode(struct input_dev *dev, int index, int *keycode)
-{
-       if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys))
-               return -EINVAL;
-
-       return dm355evm_keys[index].keycode;
+       return IRQ_HANDLED;
 }
 
 /*----------------------------------------------------------------------*/
@@ -213,7 +176,6 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
        struct dm355evm_keys    *keys;
        struct input_dev        *input;
        int                     status;
-       int                     i;
 
        /* allocate instance struct and input dev */
        keys = kzalloc(sizeof *keys, GFP_KERNEL);
@@ -242,31 +204,30 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
        input->id.product = 0x0355;
        input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
 
-       input->evbit[0] = BIT(EV_KEY);
-       for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++)
-               __set_bit(dm355evm_keys[i].keycode, input->keybit);
-
-       input->setkeycode = dm355evm_setkeycode;
-       input->getkeycode = dm355evm_getkeycode;
+       status = sparse_keymap_setup(input, dm355evm_keys, NULL);
+       if (status)
+               goto fail1;
 
        /* REVISIT:  flush the event queue? */
 
        status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq,
                        IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys);
        if (status < 0)
-               goto fail1;
+               goto fail2;
 
        /* register */
        status = input_register_device(input);
        if (status < 0)
-               goto fail2;
+               goto fail3;
 
        platform_set_drvdata(pdev, keys);
 
        return 0;
 
-fail2:
+fail3:
        free_irq(keys->irq, keys);
+fail2:
+       sparse_keymap_free(input);
 fail1:
        input_free_device(input);
        kfree(keys);
@@ -280,6 +241,7 @@ static int __devexit dm355evm_keys_remove(struct platform_device *pdev)
        struct dm355evm_keys    *keys = platform_get_drvdata(pdev);
 
        free_irq(keys->irq, keys);
+       sparse_keymap_free(keys->input);
        input_unregister_device(keys->input);
        kfree(keys);
 
index a53c488..668913d 100644 (file)
@@ -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);
 
index a932179..38da6ab 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/dmi.h>
 #include <linux/init.h>
 #include <linux/input-polldev.h>
+#include <linux/input/sparse-keymap.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
@@ -224,19 +225,8 @@ static void bios_set_state(u8 subsys, int enable)
 
 /* Hardware database */
 
-struct key_entry {
-       char type;              /* See KE_* below */
-       u8 code;
-       union {
-               u16 keycode;            /* For KE_KEY */
-               struct {                /* For KE_SW */
-                       u8 code;
-                       u8 value;
-               } sw;
-       };
-};
-
-enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
+#define KE_WIFI                (KE_LAST + 1)
+#define KE_BLUETOOTH   (KE_LAST + 2)
 
 #define FE_MAIL_LED 0x01
 #define FE_WIFI_LED 0x02
@@ -644,10 +634,10 @@ static struct key_entry keymap_prestigio[] __initdata = {
  * a list of buttons and their key codes (reported when loading this module
  * with force=1) and the output of dmidecode to $MODULE_AUTHOR.
  */
-static struct dmi_system_id dmi_ids[] __initdata = {
+static const struct dmi_system_id __initconst dmi_ids[] = {
        {
+               /* Fujitsu-Siemens Amilo Pro V2000 */
                .callback = dmi_matched,
-               .ident = "Fujitsu-Siemens Amilo Pro V2000",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"),
@@ -655,8 +645,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_fs_amilo_pro_v2000
        },
        {
+               /* Fujitsu-Siemens Amilo Pro Edition V3505 */
                .callback = dmi_matched,
-               .ident = "Fujitsu-Siemens Amilo Pro Edition V3505",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"),
@@ -664,8 +654,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_fs_amilo_pro_v3505
        },
        {
+               /* Fujitsu-Siemens Amilo M7400 */
                .callback = dmi_matched,
-               .ident = "Fujitsu-Siemens Amilo M7400",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M        "),
@@ -673,8 +663,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_fs_amilo_pro_v2000
        },
        {
+               /* Maxdata Pro 7000 DX */
                .callback = dmi_matched,
-               .ident = "Maxdata Pro 7000 DX",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"),
@@ -682,8 +672,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_fs_amilo_pro_v2000
        },
        {
+               /* Fujitsu N3510 */
                .callback = dmi_matched,
-               .ident = "Fujitsu N3510",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "N3510"),
@@ -691,8 +681,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_fujitsu_n3510
        },
        {
+               /* Acer Aspire 1500 */
                .callback = dmi_matched,
-               .ident = "Acer Aspire 1500",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"),
@@ -700,8 +690,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_aspire_1500
        },
        {
+               /* Acer Aspire 1600 */
                .callback = dmi_matched,
-               .ident = "Acer Aspire 1600",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"),
@@ -709,8 +699,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_aspire_1600
        },
        {
+               /* Acer Aspire 3020 */
                .callback = dmi_matched,
-               .ident = "Acer Aspire 3020",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
@@ -718,8 +708,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_aspire_5020
        },
        {
+               /* Acer Aspire 5020 */
                .callback = dmi_matched,
-               .ident = "Acer Aspire 5020",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
@@ -727,8 +717,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_aspire_5020
        },
        {
+               /* Acer TravelMate 2100 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 2100",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"),
@@ -736,8 +726,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_aspire_5020
        },
        {
+               /* Acer TravelMate 2410 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 2410",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"),
@@ -745,8 +735,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_2410
        },
        {
+               /* Acer TravelMate C300 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate C300",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"),
@@ -754,8 +744,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_300
        },
        {
+               /* Acer TravelMate C100 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate C100",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"),
@@ -763,8 +753,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_300
        },
        {
+               /* Acer TravelMate C110 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate C110",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"),
@@ -772,8 +762,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_110
        },
        {
+               /* Acer TravelMate 380 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 380",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"),
@@ -781,8 +771,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_380
        },
        {
+               /* Acer TravelMate 370 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 370",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"),
@@ -790,8 +780,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
        },
        {
+               /* Acer TravelMate 220 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 220",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"),
@@ -799,8 +789,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_220
        },
        {
+               /* Acer TravelMate 260 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 260",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"),
@@ -808,8 +798,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_220
        },
        {
+               /* Acer TravelMate 230 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 230",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"),
@@ -818,8 +808,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_230
        },
        {
+               /* Acer TravelMate 280 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 280",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"),
@@ -827,8 +817,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_230
        },
        {
+               /* Acer TravelMate 240 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 240",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"),
@@ -836,8 +826,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_240
        },
        {
+               /* Acer TravelMate 250 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 250",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"),
@@ -845,8 +835,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_240
        },
        {
+               /* Acer TravelMate 2424NWXCi */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 2424NWXCi",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
@@ -854,8 +844,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_240
        },
        {
+               /* Acer TravelMate 350 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 350",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"),
@@ -863,8 +853,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_350
        },
        {
+               /* Acer TravelMate 360 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 360",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
@@ -872,8 +862,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_360
        },
        {
+               /* Acer TravelMate 610 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 610",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"),
@@ -881,8 +871,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_610
        },
        {
+               /* Acer TravelMate 620 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 620",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"),
@@ -890,8 +880,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_630
        },
        {
+               /* Acer TravelMate 630 */
                .callback = dmi_matched,
-               .ident = "Acer TravelMate 630",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"),
@@ -899,8 +889,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_acer_travelmate_630
        },
        {
+               /* AOpen 1559AS */
                .callback = dmi_matched,
-               .ident = "AOpen 1559AS",
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "E2U"),
                        DMI_MATCH(DMI_BOARD_NAME, "E2U"),
@@ -908,8 +898,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_aopen_1559as
        },
        {
+               /* Medion MD 9783 */
                .callback = dmi_matched,
-               .ident = "Medion MD 9783",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"),
@@ -917,8 +907,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_wistron_ms2111
        },
        {
+               /* Medion MD 40100 */
                .callback = dmi_matched,
-               .ident = "Medion MD 40100",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"),
@@ -926,8 +916,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_wistron_md40100
        },
        {
+               /* Medion MD 2900 */
                .callback = dmi_matched,
-               .ident = "Medion MD 2900",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"),
@@ -935,8 +925,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_wistron_md2900
        },
        {
+               /* Medion MD 42200 */
                .callback = dmi_matched,
-               .ident = "Medion MD 42200",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"),
@@ -944,8 +934,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_fs_amilo_pro_v2000
        },
        {
+               /* Medion MD 96500 */
                .callback = dmi_matched,
-               .ident = "Medion MD 96500",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"),
@@ -953,8 +943,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_wistron_md96500
        },
        {
+               /* Medion MD 95400 */
                .callback = dmi_matched,
-               .ident = "Medion MD 95400",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"),
@@ -962,8 +952,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_wistron_md96500
        },
        {
+               /* Fujitsu Siemens Amilo D7820 */
                .callback = dmi_matched,
-               .ident = "Fujitsu Siemens Amilo D7820",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */
                        DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"),
@@ -971,8 +961,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                .driver_data = keymap_fs_amilo_d88x0
        },
        {
+               /* Fujitsu Siemens Amilo D88x0 */
                .callback = dmi_matched,
-               .ident = "Fujitsu Siemens Amilo D88x0",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"),
@@ -1037,21 +1027,6 @@ static unsigned long jiffies_last_press;
 static bool wifi_enabled;
 static bool bluetooth_enabled;
 
-static void report_key(struct input_dev *dev, unsigned int keycode)
-{
-       input_report_key(dev, keycode, 1);
-       input_sync(dev);
-       input_report_key(dev, keycode, 0);
-       input_sync(dev);
-}
-
-static void report_switch(struct input_dev *dev, unsigned int code, int value)
-{
-       input_report_switch(dev, code, value);
-       input_sync(dev);
-}
-
-
  /* led management */
 static void wistron_mail_led_set(struct led_classdev *led_cdev,
                                enum led_brightness value)
@@ -1128,43 +1103,13 @@ static inline void wistron_led_resume(void)
                led_classdev_resume(&wistron_wifi_led);
 }
 
-static struct key_entry *wistron_get_entry_by_scancode(int code)
-{
-       struct key_entry *key;
-
-       for (key = keymap; key->type != KE_END; key++)
-               if (code == key->code)
-                       return key;
-
-       return NULL;
-}
-
-static struct key_entry *wistron_get_entry_by_keycode(int keycode)
-{
-       struct key_entry *key;
-
-       for (key = keymap; key->type != KE_END; key++)
-               if (key->type == KE_KEY && keycode == key->keycode)
-                       return key;
-
-       return NULL;
-}
-
 static void handle_key(u8 code)
 {
-       const struct key_entry *key = wistron_get_entry_by_scancode(code);
+       const struct key_entry *key =
+               sparse_keymap_entry_from_scancode(wistron_idev->input, code);
 
        if (key) {
                switch (key->type) {
-               case KE_KEY:
-                       report_key(wistron_idev->input, key->keycode);
-                       break;
-
-               case KE_SW:
-                       report_switch(wistron_idev->input,
-                                     key->sw.code, key->sw.value);
-                       break;
-
                case KE_WIFI:
                        if (have_wifi) {
                                wifi_enabled = !wifi_enabled;
@@ -1180,7 +1125,9 @@ static void handle_key(u8 code)
                        break;
 
                default:
-                       BUG();
+                       sparse_keymap_report_entry(wistron_idev->input,
+                                                  key, 1, true);
+                       break;
                }
                jiffies_last_press = jiffies;
        } else
@@ -1220,42 +1167,39 @@ static void wistron_poll(struct input_polled_dev *dev)
                dev->poll_interval = POLL_INTERVAL_DEFAULT;
 }
 
-static int wistron_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static int __devinit wistron_setup_keymap(struct input_dev *dev,
+                                         struct key_entry *entry)
 {
-       const struct key_entry *key = wistron_get_entry_by_scancode(scancode);
+       switch (entry->type) {
 
-       if (key && key->type == KE_KEY) {
-               *keycode = key->keycode;
-               return 0;
-       }
-
-       return -EINVAL;
-}
+       /* if wifi or bluetooth are not available, create normal keys */
+       case KE_WIFI:
+               if (!have_wifi) {
+                       entry->type = KE_KEY;
+                       entry->keycode = KEY_WLAN;
+               }
+               break;
 
-static int wistron_setkeycode(struct input_dev *dev, int scancode, int keycode)
-{
-       struct key_entry *key;
-       int old_keycode;
-
-       if (keycode < 0 || keycode > KEY_MAX)
-               return -EINVAL;
-
-       key = wistron_get_entry_by_scancode(scancode);
-       if (key && key->type == KE_KEY) {
-               old_keycode = key->keycode;
-               key->keycode = keycode;
-               set_bit(keycode, dev->keybit);
-               if (!wistron_get_entry_by_keycode(old_keycode))
-                       clear_bit(old_keycode, dev->keybit);
-               return 0;
+       case KE_BLUETOOTH:
+               if (!have_bluetooth) {
+                       entry->type = KE_KEY;
+                       entry->keycode = KEY_BLUETOOTH;
+               }
+               break;
+
+       case KE_END:
+               if (entry->code & FE_UNTESTED)
+                       printk(KERN_WARNING "Untested laptop multimedia keys, "
+                               "please report success or failure to "
+                               "eric.piel@tremplin-utc.net\n");
+               break;
        }
 
-       return -EINVAL;
+       return 0;
 }
 
 static int __devinit setup_input_dev(void)
 {
-       struct key_entry *key;
        struct input_dev *input_dev;
        int error;
 
@@ -1263,7 +1207,7 @@ static int __devinit setup_input_dev(void)
        if (!wistron_idev)
                return -ENOMEM;
 
-       wistron_idev->flush = wistron_flush;
+       wistron_idev->open = wistron_flush;
        wistron_idev->poll = wistron_poll;
        wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT;
 
@@ -1273,56 +1217,21 @@ static int __devinit setup_input_dev(void)
        input_dev->id.bustype = BUS_HOST;
        input_dev->dev.parent = &wistron_device->dev;
 
-       input_dev->getkeycode = wistron_getkeycode;
-       input_dev->setkeycode = wistron_setkeycode;
-
-       for (key = keymap; key->type != KE_END; key++) {
-               switch (key->type) {
-                       case KE_KEY:
-                               set_bit(EV_KEY, input_dev->evbit);
-                               set_bit(key->keycode, input_dev->keybit);
-                               break;
-
-                       case KE_SW:
-                               set_bit(EV_SW, input_dev->evbit);
-                               set_bit(key->sw.code, input_dev->swbit);
-                               break;
-
-                       /* if wifi or bluetooth are not available, create normal keys */
-                       case KE_WIFI:
-                               if (!have_wifi) {
-                                       key->type = KE_KEY;
-                                       key->keycode = KEY_WLAN;
-                                       key--;
-                               }
-                               break;
-
-                       case KE_BLUETOOTH:
-                               if (!have_bluetooth) {
-                                       key->type = KE_KEY;
-                                       key->keycode = KEY_BLUETOOTH;
-                                       key--;
-                               }
-                               break;
-
-                       default:
-                               break;
-               }
-       }
-
-       /* reads information flags on KE_END */
-       if (key->code & FE_UNTESTED)
-               printk(KERN_WARNING "Untested laptop multimedia keys, "
-                       "please report success or failure to eric.piel"
-                       "@tremplin-utc.net\n");
+       error = sparse_keymap_setup(input_dev, keymap, wistron_setup_keymap);
+       if (error)
+               goto err_free_dev;
 
        error = input_register_polled_device(wistron_idev);
-       if (error) {
-               input_free_polled_device(wistron_idev);
-               return error;
-       }
+       if (error)
+               goto err_free_keymap;
 
        return 0;
+
+ err_free_keymap:
+       sparse_keymap_free(input_dev);
+ err_free_dev:
+       input_free_polled_device(wistron_idev);
+       return error;
 }
 
 /* Driver core */
@@ -1371,6 +1280,7 @@ static int __devexit wistron_remove(struct platform_device *dev)
 {
        wistron_led_remove();
        input_unregister_polled_device(wistron_idev);
+       sparse_keymap_free(wistron_idev->input);
        input_free_polled_device(wistron_idev);
        bios_detach();
 
index f361106..a3f492a 100644 (file)
 #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;
index fda35e6..b27684f 100644 (file)
@@ -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);
index de1e553..b146237 100644 (file)
@@ -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;
index 8281155..2e6bdfe 100644 (file)
@@ -25,11 +25,13 @@ struct lifebook_data {
        char phys[32];
 };
 
+static bool lifebook_present;
+
 static const char *desired_serio_phys;
 
-static int lifebook_set_serio_phys(const struct dmi_system_id *d)
+static int lifebook_limit_serio3(const struct dmi_system_id *d)
 {
-       desired_serio_phys = d->driver_data;
+       desired_serio_phys = "isa0060/serio3";
        return 0;
 }
 
@@ -41,53 +43,53 @@ static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
        return 0;
 }
 
-static const struct dmi_system_id lifebook_dmi_table[] = {
+static const struct dmi_system_id __initconst lifebook_dmi_table[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
        {
-               .ident = "FLORA-ie 55mi",
+               /* FLORA-ie 55mi */
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"),
                },
        },
        {
-               .ident = "LifeBook B",
+               /* LifeBook B */
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"),
                },
        },
        {
-               .ident = "Lifebook B",
+               /* Lifebook B */
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
                },
        },
        {
-               .ident = "Lifebook B-2130",
+               /* Lifebook B-2130 */
                .matches = {
                        DMI_MATCH(DMI_BOARD_NAME, "ZEPHYR"),
                },
        },
        {
-               .ident = "Lifebook B213x/B2150",
+               /* Lifebook B213x/B2150 */
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"),
                },
        },
        {
-               .ident = "Zephyr",
+               /* Zephyr */
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"),
                },
        },
        {
-               .ident = "CF-18",
+               /* Panasonic CF-18 */
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
                },
-               .callback = lifebook_set_serio_phys,
-               .driver_data = "isa0060/serio3",
+               .callback = lifebook_limit_serio3,
        },
        {
-               .ident = "Panasonic CF-28",
+               /* Panasonic CF-28 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"),
@@ -95,7 +97,7 @@ static const struct dmi_system_id lifebook_dmi_table[] = {
                .callback = lifebook_set_6byte_proto,
        },
        {
-               .ident = "Panasonic CF-29",
+               /* Panasonic CF-29 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
@@ -103,21 +105,27 @@ static const struct dmi_system_id lifebook_dmi_table[] = {
                .callback = lifebook_set_6byte_proto,
        },
        {
-               .ident = "CF-72",
+               /* Panasonic CF-72 */
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"),
                },
                .callback = lifebook_set_6byte_proto,
        },
        {
-               .ident = "Lifebook B142",
+               /* Lifebook B142 */
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
                },
        },
        { }
+#endif
 };
 
+void __init lifebook_module_init(void)
+{
+       lifebook_present = dmi_check_system(lifebook_dmi_table);
+}
+
 static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
 {
        struct lifebook_data *priv = psmouse->private;
@@ -198,10 +206,10 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
                return -1;
 
        /*
-          Enable absolute output -- ps2_command fails always but if
-          you leave this call out the touchsreen will never send
-          absolute coordinates
-       */
+        * Enable absolute output -- ps2_command fails always but if
+        * you leave this call out the touchsreen will never send
+        * absolute coordinates
+        */
        param = lifebook_use_6byte_proto ? 0x08 : 0x07;
        ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
 
@@ -243,7 +251,7 @@ static void lifebook_disconnect(struct psmouse *psmouse)
 
 int lifebook_detect(struct psmouse *psmouse, bool set_properties)
 {
-        if (!dmi_check_system(lifebook_dmi_table))
+        if (!lifebook_present)
                 return -1;
 
        if (desired_serio_phys &&
@@ -283,8 +291,8 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
 
        dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
        dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-       dev2->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
-               BIT_MASK(BTN_RIGHT);
+       dev2->keybit[BIT_WORD(BTN_LEFT)] =
+                               BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
 
        error = input_register_device(priv->dev2);
        if (error)
@@ -309,6 +317,7 @@ int lifebook_init(struct psmouse *psmouse)
 
        dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
        dev1->relbit[0] = 0;
+       dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0;
        dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
        input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
        input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
index 407cb22..4c4326c 100644 (file)
 #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;
index ab5dc5f..543c240 100644 (file)
@@ -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);
index 07c5379..fd0bc09 100644 (file)
@@ -425,6 +425,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties)
                return -1;
 
        if (set_properties) {
+               __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
                __set_bit(BTN_EXTRA, psmouse->dev->keybit);
                __set_bit(BTN_SIDE, psmouse->dev->keybit);
                __set_bit(REL_WHEEL, psmouse->dev->relbit);
@@ -460,8 +461,10 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
                __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
                __set_bit(REL_WHEEL, psmouse->dev->relbit);
 
-               if (!psmouse->vendor) psmouse->vendor = "Generic";
-               if (!psmouse->name) psmouse->name = "Wheel Mouse";
+               if (!psmouse->vendor)
+                       psmouse->vendor = "Generic";
+               if (!psmouse->name)
+                       psmouse->name = "Wheel Mouse";
                psmouse->pktsize = 4;
        }
 
@@ -504,8 +507,10 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
                __set_bit(BTN_SIDE, psmouse->dev->keybit);
                __set_bit(BTN_EXTRA, psmouse->dev->keybit);
 
-               if (!psmouse->vendor) psmouse->vendor = "Generic";
-               if (!psmouse->name) psmouse->name = "Explorer Mouse";
+               if (!psmouse->vendor)
+                       psmouse->vendor = "Generic";
+               if (!psmouse->name)
+                       psmouse->name = "Explorer Mouse";
                psmouse->pktsize = 4;
        }
 
@@ -536,6 +541,7 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties)
                return -1;
 
        if (set_properties) {
+               __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
                __set_bit(BTN_EXTRA, psmouse->dev->keybit);
 
                psmouse->vendor = "Kensington";
@@ -551,8 +557,16 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties)
 static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
 {
        if (set_properties) {
-               if (!psmouse->vendor) psmouse->vendor = "Generic";
-               if (!psmouse->name) psmouse->name = "Mouse";
+               if (!psmouse->vendor)
+                       psmouse->vendor = "Generic";
+               if (!psmouse->name)
+                       psmouse->name = "Mouse";
+
+/*
+ * We have no way of figuring true number of buttons so let's
+ * assume that the device has 3.
+ */
+               __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
        }
 
        return 0;
@@ -567,6 +581,8 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties)
        if (set_properties) {
                psmouse->vendor = "Cortron";
                psmouse->name = "PS/2 Trackball";
+
+               __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
                __set_bit(BTN_SIDE, psmouse->dev->keybit);
        }
 
@@ -1184,15 +1200,16 @@ static void psmouse_disconnect(struct serio *serio)
        mutex_unlock(&psmouse_mutex);
 }
 
-static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto)
+static int psmouse_switch_protocol(struct psmouse *psmouse,
+                                  const struct psmouse_protocol *proto)
 {
        struct input_dev *input_dev = psmouse->dev;
 
        input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
 
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-       input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
-               BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+       input_dev->keybit[BIT_WORD(BTN_MOUSE)] =
+                               BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
        input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
 
        psmouse->set_rate = psmouse_set_rate;
@@ -1209,8 +1226,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse
                        return -1;
 
                psmouse->type = proto->type;
-       }
-       else
+       } else
                psmouse->type = psmouse_extensions(psmouse,
                                                   psmouse_max_proto, true);
 
@@ -1680,6 +1696,9 @@ static int __init psmouse_init(void)
 {
        int err;
 
+       lifebook_module_init();
+       synaptics_module_init();
+
        kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
        if (!kpsmoused_wq) {
                printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
index f84cbd9..77b9fd0 100644 (file)
@@ -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);
index f4a6125..05689e7 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/dmi.h>
 #include <linux/input.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
@@ -629,25 +630,26 @@ static int synaptics_reconnect(struct psmouse *psmouse)
        return 0;
 }
 
-#if defined(__i386__)
-#include <linux/dmi.h>
-static const struct dmi_system_id toshiba_dmi_table[] = {
+static bool impaired_toshiba_kbc;
+
+static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
        {
-               .ident = "Toshiba Satellite",
+               /* Toshiba Satellite */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"),
                },
        },
        {
-               .ident = "Toshiba Dynabook",
+               /* Toshiba Dynabook */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"),
                },
        },
        {
-               .ident = "Toshiba Portege M300",
+               /* Toshiba Portege M300 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"),
@@ -655,7 +657,7 @@ static const struct dmi_system_id toshiba_dmi_table[] = {
 
        },
        {
-               .ident = "Toshiba Portege M300",
+               /* Toshiba Portege M300 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"),
@@ -664,8 +666,13 @@ static const struct dmi_system_id toshiba_dmi_table[] = {
 
        },
        { }
-};
 #endif
+};
+
+void __init synaptics_module_init(void)
+{
+       impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
+}
 
 int synaptics_init(struct psmouse *psmouse)
 {
@@ -718,18 +725,16 @@ int synaptics_init(struct psmouse *psmouse)
        if (SYN_CAP_PASS_THROUGH(priv->capabilities))
                synaptics_pt_create(psmouse);
 
-#if defined(__i386__)
        /*
         * Toshiba's KBC seems to have trouble handling data from
         * Synaptics as full rate, switch to lower rate which is roughly
         * thye same as rate of standard PS/2 mouse.
         */
-       if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) {
+       if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
                printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
                        dmi_get_system_info(DMI_PRODUCT_NAME));
                psmouse->rate = 40;
        }
-#endif
 
        return 0;
 
@@ -740,6 +745,10 @@ int synaptics_init(struct psmouse *psmouse)
 
 #else /* CONFIG_MOUSE_PS2_SYNAPTICS */
 
+void __init synaptics_module_init(void)
+{
+}
+
 int synaptics_init(struct psmouse *psmouse)
 {
        return -ENOSYS;
index 871f6fe..838e7f2 100644 (file)
@@ -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);
index 7283c78..9867dfe 100644 (file)
@@ -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;
 
index 0308a0f..909431c 100644 (file)
@@ -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);
 
index e354362..63d4a67 100644 (file)
@@ -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;
        }
 
index 7011144..bf2c0c8 100644 (file)
 
 #define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet"
 
-MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
 
 #undef VSXXXAA_DEBUG
 #ifdef VSXXXAA_DEBUG
-#define DBG(x...) printk (x)
+#define DBG(x...) printk(x)
 #else
 #define DBG(x...) do {} while (0)
 #endif
 
 #define VSXXXAA_INTRO_MASK     0x80
 #define VSXXXAA_INTRO_HEAD     0x80
-#define IS_HDR_BYTE(x)         (((x) & VSXXXAA_INTRO_MASK)     \
-                                       == VSXXXAA_INTRO_HEAD)
+#define IS_HDR_BYTE(x)                 \
+       (((x) & VSXXXAA_INTRO_MASK) == VSXXXAA_INTRO_HEAD)
 
 #define VSXXXAA_PACKET_MASK    0xe0
 #define VSXXXAA_PACKET_REL     0x80
 #define VSXXXAA_PACKET_ABS     0xc0
 #define VSXXXAA_PACKET_POR     0xa0
-#define MATCH_PACKET_TYPE(data, type)  (((data) & VSXXXAA_PACKET_MASK) == (type))
+#define MATCH_PACKET_TYPE(data, type)  \
+       (((data) & VSXXXAA_PACKET_MASK) == (type))
 
 
 
@@ -123,52 +124,50 @@ struct vsxxxaa {
        char phys[32];
 };
 
-static void
-vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num)
+static void vsxxxaa_drop_bytes(struct vsxxxaa *mouse, int num)
 {
-       if (num >= mouse->count)
+       if (num >= mouse->count) {
                mouse->count = 0;
-       else {
-               memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num);
+       } else {
+               memmove(mouse->buf, mouse->buf + num - 1, BUFLEN - num);
                mouse->count -= num;
        }
 }
 
-static void
-vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte)
+static void vsxxxaa_queue_byte(struct vsxxxaa *mouse, unsigned char byte)
 {
        if (mouse->count == BUFLEN) {
-               printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n",
-                               mouse->name, mouse->phys);
-               vsxxxaa_drop_bytes (mouse, 1);
+               printk(KERN_ERR "%s on %s: Dropping a byte of full buffer.\n",
+                       mouse->name, mouse->phys);
+               vsxxxaa_drop_bytes(mouse, 1);
        }
-       DBG (KERN_INFO "Queueing byte 0x%02x\n", byte);
+
+       DBG(KERN_INFO "Queueing byte 0x%02x\n", byte);
 
        mouse->buf[mouse->count++] = byte;
 }
 
-static void
-vsxxxaa_detection_done (struct vsxxxaa *mouse)
+static void vsxxxaa_detection_done(struct vsxxxaa *mouse)
 {
        switch (mouse->type) {
-               case 0x02:
-                       strlcpy (mouse->name, "DEC VSXXX-AA/-GA mouse",
-                                sizeof (mouse->name));
-                       break;
-
-               case 0x04:
-                       strlcpy (mouse->name, "DEC VSXXX-AB digitizer",
-                                sizeof (mouse->name));
-                       break;
-
-               default:
-                       snprintf (mouse->name, sizeof (mouse->name),
-                                 "unknown DEC pointer device (type = 0x%02x)",
-                                 mouse->type);
-                       break;
+       case 0x02:
+               strlcpy(mouse->name, "DEC VSXXX-AA/-GA mouse",
+                       sizeof(mouse->name));
+               break;
+
+       case 0x04:
+               strlcpy(mouse->name, "DEC VSXXX-AB digitizer",
+                       sizeof(mouse->name));
+               break;
+
+       default:
+               snprintf(mouse->name, sizeof(mouse->name),
+                        "unknown DEC pointer device (type = 0x%02x)",
+                        mouse->type);
+               break;
        }
 
-       printk (KERN_INFO
+       printk(KERN_INFO
                "Found %s version 0x%02x from country 0x%02x on port %s\n",
                mouse->name, mouse->version, mouse->country, mouse->phys);
 }
@@ -176,42 +175,38 @@ vsxxxaa_detection_done (struct vsxxxaa *mouse)
 /*
  * Returns number of bytes to be dropped, 0 if packet is okay.
  */
-static int
-vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len)
+static int vsxxxaa_check_packet(struct vsxxxaa *mouse, int packet_len)
 {
        int i;
 
        /* First byte must be a header byte */
-       if (!IS_HDR_BYTE (mouse->buf[0])) {
-               DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]);
+       if (!IS_HDR_BYTE(mouse->buf[0])) {
+               DBG("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]);
                return 1;
        }
 
        /* Check all following bytes */
-       if (packet_len > 1) {
-               for (i = 1; i < packet_len; i++) {
-                       if (IS_HDR_BYTE (mouse->buf[i])) {
-                               printk (KERN_ERR "Need to drop %d bytes "
-                                               "of a broken packet.\n",
-                                               i - 1);
-                               DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n",
-                                               packet_len, i, mouse->buf[i]);
-                               return i - 1;
-                       }
+       for (i = 1; i < packet_len; i++) {
+               if (IS_HDR_BYTE(mouse->buf[i])) {
+                       printk(KERN_ERR
+                               "Need to drop %d bytes of a broken packet.\n",
+                               i - 1);
+                       DBG(KERN_INFO "check: len=%d, b[%d]=0x%02x\n",
+                           packet_len, i, mouse->buf[i]);
+                       return i - 1;
                }
        }
 
        return 0;
 }
 
-static __inline__ int
-vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len)
+static inline int vsxxxaa_smells_like_packet(struct vsxxxaa *mouse,
+                                            unsigned char type, size_t len)
 {
-       return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type);
+       return mouse->count >= len && MATCH_PACKET_TYPE(mouse->buf[0], type);
 }
 
-static void
-vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse)
+static void vsxxxaa_handle_REL_packet(struct vsxxxaa *mouse)
 {
        struct input_dev *dev = mouse->dev;
        unsigned char *buf = mouse->buf;
@@ -232,43 +227,42 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse)
         * 0, bit 4 of byte 0 is direction.
         */
        dx = buf[1] & 0x7f;
-       dx *= ((buf[0] >> 4) & 0x01)? 1: -1;
+       dx *= ((buf[0] >> 4) & 0x01) ? 1 : -1;
 
        /*
         * Low 7 bit of byte 2 are abs(dy), bit 7 is
         * 0, bit 3 of byte 0 is direction.
         */
        dy = buf[2] & 0x7f;
-       dy *= ((buf[0] >> 3) & 0x01)? -1: 1;
+       dy *= ((buf[0] >> 3) & 0x01) ? -1 : 1;
 
        /*
         * Get button state. It's the low three bits
         * (for three buttons) of byte 0.
         */
-       left    = (buf[0] & 0x04)? 1: 0;
-       middle  = (buf[0] & 0x02)? 1: 0;
-       right   = (buf[0] & 0x01)? 1: 0;
+       left    = buf[0] & 0x04;
+       middle  = buf[0] & 0x02;
+       right   = buf[0] & 0x01;
 
-       vsxxxaa_drop_bytes (mouse, 3);
+       vsxxxaa_drop_bytes(mouse, 3);
 
-       DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n",
-                       mouse->name, mouse->phys, dx, dy,
-                       left? "L": "l", middle? "M": "m", right? "R": "r");
+       DBG(KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n",
+           mouse->name, mouse->phys, dx, dy,
+           left ? "L" : "l", middle ? "M" : "m", right ? "R" : "r");
 
        /*
         * Report what we've found so far...
         */
-       input_report_key (dev, BTN_LEFT, left);
-       input_report_key (dev, BTN_MIDDLE, middle);
-       input_report_key (dev, BTN_RIGHT, right);
-       input_report_key (dev, BTN_TOUCH, 0);
-       input_report_rel (dev, REL_X, dx);
-       input_report_rel (dev, REL_Y, dy);
-       input_sync (dev);
+       input_report_key(dev, BTN_LEFT, left);
+       input_report_key(dev, BTN_MIDDLE, middle);
+       input_report_key(dev, BTN_RIGHT, right);
+       input_report_key(dev, BTN_TOUCH, 0);
+       input_report_rel(dev, REL_X, dx);
+       input_report_rel(dev, REL_Y, dy);
+       input_sync(dev);
 }
 
-static void
-vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse)
+static void vsxxxaa_handle_ABS_packet(struct vsxxxaa *mouse)
 {
        struct input_dev *dev = mouse->dev;
        unsigned char *buf = mouse->buf;
@@ -296,32 +290,31 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse)
        /*
         * Get button state. It's bits <4..1> of byte 0.
         */
-       left    = (buf[0] & 0x02)? 1: 0;
-       middle  = (buf[0] & 0x04)? 1: 0;
-       right   = (buf[0] & 0x08)? 1: 0;
-       touch   = (buf[0] & 0x10)? 1: 0;
+       left    = buf[0] & 0x02;
+       middle  = buf[0] & 0x04;
+       right   = buf[0] & 0x08;
+       touch   = buf[0] & 0x10;
 
-       vsxxxaa_drop_bytes (mouse, 5);
+       vsxxxaa_drop_bytes(mouse, 5);
 
-       DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n",
-                       mouse->name, mouse->phys, x, y,
-                       left? "L": "l", middle? "M": "m",
-                       right? "R": "r", touch? "T": "t");
+       DBG(KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n",
+           mouse->name, mouse->phys, x, y,
+           left ? "L" : "l", middle ? "M" : "m",
+           right ? "R" : "r", touch ? "T" : "t");
 
        /*
         * Report what we've found so far...
         */
-       input_report_key (dev, BTN_LEFT, left);
-       input_report_key (dev, BTN_MIDDLE, middle);
-       input_report_key (dev, BTN_RIGHT, right);
-       input_report_key (dev, BTN_TOUCH, touch);
-       input_report_abs (dev, ABS_X, x);
-       input_report_abs (dev, ABS_Y, y);
-       input_sync (dev);
+       input_report_key(dev, BTN_LEFT, left);
+       input_report_key(dev, BTN_MIDDLE, middle);
+       input_report_key(dev, BTN_RIGHT, right);
+       input_report_key(dev, BTN_TOUCH, touch);
+       input_report_abs(dev, ABS_X, x);
+       input_report_abs(dev, ABS_Y, y);
+       input_sync(dev);
 }
 
-static void
-vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
+static void vsxxxaa_handle_POR_packet(struct vsxxxaa *mouse)
 {
        struct input_dev *dev = mouse->dev;
        unsigned char *buf = mouse->buf;
@@ -356,24 +349,24 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
         * (for three buttons) of byte 0. Maybe even the bit <3>
         * has some meaning if a tablet is attached.
         */
-       left    = (buf[0] & 0x04)? 1: 0;
-       middle  = (buf[0] & 0x02)? 1: 0;
-       right   = (buf[0] & 0x01)? 1: 0;
+       left    = buf[0] & 0x04;
+       middle  = buf[0] & 0x02;
+       right   = buf[0] & 0x01;
 
-       vsxxxaa_drop_bytes (mouse, 4);
-       vsxxxaa_detection_done (mouse);
+       vsxxxaa_drop_bytes(mouse, 4);
+       vsxxxaa_detection_done(mouse);
 
        if (error <= 0x1f) {
                /* No (serious) error. Report buttons */
-               input_report_key (dev, BTN_LEFT, left);
-               input_report_key (dev, BTN_MIDDLE, middle);
-               input_report_key (dev, BTN_RIGHT, right);
-               input_report_key (dev, BTN_TOUCH, 0);
-               input_sync (dev);
+               input_report_key(dev, BTN_LEFT, left);
+               input_report_key(dev, BTN_MIDDLE, middle);
+               input_report_key(dev, BTN_RIGHT, right);
+               input_report_key(dev, BTN_TOUCH, 0);
+               input_sync(dev);
 
                if (error != 0)
-                       printk (KERN_INFO "Your %s on %s reports error=0x%02x\n",
-                                       mouse->name, mouse->phys, error);
+                       printk(KERN_INFO "Your %s on %s reports error=0x%02x\n",
+                               mouse->name, mouse->phys, error);
 
        }
 
@@ -381,18 +374,18 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
         * If the mouse was hot-plugged, we need to force differential mode
         * now... However, give it a second to recover from it's reset.
         */
-       printk (KERN_NOTICE "%s on %s: Forceing standard packet format, "
-                       "incremental streaming mode and 72 samples/sec\n",
-                       mouse->name, mouse->phys);
-       serio_write (mouse->serio, 'S');        /* Standard format */
-       mdelay (50);
-       serio_write (mouse->serio, 'R');        /* Incremental */
-       mdelay (50);
-       serio_write (mouse->serio, 'L');        /* 72 samples/sec */
+       printk(KERN_NOTICE
+               "%s on %s: Forcing standard packet format, "
+               "incremental streaming mode and 72 samples/sec\n",
+               mouse->name, mouse->phys);
+       serio_write(mouse->serio, 'S'); /* Standard format */
+       mdelay(50);
+       serio_write(mouse->serio, 'R'); /* Incremental */
+       mdelay(50);
+       serio_write(mouse->serio, 'L'); /* 72 samples/sec */
 }
 
-static void
-vsxxxaa_parse_buffer (struct vsxxxaa *mouse)
+static void vsxxxaa_parse_buffer(struct vsxxxaa *mouse)
 {
        unsigned char *buf = mouse->buf;
        int stray_bytes;
@@ -409,122 +402,107 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse)
                 * activity on the mouse.
                 */
                while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) {
-                       printk (KERN_ERR "%s on %s: Dropping a byte to regain "
-                                       "sync with mouse data stream...\n",
-                                       mouse->name, mouse->phys);
-                       vsxxxaa_drop_bytes (mouse, 1);
+                       printk(KERN_ERR "%s on %s: Dropping a byte to regain "
+                               "sync with mouse data stream...\n",
+                               mouse->name, mouse->phys);
+                       vsxxxaa_drop_bytes(mouse, 1);
                }
 
                /*
                 * Check for packets we know about.
                 */
 
-               if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) {
+               if (vsxxxaa_smells_like_packet(mouse, VSXXXAA_PACKET_REL, 3)) {
                        /* Check for broken packet */
-                       stray_bytes = vsxxxaa_check_packet (mouse, 3);
-                       if (stray_bytes > 0) {
-                               printk (KERN_ERR "Dropping %d bytes now...\n",
-                                               stray_bytes);
-                               vsxxxaa_drop_bytes (mouse, stray_bytes);
-                               continue;
-                       }
-
-                       vsxxxaa_handle_REL_packet (mouse);
-                       continue; /* More to parse? */
-               }
+                       stray_bytes = vsxxxaa_check_packet(mouse, 3);
+                       if (!stray_bytes)
+                               vsxxxaa_handle_REL_packet(mouse);
 
-               if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) {
+               } else if (vsxxxaa_smells_like_packet(mouse,
+                                                     VSXXXAA_PACKET_ABS, 5)) {
                        /* Check for broken packet */
-                       stray_bytes = vsxxxaa_check_packet (mouse, 5);
-                       if (stray_bytes > 0) {
-                               printk (KERN_ERR "Dropping %d bytes now...\n",
-                                               stray_bytes);
-                               vsxxxaa_drop_bytes (mouse, stray_bytes);
-                               continue;
-                       }
-
-                       vsxxxaa_handle_ABS_packet (mouse);
-                       continue; /* More to parse? */
-               }
+                       stray_bytes = vsxxxaa_check_packet(mouse, 5);
+                       if (!stray_bytes)
+                               vsxxxaa_handle_ABS_packet(mouse);
 
-               if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) {
+               } else if (vsxxxaa_smells_like_packet(mouse,
+                                                     VSXXXAA_PACKET_POR, 4)) {
                        /* Check for broken packet */
-                       stray_bytes = vsxxxaa_check_packet (mouse, 4);
-                       if (stray_bytes > 0) {
-                               printk (KERN_ERR "Dropping %d bytes now...\n",
-                                               stray_bytes);
-                               vsxxxaa_drop_bytes (mouse, stray_bytes);
-                               continue;
-                       }
-
-                       vsxxxaa_handle_POR_packet (mouse);
-                       continue; /* More to parse? */
+                       stray_bytes = vsxxxaa_check_packet(mouse, 4);
+                       if (!stray_bytes)
+                               vsxxxaa_handle_POR_packet(mouse);
+
+               } else {
+                       break; /* No REL, ABS or POR packet found */
+               }
+
+               if (stray_bytes > 0) {
+                       printk(KERN_ERR "Dropping %d bytes now...\n",
+                               stray_bytes);
+                       vsxxxaa_drop_bytes(mouse, stray_bytes);
                }
 
-               break; /* No REL, ABS or POR packet found */
        } while (1);
 }
 
-static irqreturn_t
-vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags)
+static irqreturn_t vsxxxaa_interrupt(struct serio *serio,
+                                    unsigned char data, unsigned int flags)
 {
-       struct vsxxxaa *mouse = serio_get_drvdata (serio);
+       struct vsxxxaa *mouse = serio_get_drvdata(serio);
 
-       vsxxxaa_queue_byte (mouse, data);
-       vsxxxaa_parse_buffer (mouse);
+       vsxxxaa_queue_byte(mouse, data);
+       vsxxxaa_parse_buffer(mouse);
 
        return IRQ_HANDLED;
 }
 
-static void
-vsxxxaa_disconnect (struct serio *serio)
+static void vsxxxaa_disconnect(struct serio *serio)
 {
-       struct vsxxxaa *mouse = serio_get_drvdata (serio);
+       struct vsxxxaa *mouse = serio_get_drvdata(serio);
 
-       serio_close (serio);
-       serio_set_drvdata (serio, NULL);
-       input_unregister_device (mouse->dev);
-       kfree (mouse);
+       serio_close(serio);
+       serio_set_drvdata(serio, NULL);
+       input_unregister_device(mouse->dev);
+       kfree(mouse);
 }
 
-static int
-vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
+static int vsxxxaa_connect(struct serio *serio, struct serio_driver *drv)
 {
        struct vsxxxaa *mouse;
        struct input_dev *input_dev;
        int err = -ENOMEM;
 
-       mouse = kzalloc (sizeof (struct vsxxxaa), GFP_KERNEL);
-       input_dev = input_allocate_device ();
+       mouse = kzalloc(sizeof(struct vsxxxaa), GFP_KERNEL);
+       input_dev = input_allocate_device();
        if (!mouse || !input_dev)
                goto fail1;
 
        mouse->dev = input_dev;
        mouse->serio = serio;
-       strlcat (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer",
-                sizeof (mouse->name));
-       snprintf (mouse->phys, sizeof (mouse->phys), "%s/input0", serio->phys);
+       strlcat(mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer",
+                sizeof(mouse->name));
+       snprintf(mouse->phys, sizeof(mouse->phys), "%s/input0", serio->phys);
 
        input_dev->name = mouse->name;
        input_dev->phys = mouse->phys;
        input_dev->id.bustype = BUS_RS232;
        input_dev->dev.parent = &serio->dev;
 
-       set_bit (EV_KEY, input_dev->evbit);             /* We have buttons */
-       set_bit (EV_REL, input_dev->evbit);
-       set_bit (EV_ABS, input_dev->evbit);
-       set_bit (BTN_LEFT, input_dev->keybit);          /* We have 3 buttons */
-       set_bit (BTN_MIDDLE, input_dev->keybit);
-       set_bit (BTN_RIGHT, input_dev->keybit);
-       set_bit (BTN_TOUCH, input_dev->keybit);         /* ...and Tablet */
-       set_bit (REL_X, input_dev->relbit);
-       set_bit (REL_Y, input_dev->relbit);
-       input_set_abs_params (input_dev, ABS_X, 0, 1023, 0, 0);
-       input_set_abs_params (input_dev, ABS_Y, 0, 1023, 0, 0);
-
-       serio_set_drvdata (serio, mouse);
-
-       err = serio_open (serio, drv);
+       __set_bit(EV_KEY, input_dev->evbit);            /* We have buttons */
+       __set_bit(EV_REL, input_dev->evbit);
+       __set_bit(EV_ABS, input_dev->evbit);
+       __set_bit(BTN_LEFT, input_dev->keybit);         /* We have 3 buttons */
+       __set_bit(BTN_MIDDLE, input_dev->keybit);
+       __set_bit(BTN_RIGHT, input_dev->keybit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);        /* ...and Tablet */
+       __set_bit(REL_X, input_dev->relbit);
+       __set_bit(REL_Y, input_dev->relbit);
+       input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
+
+       serio_set_drvdata(serio, mouse);
+
+       err = serio_open(serio, drv);
        if (err)
                goto fail2;
 
@@ -532,18 +510,18 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
         * Request selftest. Standard packet format and differential
         * mode will be requested after the device ID'ed successfully.
         */
-       serio_write (serio, 'T'); /* Test */
+       serio_write(serio, 'T'); /* Test */
 
-       err = input_register_device (input_dev);
+       err = input_register_device(input_dev);
        if (err)
                goto fail3;
 
        return 0;
 
- fail3:        serio_close (serio);
- fail2:        serio_set_drvdata (serio, NULL);
- fail1:        input_free_device (input_dev);
-       kfree (mouse);
+ fail3:        serio_close(serio);
+ fail2:        serio_set_drvdata(serio, NULL);
+ fail1:        input_free_device(input_dev);
+       kfree(mouse);
        return err;
 }
 
@@ -570,18 +548,16 @@ static struct serio_driver vsxxxaa_drv = {
        .disconnect     = vsxxxaa_disconnect,
 };
 
-static int __init
-vsxxxaa_init (void)
+static int __init vsxxxaa_init(void)
 {
        return serio_register_driver(&vsxxxaa_drv);
 }
 
-static void __exit
-vsxxxaa_exit (void)
+static void __exit vsxxxaa_exit(void)
 {
        serio_unregister_driver(&vsxxxaa_drv);
 }
 
-module_init (vsxxxaa_init);
-module_exit (vsxxxaa_exit);
+module_init(vsxxxaa_init);
+module_exit(vsxxxaa_exit);
 
index aa533ce..7e319d6 100644 (file)
@@ -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
index 9b6c813..bf945f7 100644 (file)
@@ -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 (file)
index 0000000..f479ea5
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Altera University Program PS2 controller driver
+ *
+ * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * Based on sa1111ps2.c, which is:
+ * Copyright (C) 2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_NAME "altera_ps2"
+
+struct ps2if {
+       struct serio *io;
+       struct resource *iomem_res;
+       void __iomem *base;
+       unsigned irq;
+};
+
+/*
+ * Read all bytes waiting in the PS2 port.  There should be
+ * at the most one, but we loop for safety.
+ */
+static irqreturn_t altera_ps2_rxint(int irq, void *dev_id)
+{
+       struct ps2if *ps2if = dev_id;
+       unsigned int status;
+       int handled = IRQ_NONE;
+
+       while ((status = readl(ps2if->base)) & 0xffff0000) {
+               serio_interrupt(ps2if->io, status & 0xff, 0);
+               handled = IRQ_HANDLED;
+       }
+
+       return handled;
+}
+
+/*
+ * Write a byte to the PS2 port.
+ */
+static int altera_ps2_write(struct serio *io, unsigned char val)
+{
+       struct ps2if *ps2if = io->port_data;
+
+       writel(val, ps2if->base);
+       return 0;
+}
+
+static int altera_ps2_open(struct serio *io)
+{
+       struct ps2if *ps2if = io->port_data;
+
+       /* clear fifo */
+       while (readl(ps2if->base) & 0xffff0000)
+               /* empty */;
+
+       writel(1, ps2if->base + 4); /* enable rx irq */
+       return 0;
+}
+
+static void altera_ps2_close(struct serio *io)
+{
+       struct ps2if *ps2if = io->port_data;
+
+       writel(0, ps2if->base); /* disable rx irq */
+}
+
+/*
+ * Add one device to this driver.
+ */
+static int 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 <thomas@wytron.com.tw>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 2bcf1ac..7fbffe4 100644 (file)
@@ -67,10 +67,12 @@ static inline void i8042_write_command(int val)
 
 #include <linux/dmi.h>
 
-static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
+static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
        {
-               /* AUX LOOP command does not raise AUX IRQ */
-               .ident = "Arima-Rioworks HDAMB",
+               /*
+                * Arima-Rioworks HDAMB -
+                * AUX LOOP command does not raise AUX IRQ
+                */
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"),
                        DMI_MATCH(DMI_BOARD_NAME, "HDAMB"),
@@ -78,7 +80,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               .ident = "ASUS G1S",
+               /* ASUS G1S */
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
                        DMI_MATCH(DMI_BOARD_NAME, "G1S"),
@@ -86,8 +88,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               /* AUX LOOP command does not raise AUX IRQ */
-               .ident = "ASUS P65UP5",
+               /* ASUS P65UP5 - AUX LOOP command does not raise AUX IRQ */
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
                        DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"),
@@ -95,7 +96,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               .ident = "Compaq Proliant 8500",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
                        DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
@@ -103,7 +103,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               .ident = "Compaq Proliant DL760",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
                        DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
@@ -111,7 +110,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               .ident = "OQO Model 01",
+               /* OQO Model 01 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
@@ -119,8 +118,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               /* AUX LOOP does not work properly */
-               .ident = "ULI EV4873",
+               /* ULI EV4873 - AUX LOOP does not work properly */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ULI"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"),
@@ -128,7 +126,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               .ident = "Microsoft Virtual Machine",
+               /* Microsoft Virtual Machine */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
@@ -136,7 +134,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               .ident = "Medion MAM 2070",
+               /* Medion MAM 2070 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"),
@@ -144,7 +142,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               .ident = "Blue FB5601",
+               /* Blue FB5601 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "blue"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"),
@@ -152,7 +150,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                },
        },
        {
-               .ident = "Gigabyte M912",
+               /* Gigabyte M912 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "M912"),
@@ -160,7 +158,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"),
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
new file mode 100644 (file)
index 0000000..fbd3987
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Generic support for sparse keymaps
+ *
+ * Copyright (c) 2009 Dmitry Torokhov
+ *
+ * Derived from wistron button driver:
+ * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
+ * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
+ * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION("Generic support for sparse keymaps");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1");
+
+/**
+ * sparse_keymap_entry_from_scancode - perform sparse keymap lookup
+ * @dev: Input device using sparse keymap
+ * @code: Scan code
+ *
+ * This function is used to perform &struct key_entry lookup in an
+ * input device using sparse keymap.
+ */
+struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
+                                                   unsigned int code)
+{
+       struct key_entry *key;
+
+       for (key = dev->keycode; key->type != KE_END; key++)
+               if (code == key->code)
+                       return key;
+
+       return NULL;
+}
+EXPORT_SYMBOL(sparse_keymap_entry_from_scancode);
+
+/**
+ * sparse_keymap_entry_from_keycode - perform sparse keymap lookup
+ * @dev: Input device using sparse keymap
+ * @keycode: Key code
+ *
+ * This function is used to perform &struct key_entry lookup in an
+ * input device using sparse keymap.
+ */
+struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
+                                                  unsigned int keycode)
+{
+       struct key_entry *key;
+
+       for (key = dev->keycode; key->type != KE_END; key++)
+               if (key->type == KE_KEY && keycode == key->keycode)
+                       return key;
+
+       return NULL;
+}
+EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
+
+static int sparse_keymap_getkeycode(struct input_dev *dev,
+                                   int scancode, int *keycode)
+{
+       const struct key_entry *key =
+                       sparse_keymap_entry_from_scancode(dev, scancode);
+
+       if (key && key->type == KE_KEY) {
+               *keycode = key->keycode;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int sparse_keymap_setkeycode(struct input_dev *dev,
+                                   int scancode, int keycode)
+{
+       struct key_entry *key;
+       int old_keycode;
+
+       if (keycode < 0 || keycode > KEY_MAX)
+               return -EINVAL;
+
+       key = sparse_keymap_entry_from_scancode(dev, scancode);
+       if (key && key->type == KE_KEY) {
+               old_keycode = key->keycode;
+               key->keycode = keycode;
+               set_bit(keycode, dev->keybit);
+               if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
+                       clear_bit(old_keycode, dev->keybit);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * sparse_keymap_setup - set up sparse keymap for an input device
+ * @dev: Input device
+ * @keymap: Keymap in form of array of &key_entry structures ending
+ *     with %KE_END type entry
+ * @setup: Function that can be used to adjust keymap entries
+ *     depending on device's deeds, may be %NULL
+ *
+ * The function calculates size and allocates copy of the original
+ * keymap after which sets up input device event bits appropriately.
+ * Before destroying input device allocated keymap should be freed
+ * with a call to sparse_keymap_free().
+ */
+int sparse_keymap_setup(struct input_dev *dev,
+                       const struct key_entry *keymap,
+                       int (*setup)(struct input_dev *, struct key_entry *))
+{
+       size_t map_size = 1; /* to account for the last KE_END entry */
+       const struct key_entry *e;
+       struct key_entry *map, *entry;
+       int i;
+       int error;
+
+       for (e = keymap; e->type != KE_END; e++)
+               map_size++;
+
+       map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL);
+       if (!map)
+               return -ENOMEM;
+
+       memcpy(map, keymap, map_size * sizeof (struct key_entry));
+
+       for (i = 0; i < map_size; i++) {
+               entry = &map[i];
+
+               if (setup) {
+                       error = setup(dev, entry);
+                       if (error)
+                               goto err_out;
+               }
+
+               switch (entry->type) {
+               case KE_KEY:
+                       __set_bit(EV_KEY, dev->evbit);
+                       __set_bit(entry->keycode, dev->keybit);
+                       break;
+
+               case KE_SW:
+                       __set_bit(EV_SW, dev->evbit);
+                       __set_bit(entry->sw.code, dev->swbit);
+                       break;
+               }
+       }
+
+       dev->keycode = map;
+       dev->keycodemax = map_size;
+       dev->getkeycode = sparse_keymap_getkeycode;
+       dev->setkeycode = sparse_keymap_setkeycode;
+
+       return 0;
+
+ err_out:
+       kfree(keymap);
+       return error;
+
+}
+EXPORT_SYMBOL(sparse_keymap_setup);
+
+/**
+ * sparse_keymap_free - free memory allocated for sparse keymap
+ * @dev: Input device using sparse keymap
+ *
+ * This function is used to free memory allocated by sparse keymap
+ * in an input device that was set up by sparse_keymap_setup().
+ */
+void sparse_keymap_free(struct input_dev *dev)
+{
+       kfree(dev->keycode);
+       dev->keycode = NULL;
+       dev->keycodemax = 0;
+       dev->getkeycode = NULL;
+       dev->setkeycode = NULL;
+}
+EXPORT_SYMBOL(sparse_keymap_free);
+
+/**
+ * sparse_keymap_report_entry - report event corresponding to given key entry
+ * @dev: Input device for which event should be reported
+ * @ke: key entry describing event
+ * @value: Value that should be reported (ignored by %KE_SW entries)
+ * @autorelease: Signals whether release event should be emitted for %KE_KEY
+ *     entries right after reporting press event, ignored by all other
+ *     entries
+ *
+ * This function is used to report input event described by given
+ * &struct key_entry.
+ */
+void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke,
+                               unsigned int value, bool autorelease)
+{
+       switch (ke->type) {
+       case KE_KEY:
+               input_report_key(dev, ke->keycode, value);
+               input_sync(dev);
+               if (value && autorelease) {
+                       input_report_key(dev, ke->keycode, 0);
+                       input_sync(dev);
+               }
+               break;
+
+       case KE_SW:
+               value = ke->sw.value;
+               /* fall through */
+
+       case KE_VSW:
+               input_report_switch(dev, ke->sw.code, value);
+               break;
+       }
+}
+EXPORT_SYMBOL(sparse_keymap_report_entry);
+
+/**
+ * sparse_keymap_report_event - report event corresponding to given scancode
+ * @dev: Input device using sparse keymap
+ * @code: Scan code
+ * @value: Value that should be reported (ignored by %KE_SW entries)
+ * @autorelease: Signals whether release event should be emitted for %KE_KEY
+ *     entries right after reporting press event, ignored by all other
+ *     entries
+ *
+ * This function is used to perform lookup in an input device using sparse
+ * keymap and report corresponding event. Returns %true if lookup was
+ * successful and %false otherwise.
+ */
+bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code,
+                               unsigned int value, bool autorelease)
+{
+       const struct key_entry *ke =
+               sparse_keymap_entry_from_scancode(dev, code);
+
+       if (ke) {
+               sparse_keymap_report_entry(dev, ke, value, autorelease);
+               return true;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL(sparse_keymap_report_event);
+
index 8cc453c..32fc8ba 100644 (file)
@@ -111,6 +111,18 @@ config TOUCHSCREEN_DA9034
          Say Y here to enable the support for the touchscreen found
          on Dialog Semiconductor DA9034 PMIC.
 
+config TOUCHSCREEN_DYNAPRO
+       tristate "Dynapro serial touchscreen"
+       select SERIO
+       help
+         Say Y here if you have a Dynapro serial touchscreen connected to
+         your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called dynapro.
+
 config TOUCHSCREEN_EETI
        tristate "EETI touchscreen panel support"
        depends on I2C
@@ -133,6 +145,18 @@ config TOUCHSCREEN_FUJITSU
          To compile this driver as a module, choose M here: the
          module will be called fujitsu-ts.
 
+config TOUCHSCREEN_S3C2410
+       tristate "Samsung S3C2410 touchscreen input driver"
+       depends on ARCH_S3C2410
+       select S3C24XX_ADC
+       help
+         Say Y here if you have the s3c2410 touchscreen.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called s3c2410_ts.
+
 config TOUCHSCREEN_GUNZE
        tristate "Gunze AHL-51S touchscreen"
        select SERIO
@@ -297,7 +321,7 @@ config TOUCHSCREEN_TOUCHWIN
 
 config TOUCHSCREEN_ATMEL_TSADCC
        tristate "Atmel Touchscreen Interface"
-       depends on ARCH_AT91SAM9RL
+       depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
        help
          Say Y here if you have a 4-wire touchscreen connected to the
           ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
@@ -418,6 +442,7 @@ config TOUCHSCREEN_USB_COMPOSITE
          - IdealTEK URTC1000
          - GoTop Super_Q2/GogoPen/PenPower tablets
          - JASTEC USB Touch Controller/DigiTech DTR-02U
+         - Zytronic controllers
 
          Have a look at <http://linux.chapter7.ch/touchkit/> for
          a usage description and the required user-space stuff.
@@ -490,6 +515,16 @@ config TOUCHSCREEN_USB_E2I
        bool "e2i Touchscreen controller (e.g. from Mimo 740)"
        depends on TOUCHSCREEN_USB_COMPOSITE
 
+config TOUCHSCREEN_USB_ZYTRONIC
+       default y
+       bool "Zytronic controller" if EMBEDDED
+       depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ETT_TC5UH
+       default y
+       bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
+       depends on TOUCHSCREEN_USB_COMPOSITE
+
 config TOUCHSCREEN_TOUCHIT213
        tristate "Sahara TouchIT-213 touchscreen"
        select SERIO
index 15fa62c..f1f59c9 100644 (file)
@@ -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
@@ -25,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
@@ -41,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
index 09c8109..52d2ca1 100644 (file)
 #include <linux/spi/ads7846.h>
 #include <asm/irq.h>
 
-
 /*
  * This code has been heavily tested on a Nokia 770, and lightly
- * tested on other ads7846 devices (OSK/Mistral, Lubbock).
+ * tested on other ads7846 devices (OSK/Mistral, Lubbock, Spitz).
  * TSC2046 is just newer ads7846 silicon.
  * Support for ads7843 tested on Atmel at91sam926x-EK.
  * Support for ads7845 has only been stubbed in.
@@ -43,7 +42,7 @@
  * have to maintain our own SW IRQ disabled status. This should be
  * removed as soon as the affected platform's IRQ handling is fixed.
  *
- * app note sbaa036 talks in more detail about accurate sampling...
+ * App note sbaa036 talks in more detail about accurate sampling...
  * that ought to help in situations like LCDs inducing noise (which
  * can also be helped by using synch signals) and more generally.
  * This driver tries to utilize the measures described in the app
@@ -566,10 +565,8 @@ static void ads7846_rx(void *ads)
         * once more the measurement
         */
        if (packet->tc.ignore || Rt > ts->pressure_max) {
-#ifdef VERBOSE
-               pr_debug("%s: ignored %d pressure %d\n",
-                       dev_name(&ts->spi->dev), packet->tc.ignore, Rt);
-#endif
+               dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
+                        packet->tc.ignore, Rt);
                hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
                              HRTIMER_MODE_REL);
                return;
@@ -598,9 +595,7 @@ static void ads7846_rx(void *ads)
                if (!ts->pendown) {
                        input_report_key(input, BTN_TOUCH, 1);
                        ts->pendown = 1;
-#ifdef VERBOSE
-                       dev_dbg(&ts->spi->dev, "DOWN\n");
-#endif
+                       dev_vdbg(&ts->spi->dev, "DOWN\n");
                }
 
                if (ts->swap_xy)
@@ -608,12 +603,10 @@ static void ads7846_rx(void *ads)
 
                input_report_abs(input, ABS_X, x);
                input_report_abs(input, ABS_Y, y);
-               input_report_abs(input, ABS_PRESSURE, Rt);
+               input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt);
 
                input_sync(input);
-#ifdef VERBOSE
-               dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
-#endif
+               dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
        }
 
        hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
@@ -723,9 +716,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
                        input_sync(input);
 
                        ts->pendown = 0;
-#ifdef VERBOSE
-                       dev_dbg(&ts->spi->dev, "UP\n");
-#endif
+                       dev_vdbg(&ts->spi->dev, "UP\n");
                }
 
                /* measurement cycle ended */
index 9c7fce4..3d9b516 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <mach/board.h>
+#include <mach/cpu.h>
 
 /* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
 
@@ -36,7 +38,9 @@
 #define          ATMEL_TSADCC_LOWRES   (1    <<  4)    /* Resolution selection */
 #define          ATMEL_TSADCC_SLEEP    (1    <<  5)    /* Sleep mode */
 #define          ATMEL_TSADCC_PENDET   (1    <<  6)    /* Pen Detect selection */
+#define          ATMEL_TSADCC_PRES     (1    <<  7)    /* Pressure Measurement Selection */
 #define          ATMEL_TSADCC_PRESCAL  (0x3f <<  8)    /* Prescalar Rate Selection */
+#define          ATMEL_TSADCC_EPRESCAL (0xff <<  8)    /* Prescalar Rate Selection (Extended) */
 #define          ATMEL_TSADCC_STARTUP  (0x7f << 16)    /* Start Up time */
 #define          ATMEL_TSADCC_SHTIM    (0xf  << 24)    /* Sample & Hold time */
 #define          ATMEL_TSADCC_PENDBC   (0xf  << 28)    /* Pen Detect debouncing time */
 #define ATMEL_TSADCC_CDR4      0x40    /* Channel Data 4 */
 #define ATMEL_TSADCC_CDR5      0x44    /* Channel Data 5 */
 
-#define ADC_CLOCK      1000000
+#define ATMEL_TSADCC_XPOS      0x50
+#define ATMEL_TSADCC_Z1DAT     0x54
+#define ATMEL_TSADCC_Z2DAT     0x58
+
+#define PRESCALER_VAL(x)       ((x) >> 8)
+
+#define ADC_DEFAULT_CLOCK      100000
 
 struct atmel_tsadcc {
        struct input_dev        *input;
@@ -172,6 +182,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
        struct atmel_tsadcc     *ts_dev;
        struct input_dev        *input_dev;
        struct resource         *res;
+       struct at91_tsadcc_data *pdata = pdev->dev.platform_data;
        int             err = 0;
        unsigned int    prsc;
        unsigned int    reg;
@@ -242,31 +253,49 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
        input_dev->phys = ts_dev->phys;
        input_dev->dev.parent = &pdev->dev;
 
-       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
+       __set_bit(EV_ABS, input_dev->evbit);
        input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0);
        input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0);
 
+       input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
+
        /* clk_enable() always returns 0, no need to check it */
        clk_enable(ts_dev->clk);
 
        prsc = clk_get_rate(ts_dev->clk);
        dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);
 
-       prsc = prsc / ADC_CLOCK / 2 - 1;
+       if (!pdata)
+               goto err_fail;
+
+       if (!pdata->adc_clock)
+               pdata->adc_clock = ADC_DEFAULT_CLOCK;
+
+       prsc = (prsc / (2 * pdata->adc_clock)) - 1;
+
+       /* saturate if this value is too high */
+       if (cpu_is_at91sam9rl()) {
+               if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL))
+                       prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL);
+       } else {
+               if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL))
+                       prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL);
+       }
+
+       dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
 
        reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE          |
                ((0x00 << 5) & ATMEL_TSADCC_SLEEP)      |       /* Normal Mode */
                ((0x01 << 6) & ATMEL_TSADCC_PENDET)     |       /* Enable Pen Detect */
-               ((prsc << 8) & ATMEL_TSADCC_PRESCAL)    |       /* PRESCAL */
-               ((0x13 << 16) & ATMEL_TSADCC_STARTUP)   |       /* STARTUP */
-               ((0x0F << 28) & ATMEL_TSADCC_PENDBC);           /* PENDBC */
+               (prsc << 8)                             |
+               ((0x26 << 16) & ATMEL_TSADCC_STARTUP)   |
+               ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
 
        atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST);
        atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
        atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
-       atmel_tsadcc_write(ATMEL_TSADCC_TSR, (0x3 << 24) & ATMEL_TSADCC_TSSHTIM);
+       atmel_tsadcc_write(ATMEL_TSADCC_TSR,
+               (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
 
        atmel_tsadcc_read(ATMEL_TSADCC_SR);
        atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
new file mode 100644 (file)
index 0000000..4553539
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Dynapro serial touchscreen driver
+ *
+ * Copyright (c) 2009 Tias Guns
+ * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
+ * Richard Lemon
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * 2009/09/19 Tias Guns <tias@ulyssis.org>
+ *   Copied inexio.c and edited for Dynapro protocol (from retired Xorg module)
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC    "Dynapro serial touchscreen driver"
+
+MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define DYNAPRO_FORMAT_TOUCH_BIT 0x40
+#define DYNAPRO_FORMAT_LENGTH 3
+#define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80
+
+#define DYNAPRO_MIN_XC 0
+#define DYNAPRO_MAX_XC 0x3ff
+#define DYNAPRO_MIN_YC 0
+#define DYNAPRO_MAX_YC 0x3ff
+
+#define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4))
+#define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7))
+#define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0])
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct dynapro {
+       struct input_dev *dev;
+       struct serio *serio;
+       int idx;
+       unsigned char data[DYNAPRO_FORMAT_LENGTH];
+       char phys[32];
+};
+
+static void dynapro_process_data(struct dynapro *pdynapro)
+{
+       struct input_dev *dev = pdynapro->dev;
+
+       if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) {
+               input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data));
+               input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data));
+               input_report_key(dev, BTN_TOUCH,
+                                DYNAPRO_GET_TOUCHED(pdynapro->data));
+               input_sync(dev);
+
+               pdynapro->idx = 0;
+       }
+}
+
+static irqreturn_t dynapro_interrupt(struct serio *serio,
+               unsigned char data, unsigned int flags)
+{
+       struct dynapro *pdynapro = serio_get_drvdata(serio);
+
+       pdynapro->data[pdynapro->idx] = data;
+
+       if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0])
+               dynapro_process_data(pdynapro);
+       else
+               dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
+                       pdynapro->data[0]);
+
+       return IRQ_HANDLED;
+}
+
+static void dynapro_disconnect(struct serio *serio)
+{
+       struct dynapro *pdynapro = serio_get_drvdata(serio);
+
+       input_get_device(pdynapro->dev);
+       input_unregister_device(pdynapro->dev);
+       serio_close(serio);
+       serio_set_drvdata(serio, NULL);
+       input_put_device(pdynapro->dev);
+       kfree(pdynapro);
+}
+
+/*
+ * dynapro_connect() is the routine that is called when someone adds a
+ * new serio device that supports dynapro protocol and registers it as
+ * an input device. This is usually accomplished using inputattach.
+ */
+
+static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
+{
+       struct dynapro *pdynapro;
+       struct input_dev *input_dev;
+       int err;
+
+       pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!pdynapro || !input_dev) {
+               err = -ENOMEM;
+               goto fail1;
+       }
+
+       pdynapro->serio = serio;
+       pdynapro->dev = input_dev;
+       snprintf(pdynapro->phys, sizeof(pdynapro->phys),
+                "%s/input0", serio->phys);
+
+       input_dev->name = "Dynapro Serial TouchScreen";
+       input_dev->phys = pdynapro->phys;
+       input_dev->id.bustype = BUS_RS232;
+       input_dev->id.vendor = SERIO_DYNAPRO;
+       input_dev->id.product = 0;
+       input_dev->id.version = 0x0001;
+       input_dev->dev.parent = &serio->dev;
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       input_set_abs_params(pdynapro->dev, ABS_X,
+                            DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0);
+       input_set_abs_params(pdynapro->dev, ABS_Y,
+                            DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0);
+
+       serio_set_drvdata(serio, pdynapro);
+
+       err = serio_open(serio, drv);
+       if (err)
+               goto fail2;
+
+       err = input_register_device(pdynapro->dev);
+       if (err)
+               goto fail3;
+
+       return 0;
+
+ fail3:        serio_close(serio);
+ fail2:        serio_set_drvdata(serio, NULL);
+ fail1:        input_free_device(input_dev);
+       kfree(pdynapro);
+       return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id dynapro_serio_ids[] = {
+       {
+               .type   = SERIO_RS232,
+               .proto  = SERIO_DYNAPRO,
+               .id     = SERIO_ANY,
+               .extra  = SERIO_ANY,
+       },
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, dynapro_serio_ids);
+
+static struct serio_driver dynapro_drv = {
+       .driver         = {
+               .name   = "dynapro",
+       },
+       .description    = DRIVER_DESC,
+       .id_table       = dynapro_serio_ids,
+       .interrupt      = dynapro_interrupt,
+       .connect        = dynapro_connect,
+       .disconnect     = dynapro_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init dynapro_init(void)
+{
+       return serio_register_driver(&dynapro_drv);
+}
+
+static void __exit dynapro_exit(void)
+{
+       serio_unregister_driver(&dynapro_drv);
+}
+
+module_init(dynapro_init);
+module_exit(dynapro_exit);
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
new file mode 100644 (file)
index 0000000..6386b44
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * Samsung S3C24XX touchscreen driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the term of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
+ * Copyright 2008 Ben Dooks <ben-linux@fluff.org>
+ * Copyright 2009 Simtec Electronics <linux@simtec.co.uk>
+ *
+ * Additional work by Herbert Pƶtzl <herbert@13thfloor.at> and
+ * Harald Welte <laforge@openmoko.org>
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/adc.h>
+#include <plat/regs-adc.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/ts.h>
+
+#define TSC_SLEEP  (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
+
+#define INT_DOWN       (0)
+#define INT_UP         (1 << 8)
+
+#define WAIT4INT       (S3C2410_ADCTSC_YM_SEN | \
+                        S3C2410_ADCTSC_YP_SEN | \
+                        S3C2410_ADCTSC_XP_SEN | \
+                        S3C2410_ADCTSC_XY_PST(3))
+
+#define AUTOPST                (S3C2410_ADCTSC_YM_SEN | \
+                        S3C2410_ADCTSC_YP_SEN | \
+                        S3C2410_ADCTSC_XP_SEN | \
+                        S3C2410_ADCTSC_AUTO_PST | \
+                        S3C2410_ADCTSC_XY_PST(0))
+
+/* Per-touchscreen data. */
+
+/**
+ * struct s3c2410ts - driver touchscreen state.
+ * @client: The ADC client we registered with the core driver.
+ * @dev: The device we are bound to.
+ * @input: The input device we registered with the input subsystem.
+ * @clock: The clock for the adc.
+ * @io: Pointer to the IO base.
+ * @xp: The accumulated X position data.
+ * @yp: The accumulated Y position data.
+ * @irq_tc: The interrupt number for pen up/down interrupt
+ * @count: The number of samples collected.
+ * @shift: The log2 of the maximum count to read in one go.
+ */
+struct s3c2410ts {
+       struct s3c_adc_client *client;
+       struct device *dev;
+       struct input_dev *input;
+       struct clk *clock;
+       void __iomem *io;
+       unsigned long xp;
+       unsigned long yp;
+       int irq_tc;
+       int count;
+       int shift;
+};
+
+static struct s3c2410ts ts;
+
+/**
+ * s3c2410_ts_connect - configure gpio for s3c2410 systems
+ *
+ * Configure the GPIO for the S3C2410 system, where we have external FETs
+ * connected to the device (later systems such as the S3C2440 integrate
+ * these into the device).
+*/
+static inline void s3c2410_ts_connect(void)
+{
+       s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);
+       s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);
+       s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);
+       s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);
+}
+
+/**
+ * get_down - return the down state of the pen
+ * @data0: The data read from ADCDAT0 register.
+ * @data1: The data read from ADCDAT1 register.
+ *
+ * Return non-zero if both readings show that the pen is down.
+ */
+static inline bool get_down(unsigned long data0, unsigned long data1)
+{
+       /* returns true if both data values show stylus down */
+       return (!(data0 & S3C2410_ADCDAT0_UPDOWN) &&
+               !(data1 & S3C2410_ADCDAT0_UPDOWN));
+}
+
+static void touch_timer_fire(unsigned long data)
+{
+       unsigned long data0;
+       unsigned long data1;
+       bool down;
+
+       data0 = readl(ts.io + S3C2410_ADCDAT0);
+       data1 = readl(ts.io + S3C2410_ADCDAT1);
+
+       down = get_down(data0, data1);
+
+       if (ts.count == (1 << ts.shift)) {
+               ts.xp >>= ts.shift;
+               ts.yp >>= ts.shift;
+
+               dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
+                       __func__, ts.xp, ts.yp, ts.count);
+
+               input_report_abs(ts.input, ABS_X, ts.xp);
+               input_report_abs(ts.input, ABS_Y, ts.yp);
+
+               input_report_key(ts.input, BTN_TOUCH, 1);
+               input_sync(ts.input);
+
+               ts.xp = 0;
+               ts.yp = 0;
+               ts.count = 0;
+       }
+
+       if (down) {
+               s3c_adc_start(ts.client, 0, 1 << ts.shift);
+       } else {
+               ts.count = 0;
+
+               input_report_key(ts.input, BTN_TOUCH, 0);
+               input_sync(ts.input);
+
+               writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
+       }
+}
+
+static DEFINE_TIMER(touch_timer, touch_timer_fire, 0, 0);
+
+/**
+ * stylus_irq - touchscreen stylus event interrupt
+ * @irq: The interrupt number
+ * @dev_id: The device ID.
+ *
+ * Called when the IRQ_TC is fired for a pen up or down event.
+ */
+static irqreturn_t stylus_irq(int irq, void *dev_id)
+{
+       unsigned long data0;
+       unsigned long data1;
+       bool down;
+
+       data0 = readl(ts.io + S3C2410_ADCDAT0);
+       data1 = readl(ts.io + S3C2410_ADCDAT1);
+
+       down = get_down(data0, data1);
+
+       /* TODO we should never get an interrupt with down set while
+        * the timer is running, but maybe we ought to verify that the
+        * timer isn't running anyways. */
+
+       if (down)
+               s3c_adc_start(ts.client, 0, 1 << ts.shift);
+       else
+               dev_info(ts.dev, "%s: count=%d\n", __func__, ts.count);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * s3c24xx_ts_conversion - ADC conversion callback
+ * @client: The client that was registered with the ADC core.
+ * @data0: The reading from ADCDAT0.
+ * @data1: The reading from ADCDAT1.
+ * @left: The number of samples left.
+ *
+ * Called when a conversion has finished.
+ */
+static void s3c24xx_ts_conversion(struct s3c_adc_client *client,
+                                 unsigned data0, unsigned data1,
+                                 unsigned *left)
+{
+       dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1);
+
+       ts.xp += data0;
+       ts.yp += data1;
+
+       ts.count++;
+
+       /* From tests, it seems that it is unlikely to get a pen-up
+        * event during the conversion process which means we can
+        * ignore any pen-up events with less than the requisite
+        * count done.
+        *
+        * In several thousand conversions, no pen-ups where detected
+        * before count completed.
+        */
+}
+
+/**
+ * s3c24xx_ts_select - ADC selection callback.
+ * @client: The client that was registered with the ADC core.
+ * @select: The reason for select.
+ *
+ * Called when the ADC core selects (or deslects) us as a client.
+ */
+static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select)
+{
+       if (select) {
+               writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
+                      ts.io + S3C2410_ADCTSC);
+       } else {
+               mod_timer(&touch_timer, jiffies+1);
+               writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC);
+       }
+}
+
+/**
+ * s3c2410ts_probe - device core probe entry point
+ * @pdev: The device we are being bound to.
+ *
+ * Initialise, find and allocate any resources we need to run and then
+ * register with the ADC and input systems.
+ */
+static int __devinit s3c2410ts_probe(struct platform_device *pdev)
+{
+       struct s3c2410_ts_mach_info *info;
+       struct device *dev = &pdev->dev;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int ret = -EINVAL;
+
+       /* Initialise input stuff */
+       memset(&ts, 0, sizeof(struct s3c2410ts));
+
+       ts.dev = dev;
+
+       info = pdev->dev.platform_data;
+       if (!info) {
+               dev_err(dev, "no platform data, cannot attach\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "initialising touchscreen\n");
+
+       ts.clock = clk_get(dev, "adc");
+       if (IS_ERR(ts.clock)) {
+               dev_err(dev, "cannot get adc clock source\n");
+               return -ENOENT;
+       }
+
+       clk_enable(ts.clock);
+       dev_dbg(dev, "got and enabled clocks\n");
+
+       ts.irq_tc = ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
+               dev_err(dev, "no resource for interrupt\n");
+               goto err_clk;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "no resource for registers\n");
+               ret = -ENOENT;
+               goto err_clk;
+       }
+
+       ts.io = ioremap(res->start, resource_size(res));
+       if (ts.io == NULL) {
+               dev_err(dev, "cannot map registers\n");
+               ret = -ENOMEM;
+               goto err_clk;
+       }
+
+       /* Configure the touchscreen external FETs on the S3C2410 */
+       if (!platform_get_device_id(pdev)->driver_data)
+               s3c2410_ts_connect();
+
+       ts.client = s3c_adc_register(pdev, s3c24xx_ts_select,
+                                    s3c24xx_ts_conversion, 1);
+       if (IS_ERR(ts.client)) {
+               dev_err(dev, "failed to register adc client\n");
+               ret = PTR_ERR(ts.client);
+               goto err_iomap;
+       }
+
+       /* Initialise registers */
+       if ((info->delay & 0xffff) > 0)
+               writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
+
+       writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
+
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               dev_err(dev, "Unable to allocate the input device !!\n");
+               ret = -ENOMEM;
+               goto err_iomap;
+       }
+
+       ts.input = input_dev;
+       ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);
+       input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);
+
+       ts.input->name = "S3C24XX TouchScreen";
+       ts.input->id.bustype = BUS_HOST;
+       ts.input->id.vendor = 0xDEAD;
+       ts.input->id.product = 0xBEEF;
+       ts.input->id.version = 0x0102;
+
+       ts.shift = info->oversampling_shift;
+
+       ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED,
+                         "s3c2410_ts_pen", ts.input);
+       if (ret) {
+               dev_err(dev, "cannot get TC interrupt\n");
+               goto err_inputdev;
+       }
+
+       dev_info(dev, "driver attached, registering input device\n");
+
+       /* All went ok, so register to the input system */
+       ret = input_register_device(ts.input);
+       if (ret < 0) {
+               dev_err(dev, "failed to register input device\n");
+               ret = -EIO;
+               goto err_tcirq;
+       }
+
+       return 0;
+
+ err_tcirq:
+       free_irq(ts.irq_tc, ts.input);
+ err_inputdev:
+       input_unregister_device(ts.input);
+ err_iomap:
+       iounmap(ts.io);
+ err_clk:
+       del_timer_sync(&touch_timer);
+       clk_put(ts.clock);
+       return ret;
+}
+
+/**
+ * s3c2410ts_remove - device core removal entry point
+ * @pdev: The device we are being removed from.
+ *
+ * Free up our state ready to be removed.
+ */
+static int __devexit s3c2410ts_remove(struct platform_device *pdev)
+{
+       free_irq(ts.irq_tc, ts.input);
+       del_timer_sync(&touch_timer);
+
+       clk_disable(ts.clock);
+       clk_put(ts.clock);
+
+       input_unregister_device(ts.input);
+       iounmap(ts.io);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c2410ts_suspend(struct device *dev)
+{
+       writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC);
+       disable_irq(ts.irq_tc);
+       clk_disable(ts.clock);
+
+       return 0;
+}
+
+static int s3c2410ts_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s3c2410_ts_mach_info *info = pdev->dev.platform_data;
+
+       clk_enable(ts.clock);
+
+       /* Initialise registers */
+       if ((info->delay & 0xffff) > 0)
+               writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
+
+       writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
+
+       return 0;
+}
+
+static struct dev_pm_ops s3c_ts_pmops = {
+       .suspend        = s3c2410ts_suspend,
+       .resume         = s3c2410ts_resume,
+};
+#endif
+
+static struct platform_device_id s3cts_driver_ids[] = {
+       { "s3c2410-ts", 0 },
+       { "s3c2440-ts", 1 },
+       { }
+};
+MODULE_DEVICE_TABLE(platform, s3cts_driver_ids);
+
+static struct platform_driver s3c_ts_driver = {
+       .driver         = {
+               .name   = "s3c24xx-ts",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &s3c_ts_pmops,
+#endif
+       },
+       .id_table       = s3cts_driver_ids,
+       .probe          = s3c2410ts_probe,
+       .remove         = __devexit_p(s3c2410ts_remove),
+};
+
+static int __init s3c2410ts_init(void)
+{
+       return platform_driver_register(&s3c_ts_driver);
+}
+
+static void __exit s3c2410ts_exit(void)
+{
+       platform_driver_unregister(&s3c_ts_driver);
+}
+
+module_init(s3c2410ts_init);
+module_exit(s3c2410ts_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
+             "Ben Dooks <ben@simtec.co.uk>, "
+             "Simtec Electronics <linux@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C24XX Touchscreen driver");
+MODULE_LICENSE("GPL v2");
index 095f84b..89dcbe7 100644 (file)
@@ -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);