Commit fa395aae authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

* '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
  ...
parents 3e746831 1f26978a
...@@ -293,10 +293,23 @@ X!Idrivers/video/console/fonts.c ...@@ -293,10 +293,23 @@ X!Idrivers/video/console/fonts.c
<chapter id="input_subsystem"> <chapter id="input_subsystem">
<title>Input Subsystem</title> <title>Input Subsystem</title>
<sect1><title>Input core</title>
!Iinclude/linux/input.h !Iinclude/linux/input.h
!Edrivers/input/input.c !Edrivers/input/input.c
!Edrivers/input/ff-core.c !Edrivers/input/ff-core.c
!Edrivers/input/ff-memless.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>
<chapter id="spi"> <chapter id="spi">
......
...@@ -486,13 +486,6 @@ S: Maintained ...@@ -486,13 +486,6 @@ S: Maintained
F: drivers/net/appletalk/ F: drivers/net/appletalk/
F: 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 ARC FRAMEBUFFER DRIVER
M: Jaya Kumar <jayalk@intworks.biz> M: Jaya Kumar <jayalk@intworks.biz>
S: Maintained S: Maintained
......
...@@ -865,6 +865,57 @@ static void __init at91_add_device_rtc(void) {} ...@@ -865,6 +865,57 @@ static void __init at91_add_device_rtc(void) {}
#endif #endif
/* --------------------------------------------------------------------
* Touchscreen
* -------------------------------------------------------------------- */
#if defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) || defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC_MODULE)
static u64 tsadcc_dmamask = DMA_BIT_MASK(32);
static struct at91_tsadcc_data tsadcc_data;
static struct resource tsadcc_resources[] = {
[0] = {
.start = AT91SAM9G45_BASE_TSC,
.end = AT91SAM9G45_BASE_TSC + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AT91SAM9G45_ID_TSC,
.end = AT91SAM9G45_ID_TSC,
.flags = IORESOURCE_IRQ,
}
};
static struct platform_device at91sam9g45_tsadcc_device = {
.name = "atmel_tsadcc",
.id = -1,
.dev = {
.dma_mask = &tsadcc_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &tsadcc_data,
},
.resource = tsadcc_resources,
.num_resources = ARRAY_SIZE(tsadcc_resources),
};
void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data)
{
if (!data)
return;
at91_set_gpio_input(AT91_PIN_PD20, 0); /* AD0_XR */
at91_set_gpio_input(AT91_PIN_PD21, 0); /* AD1_XL */
at91_set_gpio_input(AT91_PIN_PD22, 0); /* AD2_YT */
at91_set_gpio_input(AT91_PIN_PD23, 0); /* AD3_TB */
tsadcc_data = *data;
platform_device_register(&at91sam9g45_tsadcc_device);
}
#else
void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) {}
#endif
/* -------------------------------------------------------------------- /* --------------------------------------------------------------------
* RTT * RTT
* -------------------------------------------------------------------- */ * -------------------------------------------------------------------- */
......
...@@ -622,6 +622,7 @@ static void __init at91_add_device_tc(void) { } ...@@ -622,6 +622,7 @@ static void __init at91_add_device_tc(void) { }
#if defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) || defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC_MODULE) #if defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) || defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC_MODULE)
static u64 tsadcc_dmamask = DMA_BIT_MASK(32); static u64 tsadcc_dmamask = DMA_BIT_MASK(32);
static struct at91_tsadcc_data tsadcc_data;
static struct resource tsadcc_resources[] = { static struct resource tsadcc_resources[] = {
[0] = { [0] = {
...@@ -642,22 +643,27 @@ static struct platform_device at91sam9rl_tsadcc_device = { ...@@ -642,22 +643,27 @@ static struct platform_device at91sam9rl_tsadcc_device = {
.dev = { .dev = {
.dma_mask = &tsadcc_dmamask, .dma_mask = &tsadcc_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32), .coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &tsadcc_data,
}, },
.resource = tsadcc_resources, .resource = tsadcc_resources,
.num_resources = ARRAY_SIZE(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_PA17, 0); /* AD0_XR */
at91_set_A_periph(AT91_PIN_PA18, 0); /* AD1_XL */ 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_PA19, 0); /* AD2_YT */
at91_set_A_periph(AT91_PIN_PA20, 0); /* AD3_TB */ at91_set_A_periph(AT91_PIN_PA20, 0); /* AD3_TB */
tsadcc_data = *data;
platform_device_register(&at91sam9rl_tsadcc_device); platform_device_register(&at91sam9rl_tsadcc_device);
} }
#else #else
void __init at91_add_device_tsadcc(void) {} void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) {}
#endif #endif
......
...@@ -228,6 +228,16 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data; ...@@ -228,6 +228,16 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data;
#endif #endif
/*
* Touchscreen
*/
static struct at91_tsadcc_data ek_tsadcc_data = {
.adc_clock = 300000,
.pendet_debounce = 0x0d,
.ts_sample_hold_time = 0x0a,
};
/* /*
* GPIO Buttons * GPIO Buttons
*/ */
...@@ -379,6 +389,8 @@ static void __init ek_board_init(void) ...@@ -379,6 +389,8 @@ static void __init ek_board_init(void)
at91_add_device_i2c(0, NULL, 0); at91_add_device_i2c(0, NULL, 0);
/* LCD Controller */ /* LCD Controller */
at91_add_device_lcdc(&ek_lcdc_data); at91_add_device_lcdc(&ek_lcdc_data);
/* Touch Screen */
at91_add_device_tsadcc(&ek_tsadcc_data);
/* Push Buttons */ /* Push Buttons */
ek_add_device_buttons(); ek_add_device_buttons();
/* AC97 */ /* AC97 */
......
...@@ -242,6 +242,16 @@ static struct gpio_led ek_leds[] = { ...@@ -242,6 +242,16 @@ static struct gpio_led ek_leds[] = {
}; };
/*
* Touchscreen
*/
static struct at91_tsadcc_data ek_tsadcc_data = {
.adc_clock = 1000000,
.pendet_debounce = 0x0f,
.ts_sample_hold_time = 0x03,
};
/* /*
* GPIO Buttons * GPIO Buttons
*/ */
...@@ -310,7 +320,7 @@ static void __init ek_board_init(void) ...@@ -310,7 +320,7 @@ static void __init ek_board_init(void)
/* AC97 */ /* AC97 */
at91_add_device_ac97(&ek_ac97_data); at91_add_device_ac97(&ek_ac97_data);
/* Touch Screen Controller */ /* Touch Screen Controller */
at91_add_device_tsadcc(); at91_add_device_tsadcc(&ek_tsadcc_data);
/* LEDs */ /* LEDs */
at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
/* Push Buttons */ /* Push Buttons */
......
...@@ -187,7 +187,12 @@ extern void __init at91_add_device_ac97(struct ac97c_platform_data *data); ...@@ -187,7 +187,12 @@ extern void __init at91_add_device_ac97(struct ac97c_platform_data *data);
extern void __init at91_add_device_isi(void); extern void __init at91_add_device_isi(void);
/* Touchscreen Controller */ /* 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 */ /* CAN */
struct at91_can_data { struct at91_can_data {
......
/*
* 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
...@@ -46,8 +46,6 @@ ...@@ -46,8 +46,6 @@
extern void ctrl_alt_del(void); extern void ctrl_alt_del(void);
#define to_handle_h(n) container_of(n, struct input_handle, h_node)
/* /*
* Exported functions/variables * Exported functions/variables
*/ */
...@@ -132,6 +130,7 @@ int shift_state = 0; ...@@ -132,6 +130,7 @@ int shift_state = 0;
*/ */
static struct input_handler kbd_handler; 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 long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
static int dead_key_next; static int dead_key_next;
...@@ -190,78 +189,85 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier); ...@@ -190,78 +189,85 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
* etc.). So this means that scancodes for the extra function keys won't * 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. * 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) int getkeycode(unsigned int scancode)
{ {
struct input_handle *handle; struct getset_keycode_data d = { scancode, 0, -ENODEV };
int keycode;
int error = -ENODEV;
list_for_each_entry(handle, &kbd_handler.h_list, h_node) { input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
error = input_get_keycode(handle->dev, scancode, &keycode);
if (!error)
return keycode;
}
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) int setkeycode(unsigned int scancode, unsigned int keycode)
{ {
struct input_handle *handle; struct getset_keycode_data d = { scancode, keycode, -ENODEV };
int error = -ENODEV;
list_for_each_entry(handle, &kbd_handler.h_list, h_node) { input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
error = input_set_keycode(handle->dev, scancode, keycode);
if (!error)
break;
}
return error; return d.error;
} }
/* /*
* Making beeps and bells. * 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, dev->evbit)) {
if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, dev->sndbit))
if (test_bit(SND_TONE, handle->dev->sndbit)) input_inject_event(handle, EV_SND, SND_TONE, *hz);
input_inject_event(handle, EV_SND, SND_TONE, 0); if (test_bit(SND_BELL, handle->dev->sndbit))
if (test_bit(SND_BELL, handle->dev->sndbit)) input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
input_inject_event(handle, EV_SND, SND_BELL, 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); static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
void kd_mksound(unsigned int hz, unsigned int ticks) 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) { if (hz && ticks)
list_for_each_prev(node, &kbd_handler.h_list) { mod_timer(&kd_mksound_timer, jiffies + ticks);
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);
} }
EXPORT_SYMBOL(kd_mksound); EXPORT_SYMBOL(kd_mksound);
...@@ -269,27 +275,34 @@ EXPORT_SYMBOL(kd_mksound); ...@@ -269,27 +275,34 @@ EXPORT_SYMBOL(kd_mksound);
* Setting the keyboard rate. * 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; struct input_dev *dev = handle->dev;
unsigned int d = 0; struct kbd_repeat *rep = data;
unsigned int p = 0;
if (test_bit(EV_REP, dev->evbit)) {
list_for_each(node, &kbd_handler.h_list) {
struct input_handle *handle = to_handle_h(node); if (rep[0].delay > 0)
struct input_dev *dev = handle->dev; input_inject_event(handle,
EV_REP, REP_DELAY, rep[0].delay);
if (test_bit(EV_REP, dev->evbit)) { if (rep[0].period > 0)
if (rep->delay > 0) input_inject_event(handle,
input_inject_event(handle, EV_REP, REP_DELAY, rep->delay); EV_REP, REP_PERIOD, rep[0].period);
if (rep->period > 0)
input_inject_event(handle, EV_REP, REP_PERIOD, rep->period); rep[1].delay = dev->rep[REP_DELAY];
d = dev->rep[REP_DELAY]; rep[1].period = dev->rep[REP_PERIOD];
p = 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; return 0;
} }
...@@ -997,36 +1010,36 @@ static inline unsigned char getleds(void) ...@@ -997,36 +1010,36 @@ static inline unsigned char getleds(void)
return leds; 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 * This is the tasklet that updates LED state on all keyboards
* routine, and runs with all interrupts enabled. It does * attached to the box. The reason we use tasklet is that we
* console changing, led setting and copy_to_cooked, which can * need to handle the scenario when keyboard handler is not
* take a reasonably long time. * registered yet but we already getting updates form VT to
* * update led state.
* Aside from timing (which isn't really that important for
* keyboard interrupts as they happen often), using the software
* interrupt routines for this thing allows us to easily mask
* this when we don't want any of the above to happen.
* This allows for easy and efficient race-condition prevention
* for kbd_start => input_inject_event(dev, EV_LED, ...) => ...
*/ */
static void kbd_bh(unsigned long dummy) static void kbd_bh(unsigned long dummy)
{ {
struct list_head *node;
unsigned char leds = getleds(); unsigned char leds = getleds();
if (leds != ledstate) { if (leds != ledstate) {
list_for_each(node, &kbd_handler.h_list) { input_handler_for_each_handle(&kbd_handler, &leds,
struct input_handle *handle = to_handle_h(node); kbd_update_leds_helper);
input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); ledstate = leds;
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);
}
} }
ledstate = leds;
} }
DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); 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 ...@@ -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) static void kbd_rawcode(unsigned char data)
{ {
struct vc_data *vc = vc_cons[fg_console].d; 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) if (kbd->kbdmode == VC_RAW)
put_queue(vc, data); put_queue(vc, data);
} }
...@@ -1157,7 +1170,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) ...@@ -1157,7 +1170,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
tty->driver_data = vc; tty->driver_data = vc;
} }
kbd = kbd_table + fg_console; kbd = kbd_table + vc->vc_num;
if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
sysrq_alt = down ? keycode : 0; sysrq_alt = down ? keycode : 0;
...@@ -1296,10 +1309,16 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) ...@@ -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, static void kbd_event(struct input_handle *handle, unsigned int event_type,
unsigned int event_code, int value) 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)) if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
kbd_rawcode(value); kbd_rawcode(value);
if (event_type == EV_KEY) if (event_type == EV_KEY)
kbd_keycode(event_code, value, HW_RAW(handle->dev)); kbd_keycode(event_code, value, HW_RAW(handle->dev));
spin_unlock(&kbd_event_lock);
tasklet_schedule(&keyboard_tasklet); tasklet_schedule(&keyboard_tasklet);
do_poke_blanked_console = 1; do_poke_blanked_console = 1;
schedule_console_callback(); schedule_console_callback();
...@@ -1363,15 +1382,11 @@ static void kbd_disconnect(struct input_handle *handle) ...@@ -1363,15 +1382,11 @@ static void kbd_disconnect(struct input_handle *handle)
*/ */
static void kbd_start(struct input_handle *handle) static void kbd_start(struct input_handle *handle)
{ {
unsigned char leds = ledstate;
tasklet_disable(&keyboard_tasklet); tasklet_disable(&keyboard_tasklet);
if (leds != 0xff) {
input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); if (ledstate != 0xff)
input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); kbd_update_leds_helper(handle, &ledstate);
input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
}
tasklet_enable(&keyboard_tasklet); tasklet_enable(&keyboard_tasklet);
} }
......
...@@ -429,7 +429,7 @@ static bool dmi_matches(const struct dmi_system_id *dmi) ...@@ -429,7 +429,7 @@ static bool dmi_matches(const struct dmi_system_id *dmi)
for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) {
int s = dmi->matches[i].slot; int s = dmi->matches[i].slot;
if (s == DMI_NONE) if (s == DMI_NONE)
continue; break;
if (dmi_ident[s] if (dmi_ident[s]
&& strstr(dmi_ident[s], dmi->matches[i].substr)) && strstr(dmi_ident[s], dmi->matches[i].substr))
continue; continue;
...@@ -439,6 +439,15 @@ static bool dmi_matches(const struct dmi_system_id *dmi) ...@@ -439,6 +439,15 @@ static bool dmi_matches(const struct dmi_system_id *dmi)
return true; return true;
} }
/**
* dmi_is_end_of_table - check for end-of-table marker
* @dmi: pointer to the dmi_system_id structure to check
*/
static bool dmi_is_end_of_table(const struct dmi_system_id *dmi)
{
return dmi->matches[0].slot == DMI_NONE;
}
/** /**
* dmi_check_system - check system DMI data * dmi_check_system - check system DMI data
* @list: array of dmi_system_id structures to match against * @list: array of dmi_system_id structures to match against
...@@ -457,7 +466,7 @@ int dmi_check_system(const struct dmi_system_id *list) ...@@ -457,7 +466,7 @@ int dmi_check_system(const struct dmi_system_id *list)
int count = 0; int count = 0;
const struct dmi_system_id *d; 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)) { if (dmi_matches(d)) {
count++; count++;
if (d->callback && d->callback(d)) if (d->callback && d->callback(d))
...@@ -484,7 +493,7 @@ const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) ...@@ -484,7 +493,7 @@ const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list)
{ {
const struct dmi_system_id *d; 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)) if (dmi_matches(d))
return d; return d;
......
...@@ -266,7 +266,7 @@ static int usb_kbd_probe(struct usb_interface *iface, ...@@ -266,7 +266,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
le16_to_cpu(dev->descriptor.idProduct)); le16_to_cpu(dev->descriptor.idProduct));
usb_make_path(dev, kbd->phys, sizeof(kbd->phys)); 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->name = kbd->name;
input_dev->phys = kbd->phys; input_dev->phys = kbd->phys;
......
...@@ -8,7 +8,7 @@ menu "Input device support" ...@@ -8,7 +8,7 @@ menu "Input device support"
config INPUT config INPUT
tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
default y default y
---help--- help
Say Y here if you have any input device (mouse, keyboard, tablet, Say Y here if you have any input device (mouse, keyboard, tablet,
joystick, steering wheel ...) connected to your system and want joystick, steering wheel ...) connected to your system and want
it to be available to applications. This includes standard PS/2 it to be available to applications. This includes standard PS/2
...@@ -27,8 +27,7 @@ if INPUT ...@@ -27,8 +27,7 @@ if INPUT
config INPUT_FF_MEMLESS config INPUT_FF_MEMLESS
tristate "Support for memoryless force-feedback devices" tristate "Support for memoryless force-feedback devices"
default n help
---help---
Say Y here if you have memoryless force-feedback input device Say Y here if you have memoryless force-feedback input device
such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual
Power 2, or similar. You will also need to enable hardware-specific Power 2, or similar. You will also need to enable hardware-specific
...@@ -52,12 +51,25 @@ config INPUT_POLLDEV ...@@ -52,12 +51,25 @@ config INPUT_POLLDEV
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called input-polldev. 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" comment "Userland interfaces"
config INPUT_MOUSEDEV config INPUT_MOUSEDEV
tristate "Mouse interface" if EMBEDDED tristate "Mouse interface" if EMBEDDED
default y default y
---help--- help
Say Y here if you want your mouse to be accessible as char devices 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 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
emulated IntelliMouse Explorer PS/2 mouse. That way, all user space emulated IntelliMouse Explorer PS/2 mouse. That way, all user space
...@@ -73,7 +85,7 @@ config INPUT_MOUSEDEV_PSAUX ...@@ -73,7 +85,7 @@ config INPUT_MOUSEDEV_PSAUX
bool "Provide legacy /dev/psaux device" bool "Provide legacy /dev/psaux device"
default y default y
depends on INPUT_MOUSEDEV depends on INPUT_MOUSEDEV
---help--- help
Say Y here if you want your mouse also be accessible as char device 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 10:1 - /dev/psaux. The data available through /dev/psaux is exactly
the same as the data from /dev/input/mice. the same as the data from /dev/input/mice.
...@@ -103,7 +115,7 @@ config INPUT_MOUSEDEV_SCREEN_Y ...@@ -103,7 +115,7 @@ config INPUT_MOUSEDEV_SCREEN_Y
config INPUT_JOYDEV config INPUT_JOYDEV
tristate "Joystick interface" tristate "Joystick interface"
---help--- help
Say Y here if you want your joystick or gamepad to be Say Y here if you want your joystick or gamepad to be
accessible as char device 13:0+ - /dev/input/jsX device. accessible as char device 13:0+ - /dev/input/jsX device.
...@@ -125,7 +137,7 @@ config INPUT_EVDEV ...@@ -125,7 +137,7 @@ config INPUT_EVDEV
config INPUT_EVBUG config INPUT_EVBUG
tristate "Event debugging" tristate "Event debugging"
---help--- help
Say Y here if you have a problem with the input subsystem and Say Y here if you have a problem with the input subsystem and
want all events (keypresses, mouse movements), to be output to want all events (keypresses, mouse movements), to be output to
the system log. While this is useful for debugging, it's also the system log. While this is useful for debugging, it's also
...@@ -140,7 +152,7 @@ config INPUT_EVBUG ...@@ -140,7 +152,7 @@ config INPUT_EVBUG
config INPUT_APMPOWER config INPUT_APMPOWER
tristate "Input Power Event -> APM Bridge" if EMBEDDED tristate "Input Power Event -> APM Bridge" if EMBEDDED
depends on INPUT && APM_EMULATION depends on INPUT && APM_EMULATION
---help--- help
Say Y here if you want suspend key events to trigger a user Say Y here if you want suspend key events to trigger a user
requested suspend through APM. This is useful on embedded requested suspend through APM. This is useful on embedded
systems where such behaviour is desired without userspace systems where such behaviour is desired without userspace
......
...@@ -9,6 +9,7 @@ input-core-objs := input.o input-compat.o ff-core.o ...@@ -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_FF_MEMLESS) += ff-memless.o
obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
......
...@@ -353,7 +353,7 @@ int input_ff_create(struct input_dev *dev, int max_effects) ...@@ -353,7 +353,7 @@ int input_ff_create(struct input_dev *dev, int max_effects)
EXPORT_SYMBOL_GPL(input_ff_create); 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 * @dev: input device supporting force feedback
* *
* This function is only needed in error path as input core will * This function is only needed in error path as input core will
...@@ -369,6 +369,7 @@ void input_ff_destroy(struct input_dev *dev) ...@@ -369,6 +369,7 @@ void input_ff_destroy(struct input_dev *dev)
if (ff->destroy) if (ff->destroy)
ff->destroy(ff); ff->destroy(ff);
kfree(ff->private); kfree(ff->private);
kfree(ff->effects);
kfree(ff); kfree(ff);
dev->ff = NULL; dev->ff = NULL;
} }
......
...@@ -56,14 +56,10 @@ static void input_polldev_stop_workqueue(void) ...@@ -56,14 +56,10 @@ static void input_polldev_stop_workqueue(void)
mutex_unlock(&polldev_mutex); 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; unsigned long delay;
dev->poll(dev);
delay = msecs_to_jiffies(dev->poll_interval); delay = msecs_to_jiffies(dev->poll_interval);
if (delay >= HZ) if (delay >= HZ)
delay = round_jiffies_relative(delay); delay = round_jiffies_relative(delay);
...@@ -71,6 +67,15 @@ static void input_polled_device_work(struct work_struct *work) ...@@ -71,6 +67,15 @@ static void input_polled_device_work(struct work_struct *work)
queue_delayed_work(polldev_wq, &dev->work, delay); 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) static int input_open_polled_device(struct input_dev *input)
{ {
struct input_polled_dev *dev = input_get_drvdata(input); struct input_polled_dev *dev = input_get_drvdata(input);
...@@ -80,11 +85,12 @@ static int input_open_polled_device(struct input_dev *input) ...@@ -80,11 +85,12 @@ static int input_open_polled_device(struct input_dev *input)
if (error) if (error)
return error; return error;
if (dev->flush) if (dev->open)
dev->flush(dev); dev->open(dev);
queue_delayed_work(polldev_wq, &dev->work, /* Only start polling if polling is enabled */
msecs_to_jiffies(dev->poll_interval)); if (dev->poll_interval > 0)
queue_delayed_work(polldev_wq, &dev->work, 0);
return 0; return 0;
} }
...@@ -95,8 +101,88 @@ static void input_close_polled_device(struct input_dev *input) ...@@ -95,8 +101,88 @@ static void input_close_polled_device(struct input_dev *input)
cancel_delayed_work_sync(&dev->work); cancel_delayed_work_sync(&dev->work);
input_polldev_stop_workqueue(); 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 * input_allocate_polled_device - allocated memory polled device
* *
...@@ -126,7 +212,7 @@ EXPORT_SYMBOL(input_allocate_polled_device); ...@@ -126,7 +212,7 @@ EXPORT_SYMBOL(input_allocate_polled_device);
* @dev: device to free * @dev: device to free
* *
* The function frees memory allocated for polling device and drops * 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) void input_free_polled_device(struct input_polled_dev *dev)
{ {
...@@ -150,15 +236,38 @@ EXPORT_SYMBOL(input_free_polled_device); ...@@ -150,15 +236,38 @@ EXPORT_SYMBOL(input_free_polled_device);
int input_register_polled_device(struct input_polled_dev *dev) int input_register_polled_device(struct input_polled_dev *dev)
{ {
struct input_dev *input = dev->input; struct input_dev *input = dev->input;
int error;
input_set_drvdata(input, dev); input_set_drvdata(input, dev);
INIT_DELAYED_WORK(&dev->work, input_polled_device_work); INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
if (!dev->poll_interval) if (!dev->poll_interval)
dev->poll_interval = 500; dev->poll_interval = 500;
if (!dev->poll_interval_max)
dev->poll_interval_max = dev->poll_interval;
input->open = input_open_polled_device; input->open = input_open_polled_device;
input->close = input_close_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); EXPORT_SYMBOL(input_register_polled_device);
...@@ -169,13 +278,13 @@ EXPORT_SYMBOL(input_register_polled_device); ...@@ -169,13 +278,13 @@ EXPORT_SYMBOL(input_register_polled_device);
* The function unregisters previously registered polled input * The function unregisters previously registered polled input
* device from input layer. Polling is stopped and device is * device from input layer. Polling is stopped and device is
* ready to be freed with call to input_free_polled_device(). * 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) 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); input_unregister_device(dev->input);
dev->input = NULL;
} }
EXPORT_SYMBOL(input_unregister_polled_device); EXPORT_SYMBOL(input_unregister_polled_device);
...@@ -1657,6 +1657,38 @@ void input_unregister_handler(struct input_handler *handler) ...@@ -1657,6 +1657,38 @@ void input_unregister_handler(struct input_handler *handler)
} }
EXPORT_SYMBOL(input_unregister_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 * input_register_handle - register a new input handle
* @handle: handle to register * @handle: handle to register
...@@ -1690,7 +1722,7 @@ int input_register_handle(struct input_handle *handle) ...@@ -1690,7 +1722,7 @@ int input_register_handle(struct input_handle *handle)
* we can't be racing with input_unregister_handle() * we can't be racing with input_unregister_handle()
* and so separate lock is not needed here. * 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) if (handler->start)
handler->start(handle); handler->start(handle);
...@@ -1713,7 +1745,7 @@ void input_unregister_handle(struct input_handle *handle) ...@@ -1713,7 +1745,7 @@ void input_unregister_handle(struct input_handle *handle)
{ {
struct input_dev *dev = handle->dev; 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(). * Take dev->mutex to prevent race with input_release_device().
...@@ -1721,6 +1753,7 @@ void input_unregister_handle(struct input_handle *handle) ...@@ -1721,6 +1753,7 @@ void input_unregister_handle(struct input_handle *handle)
mutex_lock(&dev->mutex); mutex_lock(&dev->mutex);
list_del_rcu(&handle->d_node); list_del_rcu(&handle->d_node);
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
synchronize_rcu(); synchronize_rcu();
} }
EXPORT_SYMBOL(input_unregister_handle); EXPORT_SYMBOL(input_unregister_handle);
......
...@@ -125,6 +125,7 @@ static const struct xpad_device { ...@@ -125,6 +125,7 @@ static const struct xpad_device {
{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 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, 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, 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 }, { 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, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 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 { ...@@ -146,6 +147,7 @@ static const struct xpad_device {
{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 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 }, { 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 }, { 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 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN } { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN }
}; };
...@@ -212,6 +214,7 @@ static struct usb_device_id xpad_table [] = { ...@@ -212,6 +214,7 @@ static struct usb_device_id xpad_table [] = {
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */ XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */
XPAD_XBOX360_VENDOR(0x1bad), /* Rock Band Drums */ XPAD_XBOX360_VENDOR(0x1bad), /* Rock Band Drums */
XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
{ } { }
}; };
......
...@@ -361,6 +361,16 @@ config KEYBOARD_SH_KEYSC ...@@ -361,6 +361,16 @@ config KEYBOARD_SH_KEYSC
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called sh_keysc. 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 config KEYBOARD_OMAP
tristate "TI OMAP keypad support" tristate "TI OMAP keypad support"
depends on (ARCH_OMAP1 || ARCH_OMAP2) depends on (ARCH_OMAP1 || ARCH_OMAP2)
......
...@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o ...@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
......
...@@ -1567,9 +1567,8 @@ static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id) ...@@ -1567,9 +1567,8 @@ static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
return 0; 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 = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
...@@ -1578,7 +1577,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1578,7 +1577,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_dell_laptop_forced_release_keys, .driver_data = atkbd_dell_laptop_forced_release_keys,
}, },
{ {
.ident = "Dell Laptop",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
...@@ -1587,7 +1585,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1587,7 +1585,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_dell_laptop_forced_release_keys, .driver_data = atkbd_dell_laptop_forced_release_keys,
}, },
{ {
.ident = "HP 2133",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"), DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"),
...@@ -1596,7 +1593,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1596,7 +1593,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_hp_forced_release_keys, .driver_data = atkbd_hp_forced_release_keys,
}, },
{ {
.ident = "HP Pavilion ZV6100",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
...@@ -1605,7 +1601,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1605,7 +1601,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_volume_forced_release_keys, .driver_data = atkbd_volume_forced_release_keys,
}, },
{ {
.ident = "HP Presario R4000",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"), DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
...@@ -1614,7 +1609,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1614,7 +1609,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_volume_forced_release_keys, .driver_data = atkbd_volume_forced_release_keys,
}, },
{ {
.ident = "HP Presario R4100",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"), DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
...@@ -1623,7 +1617,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1623,7 +1617,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_volume_forced_release_keys, .driver_data = atkbd_volume_forced_release_keys,
}, },
{ {
.ident = "HP Presario R4200",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"), DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
...@@ -1632,7 +1625,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1632,7 +1625,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_volume_forced_release_keys, .driver_data = atkbd_volume_forced_release_keys,
}, },
{ {
.ident = "Inventec Symphony", /* Inventec Symphony */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"),
DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
...@@ -1641,7 +1634,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1641,7 +1634,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_volume_forced_release_keys, .driver_data = atkbd_volume_forced_release_keys,
}, },
{ {
.ident = "Samsung NC10", /* Samsung NC10 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
...@@ -1650,7 +1643,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1650,7 +1643,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_samsung_forced_release_keys, .driver_data = atkbd_samsung_forced_release_keys,
}, },
{ {
.ident = "Samsung NC20", /* Samsung NC20 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "NC20"), DMI_MATCH(DMI_PRODUCT_NAME, "NC20"),
...@@ -1659,7 +1652,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1659,7 +1652,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_samsung_forced_release_keys, .driver_data = atkbd_samsung_forced_release_keys,
}, },
{ {
.ident = "Samsung SQ45S70S", /* Samsung SQ45S70S */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
...@@ -1668,7 +1661,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1668,7 +1661,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_samsung_forced_release_keys, .driver_data = atkbd_samsung_forced_release_keys,
}, },
{ {
.ident = "Fujitsu Amilo PA 1510", /* Fujitsu Amilo PA 1510 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
...@@ -1677,7 +1670,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1677,7 +1670,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_volume_forced_release_keys, .driver_data = atkbd_volume_forced_release_keys,
}, },
{ {
.ident = "Fujitsu Amilo Pi 3525", /* Fujitsu Amilo Pi 3525 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"),
...@@ -1686,7 +1679,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1686,7 +1679,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_amilo_pi3525_forced_release_keys, .driver_data = atkbd_amilo_pi3525_forced_release_keys,
}, },
{ {
.ident = "Fujitsu Amilo Xi 3650", /* Fujitsu Amilo Xi 3650 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"),
...@@ -1695,7 +1688,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1695,7 +1688,6 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkbd_amilo_xi3650_forced_release_keys, .driver_data = atkbd_amilo_xi3650_forced_release_keys,
}, },
{ {
.ident = "Soltech Corporation TA12",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "TA12"), DMI_MATCH(DMI_PRODUCT_NAME, "TA12"),
...@@ -1704,7 +1696,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { ...@@ -1704,7 +1696,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.driver_data = atkdb_soltech_ta12_forced_release_keys, .driver_data = atkdb_soltech_ta12_forced_release_keys,
}, },
{ {
.ident = "OQO Model 01+", /* OQO Model 01+ */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "OQO"), DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
......
/*
* 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");
...@@ -23,8 +23,7 @@ ...@@ -23,8 +23,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/gpio_keys.h> #include <linux/gpio_keys.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/gpio.h>
#include <asm/gpio.h>
struct gpio_button_data { struct gpio_button_data {
struct gpio_keys_button *button; struct gpio_keys_button *button;
...@@ -38,10 +37,8 @@ struct gpio_keys_drvdata { ...@@ -38,10 +37,8 @@ struct gpio_keys_drvdata {
struct gpio_button_data data[0]; 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 gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input; struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY; unsigned int type = button->type ?: EV_KEY;
...@@ -51,6 +48,14 @@ static void gpio_keys_report_event(struct work_struct *work) ...@@ -51,6 +48,14 @@ static void gpio_keys_report_event(struct work_struct *work)
input_sync(input); 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) static void gpio_keys_timer(unsigned long _data)
{ {
struct gpio_button_data *data = (struct gpio_button_data *)_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) ...@@ -74,10 +79,62 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
return IRQ_HANDLED; 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) static int __devinit gpio_keys_probe(struct platform_device *pdev)
{ {
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct gpio_keys_drvdata *ddata; struct gpio_keys_drvdata *ddata;
struct device *dev = &pdev->dev;
struct input_dev *input; struct input_dev *input;
int i, error; int i, error;
int wakeup = 0; int wakeup = 0;
...@@ -87,6 +144,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) ...@@ -87,6 +144,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
GFP_KERNEL); GFP_KERNEL);
input = input_allocate_device(); input = input_allocate_device();
if (!ddata || !input) { if (!ddata || !input) {
dev_err(dev, "failed to allocate state\n");
error = -ENOMEM; error = -ENOMEM;
goto fail1; goto fail1;
} }
...@@ -111,52 +169,14 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) ...@@ -111,52 +169,14 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
for (i = 0; i < pdata->nbuttons; i++) { for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i]; struct gpio_button_data *bdata = &ddata->data[i];
int irq;
unsigned int type = button->type ?: EV_KEY; unsigned int type = button->type ?: EV_KEY;
bdata->input = input; bdata->input = input;
bdata->button = button; 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, error = gpio_keys_setup_key(dev, bdata, button);
IRQF_SHARED | if (error)
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);
goto fail2; goto fail2;
}
if (button->wakeup) if (button->wakeup)
wakeup = 1; wakeup = 1;
...@@ -166,11 +186,16 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) ...@@ -166,11 +186,16 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
error = input_register_device(input); error = input_register_device(input);
if (error) { if (error) {
pr_err("gpio-keys: Unable to register input device, " dev_err(dev, "Unable to register input device, "
"error: %d\n", error); "error: %d\n", error);
goto fail2; 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); device_init_wakeup(&pdev->dev, wakeup);
return 0; return 0;
...@@ -239,18 +264,21 @@ static int gpio_keys_suspend(struct device *dev) ...@@ -239,18 +264,21 @@ static int gpio_keys_suspend(struct device *dev)
static int gpio_keys_resume(struct device *dev) static int gpio_keys_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_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; struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i; int i;
if (device_may_wakeup(&pdev->dev)) { for (i = 0; i < pdata->nbuttons; i++) {
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_keys_button *button = &pdata->buttons[i];
if (button->wakeup) { if (button->wakeup && device_may_wakeup(&pdev->dev)) {
int irq = gpio_to_irq(button->gpio); int irq = gpio_to_irq(button->gpio);
disable_irq_wake(irq); disable_irq_wake(irq);
}
} }
gpio_keys_report_event(&ddata->data[i]);
} }
input_sync(ddata->input);
return 0; return 0;
} }
......
...@@ -72,9 +72,9 @@ ...@@ -72,9 +72,9 @@
#define DRIVER_DESC "LK keyboard driver" #define DRIVER_DESC "LK keyboard driver"
MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
MODULE_DESCRIPTION (DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
/* /*
* Known parameters: * Known parameters:
...@@ -85,27 +85,27 @@ MODULE_LICENSE ("GPL"); ...@@ -85,27 +85,27 @@ MODULE_LICENSE ("GPL");
* Please notice that there's not yet an API to set these at runtime. * Please notice that there's not yet an API to set these at runtime.
*/ */
static int bell_volume = 100; /* % */ static int bell_volume = 100; /* % */
module_param (bell_volume, int, 0); module_param(bell_volume, int, 0);
MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%"); MODULE_PARM_DESC(bell_volume, "Bell volume (in %). default is 100%");
static int keyclick_volume = 100; /* % */ static int keyclick_volume = 100; /* % */
module_param (keyclick_volume, int, 0); module_param(keyclick_volume, int, 0);
MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%"); MODULE_PARM_DESC(keyclick_volume, "Keyclick volume (in %), default is 100%");
static int ctrlclick_volume = 100; /* % */ static int ctrlclick_volume = 100; /* % */
module_param (ctrlclick_volume, int, 0); module_param(ctrlclick_volume, int, 0);
MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); MODULE_PARM_DESC(ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
static int lk201_compose_is_alt; static int lk201_compose_is_alt;
module_param (lk201_compose_is_alt, int, 0); module_param(lk201_compose_is_alt, int, 0);
MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " MODULE_PARM_DESC(lk201_compose_is_alt,
"will act as an Alt key"); "If set non-zero, LK201' Compose key will act as an Alt key");
#undef LKKBD_DEBUG #undef LKKBD_DEBUG
#ifdef LKKBD_DEBUG #ifdef LKKBD_DEBUG
#define DBG(x...) printk (x) #define DBG(x...) printk(x)
#else #else
#define DBG(x...) do {} while (0) #define DBG(x...) do {} while (0)
#endif #endif
...@@ -122,7 +122,7 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " ...@@ -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_DOWN 0x80
#define LK_MODE_AUTODOWN 0x82 #define LK_MODE_AUTODOWN 0x82
#define LK_MODE_UPDOWN 0x86 #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 */ /* Misc commands */
#define LK_CMD_ENABLE_KEYCLICK 0x1b #define LK_CMD_ENABLE_KEYCLICK 0x1b
...@@ -152,11 +152,8 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " ...@@ -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_KEYCODES 256
#define LK_NUM_IGNORE_BYTES 6 #define LK_NUM_IGNORE_BYTES 6
typedef u_int16_t lk_keycode_t;
static unsigned short lkkbd_keycode[LK_NUM_KEYCODES] = {
static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
[0x56] = KEY_F1, [0x56] = KEY_F1,
[0x57] = KEY_F2, [0x57] = KEY_F2,
[0x58] = KEY_F3, [0x58] = KEY_F3,
...@@ -268,7 +265,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { ...@@ -268,7 +265,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
}; };
#define CHECK_LED(LK, VAR_ON, VAR_OFF, LED, BITS) do { \ #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; \ VAR_ON |= BITS; \
else \ else \
VAR_OFF |= BITS; \ VAR_OFF |= BITS; \
...@@ -278,7 +275,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { ...@@ -278,7 +275,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
* Per-keyboard data * Per-keyboard data
*/ */
struct lkkbd { struct lkkbd {
lk_keycode_t keycode[LK_NUM_KEYCODES]; unsigned short keycode[LK_NUM_KEYCODES];
int ignore_bytes; int ignore_bytes;
unsigned char id[LK_NUM_IGNORE_BYTES]; unsigned char id[LK_NUM_IGNORE_BYTES];
struct input_dev *dev; struct input_dev *dev;
...@@ -301,26 +298,25 @@ static struct { ...@@ -301,26 +298,25 @@ static struct {
unsigned char *name; unsigned char *name;
} lk_response[] = { } lk_response[] = {
#define RESPONSE(x) { .value = (x), .name = #x, } #define RESPONSE(x) { .value = (x), .name = #x, }
RESPONSE (LK_STUCK_KEY), RESPONSE(LK_STUCK_KEY),
RESPONSE (LK_SELFTEST_FAILED), RESPONSE(LK_SELFTEST_FAILED),
RESPONSE (LK_ALL_KEYS_UP), RESPONSE(LK_ALL_KEYS_UP),
RESPONSE (LK_METRONOME), RESPONSE(LK_METRONOME),
RESPONSE (LK_OUTPUT_ERROR), RESPONSE(LK_OUTPUT_ERROR),
RESPONSE (LK_INPUT_ERROR), RESPONSE(LK_INPUT_ERROR),
RESPONSE (LK_KBD_LOCKED), RESPONSE(LK_KBD_LOCKED),
RESPONSE (LK_KBD_TEST_MODE_ACK), RESPONSE(LK_KBD_TEST_MODE_ACK),
RESPONSE (LK_PREFIX_KEY_DOWN), RESPONSE(LK_PREFIX_KEY_DOWN),
RESPONSE (LK_MODE_CHANGE_ACK), RESPONSE(LK_MODE_CHANGE_ACK),
RESPONSE (LK_RESPONSE_RESERVED), RESPONSE(LK_RESPONSE_RESERVED),
#undef RESPONSE #undef RESPONSE
}; };
static unsigned char * static unsigned char *response_name(unsigned char value)
response_name (unsigned char value)
{ {
int i; 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) if (lk_response[i].value == value)
return lk_response[i].name; return lk_response[i].name;
...@@ -331,8 +327,7 @@ response_name (unsigned char value) ...@@ -331,8 +327,7 @@ response_name (unsigned char value)
/* /*
* Calculate volume parameter byte for a given volume. * Calculate volume parameter byte for a given volume.
*/ */
static unsigned char static unsigned char volume_to_hw(int volume_percent)
volume_to_hw (int volume_percent)
{ {
unsigned char ret = 0; unsigned char ret = 0;
...@@ -363,8 +358,7 @@ volume_to_hw (int volume_percent) ...@@ -363,8 +358,7 @@ volume_to_hw (int volume_percent)
return ret; return ret;
} }
static void static void lkkbd_detection_done(struct lkkbd *lk)
lkkbd_detection_done (struct lkkbd *lk)
{ {
int i; int i;
...@@ -377,190 +371,202 @@ lkkbd_detection_done (struct lkkbd *lk) ...@@ -377,190 +371,202 @@ lkkbd_detection_done (struct lkkbd *lk)
* Print keyboard name and modify Compose=Alt on user's request. * Print keyboard name and modify Compose=Alt on user's request.
*/ */
switch (lk->id[4]) { switch (lk->id[4]) {
case 1: case 1:
strlcpy (lk->name, "DEC LK201 keyboard", strlcpy(lk->name, "DEC LK201 keyboard", sizeof(lk->name));
sizeof (lk->name));
if (lk201_compose_is_alt)
if (lk201_compose_is_alt) lk->keycode[0xb1] = KEY_LEFTALT;
lk->keycode[0xb1] = KEY_LEFTALT; break;
break;
case 2:
case 2: strlcpy(lk->name, "DEC LK401 keyboard", sizeof(lk->name));
strlcpy (lk->name, "DEC LK401 keyboard", break;
sizeof (lk->name));
break; default:
strlcpy(lk->name, "Unknown DEC keyboard", sizeof(lk->name));
default: printk(KERN_ERR
strlcpy (lk->name, "Unknown DEC keyboard", "lkkbd: keyboard on %s is unknown, please report to "
sizeof (lk->name)); "Jan-Benedict Glaw <jbglaw@lug-owl.de>\n", lk->phys);
printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " printk(KERN_ERR "lkkbd: keyboard ID'ed as:");
"please report to Jan-Benedict Glaw " for (i = 0; i < LK_NUM_IGNORE_BYTES; i++)
"<jbglaw@lug-owl.de>\n", lk->phys); printk(" 0x%02x", lk->id[i]);
printk (KERN_ERR "lkkbd: keyboard ID'ed as:"); printk("\n");
for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) break;
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. * Report errors during keyboard boot-up.
*/ */
switch (lk->id[2]) { switch (lk->id[2]) {
case 0x00: case 0x00:
/* All okay */ /* All okay */
break; break;
case LK_STUCK_KEY: case LK_STUCK_KEY:
printk (KERN_ERR "lkkbd: Stuck key on keyboard at " printk(KERN_ERR "lkkbd: Stuck key on keyboard at %s\n",
"%s\n", lk->phys); lk->phys);
break; break;
case LK_SELFTEST_FAILED: case LK_SELFTEST_FAILED:
printk (KERN_ERR "lkkbd: Selftest failed on keyboard " printk(KERN_ERR
"at %s, keyboard may not work " "lkkbd: Selftest failed on keyboard at %s, "
"properly\n", lk->phys); "keyboard may not work properly\n", lk->phys);
break; break;
default: default:
printk (KERN_ERR "lkkbd: Unknown error %02x on " printk(KERN_ERR
"keyboard at %s\n", lk->id[2], "lkkbd: Unknown error %02x on keyboard at %s\n",
lk->phys); lk->id[2], lk->phys);
break; break;
} }
/* /*
* Try to hint user if there's a stuck key. * Try to hint user if there's a stuck key.
*/ */
if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0) if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0)
printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode " printk(KERN_ERR
"is 0x%04x\n", lk->id[3], "Scancode of stuck key is 0x%02x, keycode is 0x%04x\n",
lk->keycode[lk->id[3]]); lk->id[3], lk->keycode[lk->id[3]]);
return;
} }
/* /*
* lkkbd_interrupt() is called by the low level driver when a character * lkkbd_interrupt() is called by the low level driver when a character
* is received. * is received.
*/ */
static irqreturn_t static irqreturn_t lkkbd_interrupt(struct serio *serio,
lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags) 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; 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) { 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; lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
if (lk->ignore_bytes == 0) if (lk->ignore_bytes == 0)
lkkbd_detection_done (lk); lkkbd_detection_done(lk);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
switch (data) { switch (data) {
case LK_ALL_KEYS_UP: case LK_ALL_KEYS_UP:
for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) for (i = 0; i < ARRAY_SIZE(lkkbd_keycode); i++)
if (lk->keycode[i] != KEY_RESERVED) input_report_key(input_dev, lk->keycode[i], 0);
input_report_key (lk->dev, lk->keycode[i], 0); input_sync(input_dev);
input_sync (lk->dev); break;
break;
case 0x01:
case 0x01: DBG(KERN_INFO "Got 0x01, scheduling re-initialization\n");
DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); lk->ignore_bytes = LK_NUM_IGNORE_BYTES;
lk->ignore_bytes = LK_NUM_IGNORE_BYTES; lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; schedule_work(&lk->tq);
schedule_work (&lk->tq); break;
break;
case LK_METRONOME:
case LK_METRONOME: case LK_OUTPUT_ERROR:
case LK_OUTPUT_ERROR: case LK_INPUT_ERROR:
case LK_INPUT_ERROR: case LK_KBD_LOCKED:
case LK_KBD_LOCKED: case LK_KBD_TEST_MODE_ACK:
case LK_KBD_TEST_MODE_ACK: case LK_PREFIX_KEY_DOWN:
case LK_PREFIX_KEY_DOWN: case LK_MODE_CHANGE_ACK:
case LK_MODE_CHANGE_ACK: case LK_RESPONSE_RESERVED:
case LK_RESPONSE_RESERVED: DBG(KERN_INFO "Got %s and don't know how to handle...\n",
DBG (KERN_INFO "Got %s and don't know how to handle...\n", response_name(data));
response_name (data)); break;
break;
default:
default: keycode = lk->keycode[data];
if (lk->keycode[data] != KEY_RESERVED) { if (keycode != KEY_RESERVED) {
if (!test_bit (lk->keycode[data], lk->dev->key)) input_report_key(input_dev, keycode,
input_report_key (lk->dev, lk->keycode[data], 1); !test_bit(keycode, input_dev->key));
else input_sync(input_dev);
input_report_key (lk->dev, lk->keycode[data], 0); } else {
input_sync (lk->dev); printk(KERN_WARNING
} else "%s: Unknown key with scancode 0x%02x on %s.\n",
printk (KERN_WARNING "%s: Unknown key with " __FILE__, data, lk->name);
"scancode 0x%02x on %s.\n", }
__FILE__, data, lk->name);
} }
return IRQ_HANDLED; 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. * lkkbd_event() handles events from the input module.
*/ */
static int static int lkkbd_event(struct input_dev *dev,
lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, unsigned int type, unsigned int code, int value)
int value)
{ {
struct lkkbd *lk = input_get_drvdata (dev); struct lkkbd *lk = input_get_drvdata(dev);
unsigned char leds_on = 0;
unsigned char leds_off = 0;
switch (type) { switch (type) {
case EV_LED: case EV_LED:
CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); lkkbd_toggle_leds(lk);
CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); return 0;
CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); case EV_SND:
if (leds_on != 0) { switch (code) {
serio_write (lk->serio, LK_CMD_LED_ON); case SND_CLICK:
serio_write (lk->serio, leds_on); lkkbd_toggle_keyclick(lk, value);
}
if (leds_off != 0) {
serio_write (lk->serio, LK_CMD_LED_OFF);
serio_write (lk->serio, leds_off);
}
return 0; return 0;
case EV_SND: case SND_BELL:
switch (code) { if (value != 0)
case SND_CLICK: serio_write(lk->serio, LK_CMD_SOUND_BELL);
if (value == 0) {
DBG ("%s: Deactivating key clicks\n", __func__); return 0;
serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK); }
serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
} else { break;
DBG ("%s: Activating key clicks\n", __func__);
serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK); default:
serio_write (lk->serio, volume_to_hw (lk->keyclick_volume)); printk(KERN_ERR "%s(): Got unknown type %d, code %d, value %d\n",
serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK); __func__, type, code, value);
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);
} }
return -1; return -1;
...@@ -570,79 +576,56 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, ...@@ -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 * lkkbd_reinit() sets leds and beeps to a state the computer remembers they
* were in. * were in.
*/ */
static void static void lkkbd_reinit(struct work_struct *work)
lkkbd_reinit (struct work_struct *work)
{ {
struct lkkbd *lk = container_of(work, struct lkkbd, tq); struct lkkbd *lk = container_of(work, struct lkkbd, tq);
int division; int division;
unsigned char leds_on = 0;
unsigned char leds_off = 0;
/* Ask for ID */ /* Ask for ID */
serio_write (lk->serio, LK_CMD_REQUEST_ID); serio_write(lk->serio, LK_CMD_REQUEST_ID);
/* Reset parameters */ /* Reset parameters */
serio_write (lk->serio, LK_CMD_SET_DEFAULTS); serio_write(lk->serio, LK_CMD_SET_DEFAULTS);
/* Set LEDs */ /* Set LEDs */
CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); lkkbd_toggle_leds(lk);
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);
}
/* /*
* Try to activate extended LK401 mode. This command will * Try to activate extended LK401 mode. This command will
* only work with a LK401 keyboard and grants access to * only work with a LK401 keyboard and grants access to
* LAlt, RAlt, RCompose and RShift. * 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 */ /* Set all keys to UPDOWN mode */
for (division = 1; division <= 14; division++) for (division = 1; division <= 14; division++)
serio_write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, serio_write(lk->serio,
division)); LK_CMD_SET_MODE(LK_MODE_UPDOWN, division));
/* Enable bell and set volume */ /* Enable bell and set volume */
serio_write (lk->serio, LK_CMD_ENABLE_BELL); serio_write(lk->serio, LK_CMD_ENABLE_BELL);
serio_write (lk->serio, volume_to_hw (lk->bell_volume)); serio_write(lk->serio, volume_to_hw(lk->bell_volume));
/* Enable/disable keyclick (and possibly set volume) */ /* Enable/disable keyclick (and possibly set volume) */
if (test_bit (SND_CLICK, lk->dev->snd)) { lkkbd_toggle_keyclick(lk, 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);
}
/* Sound the bell if needed */ /* Sound the bell if needed */
if (test_bit (SND_BELL, lk->dev->snd)) if (test_bit(SND_BELL, lk->dev->snd))
serio_write (lk->serio, LK_CMD_SOUND_BELL); serio_write(lk->serio, LK_CMD_SOUND_BELL);
} }
/* /*
* lkkbd_connect() probes for a LK keyboard and fills the necessary structures. * lkkbd_connect() probes for a LK keyboard and fills the necessary structures.
*/ */
static int static int lkkbd_connect(struct serio *serio, struct serio_driver *drv)
lkkbd_connect (struct serio *serio, struct serio_driver *drv)
{ {
struct lkkbd *lk; struct lkkbd *lk;
struct input_dev *input_dev; struct input_dev *input_dev;
int i; int i;
int err; int err;
lk = kzalloc (sizeof (struct lkkbd), GFP_KERNEL); lk = kzalloc(sizeof(struct lkkbd), GFP_KERNEL);
input_dev = input_allocate_device (); input_dev = input_allocate_device();
if (!lk || !input_dev) { if (!lk || !input_dev) {
err = -ENOMEM; err = -ENOMEM;
goto fail1; goto fail1;
...@@ -650,14 +633,14 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) ...@@ -650,14 +633,14 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
lk->serio = serio; lk->serio = serio;
lk->dev = input_dev; lk->dev = input_dev;
INIT_WORK (&lk->tq, lkkbd_reinit); INIT_WORK(&lk->tq, lkkbd_reinit);
lk->bell_volume = bell_volume; lk->bell_volume = bell_volume;
lk->keyclick_volume = keyclick_volume; lk->keyclick_volume = keyclick_volume;
lk->ctrlclick_volume = ctrlclick_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)); strlcpy(lk->name, "DEC LK keyboard", sizeof(lk->name));
snprintf (lk->phys, sizeof(lk->phys), "%s/input0", serio->phys); snprintf(lk->phys, sizeof(lk->phys), "%s/input0", serio->phys);
input_dev->name = lk->name; input_dev->name = lk->name;
input_dev->phys = lk->phys; input_dev->phys = lk->phys;
...@@ -668,62 +651,61 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) ...@@ -668,62 +651,61 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
input_dev->dev.parent = &serio->dev; input_dev->dev.parent = &serio->dev;
input_dev->event = lkkbd_event; 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_KEY, input_dev->evbit);
set_bit (EV_LED, input_dev->evbit); __set_bit(EV_LED, input_dev->evbit);
set_bit (EV_SND, input_dev->evbit); __set_bit(EV_SND, input_dev->evbit);
set_bit (EV_REP, input_dev->evbit); __set_bit(EV_REP, input_dev->evbit);
set_bit (LED_CAPSL, input_dev->ledbit); __set_bit(LED_CAPSL, input_dev->ledbit);
set_bit (LED_SLEEP, input_dev->ledbit); __set_bit(LED_SLEEP, input_dev->ledbit);
set_bit (LED_COMPOSE, input_dev->ledbit); __set_bit(LED_COMPOSE, input_dev->ledbit);
set_bit (LED_SCROLLL, input_dev->ledbit); __set_bit(LED_SCROLLL, input_dev->ledbit);
set_bit (SND_BELL, input_dev->sndbit); __set_bit(SND_BELL, input_dev->sndbit);
set_bit (SND_CLICK, input_dev->sndbit); __set_bit(SND_CLICK, input_dev->sndbit);
input_dev->keycode = lk->keycode; input_dev->keycode = lk->keycode;
input_dev->keycodesize = sizeof (lk_keycode_t); input_dev->keycodesize = sizeof(lk->keycode[0]);
input_dev->keycodemax = LK_NUM_KEYCODES; input_dev->keycodemax = ARRAY_SIZE(lk->keycode);
for (i = 0; i < LK_NUM_KEYCODES; i++) 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); __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) if (err)
goto fail2; goto fail2;
err = input_register_device (lk->dev); err = input_register_device(lk->dev);
if (err) if (err)
goto fail3; goto fail3;
serio_write (lk->serio, LK_CMD_POWERCYCLE_RESET); serio_write(lk->serio, LK_CMD_POWERCYCLE_RESET);
return 0; return 0;
fail3: serio_close (serio); fail3: serio_close(serio);
fail2: serio_set_drvdata (serio, NULL); fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device (input_dev); fail1: input_free_device(input_dev);
kfree (lk); kfree(lk);
return err; return err;
} }
/* /*
* lkkbd_disconnect() unregisters and closes behind us. * lkkbd_disconnect() unregisters and closes behind us.
*/ */
static void static void lkkbd_disconnect(struct serio *serio)
lkkbd_disconnect (struct serio *serio)
{ {
struct lkkbd *lk = serio_get_drvdata (serio); struct lkkbd *lk = serio_get_drvdata(serio);
input_get_device (lk->dev); input_get_device(lk->dev);
input_unregister_device (lk->dev); input_unregister_device(lk->dev);
serio_close (serio); serio_close(serio);
serio_set_drvdata (serio, NULL); serio_set_drvdata(serio, NULL);
input_put_device (lk->dev); input_put_device(lk->dev);
kfree (lk); kfree(lk);
} }
static struct serio_device_id lkkbd_serio_ids[] = { static struct serio_device_id lkkbd_serio_ids[] = {
...@@ -752,18 +734,16 @@ static struct serio_driver lkkbd_drv = { ...@@ -752,18 +734,16 @@ static struct serio_driver lkkbd_drv = {
/* /*
* The functions for insering/removing us as a module. * The functions for insering/removing us as a module.
*/ */
static int __init static int __init lkkbd_init(void)
lkkbd_init (void)
{ {
return serio_register_driver(&lkkbd_drv); return serio_register_driver(&lkkbd_drv);
} }
static void __exit static void __exit lkkbd_exit(void)
lkkbd_exit (void)
{ {
serio_unregister_driver(&lkkbd_drv); serio_unregister_driver(&lkkbd_drv);
} }
module_init (lkkbd_init); module_init(lkkbd_init);
module_exit (lkkbd_exit); module_exit(lkkbd_exit);
...@@ -213,8 +213,9 @@ static void matrix_keypad_stop(struct input_dev *dev) ...@@ -213,8 +213,9 @@ static void matrix_keypad_stop(struct input_dev *dev)
} }
#ifdef CONFIG_PM #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); struct matrix_keypad *keypad = platform_get_drvdata(pdev);
const struct matrix_keypad_platform_data *pdata = keypad->pdata; const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i; int i;
...@@ -228,8 +229,9 @@ static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t stat ...@@ -228,8 +229,9 @@ static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t stat
return 0; 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); struct matrix_keypad *keypad = platform_get_drvdata(pdev);
const struct matrix_keypad_platform_data *pdata = keypad->pdata; const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i; int i;
...@@ -242,9 +244,9 @@ static int matrix_keypad_resume(struct platform_device *pdev) ...@@ -242,9 +244,9 @@ static int matrix_keypad_resume(struct platform_device *pdev)
return 0; return 0;
} }
#else
#define matrix_keypad_suspend NULL static const SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
#define matrix_keypad_resume NULL matrix_keypad_suspend, matrix_keypad_resume);
#endif #endif
static int __devinit init_matrix_gpio(struct platform_device *pdev, static int __devinit init_matrix_gpio(struct platform_device *pdev,
...@@ -417,11 +419,12 @@ static int __devexit matrix_keypad_remove(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 = { static struct platform_driver matrix_keypad_driver = {
.probe = matrix_keypad_probe, .probe = matrix_keypad_probe,
.remove = __devexit_p(matrix_keypad_remove), .remove = __devexit_p(matrix_keypad_remove),
.suspend = matrix_keypad_suspend,
.resume = matrix_keypad_resume,
.driver = { .driver = {
.name = "matrix-keypad", .name = "matrix-keypad",
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &matrix_keypad_pm_ops,
#endif
}, },
}; };
......
...@@ -80,6 +80,7 @@ config INPUT_WISTRON_BTNS ...@@ -80,6 +80,7 @@ config INPUT_WISTRON_BTNS
tristate "x86 Wistron laptop button interface" tristate "x86 Wistron laptop button interface"
depends on X86 && !X86_64 depends on X86 && !X86_64
select INPUT_POLLDEV select INPUT_POLLDEV
select INPUT_SPARSEKMAP
select NEW_LEDS select NEW_LEDS
select LEDS_CLASS select LEDS_CLASS
select CHECK_SIGNATURE select CHECK_SIGNATURE
...@@ -281,6 +282,7 @@ config INPUT_RB532_BUTTON ...@@ -281,6 +282,7 @@ config INPUT_RB532_BUTTON
config INPUT_DM355EVM config INPUT_DM355EVM
tristate "TI DaVinci DM355 EVM Keypad and IR Remote" tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
depends on MFD_DM355EVM_MSP depends on MFD_DM355EVM_MSP
select INPUT_SPARSEKMAP
help help
Supports the pushbuttons and IR remote used with Supports the pushbuttons and IR remote used with
the DM355 EVM board. the DM355 EVM board.
......
...@@ -766,7 +766,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de ...@@ -766,7 +766,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
ati_remote->interface = interface; ati_remote->interface = interface;
usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); 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) if (udev->manufacturer)
strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name));
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -33,12 +34,8 @@ struct dm355evm_keys { ...@@ -33,12 +34,8 @@ struct dm355evm_keys {
int irq; int irq;
}; };
/* These initial keycodes can be remapped by dm355evm_setkeycode(). */ /* These initial keycodes can be remapped */
static struct { static const struct key_entry dm355evm_keys[] = {
u16 event;
u16 keycode;
} dm355evm_keys[] = {
/* /*
* Pushbuttons on the EVM board ... note that the labels for these * Pushbuttons on the EVM board ... note that the labels for these
* are SW10/SW11/etc on the PC board. The left/right orientation * are SW10/SW11/etc on the PC board. The left/right orientation
...@@ -47,11 +44,11 @@ static struct { ...@@ -47,11 +44,11 @@ static struct {
* is to the right. (That is, rotate the board counter-clockwise * is to the right. (That is, rotate the board counter-clockwise
* by 90 degrees from the SW10/etc and "DM355 EVM" labels.) * by 90 degrees from the SW10/etc and "DM355 EVM" labels.)
*/ */
{ 0x00d8, KEY_OK, }, /* SW12 */ { KE_KEY, 0x00d8, { KEY_OK } }, /* SW12 */
{ 0x00b8, KEY_UP, }, /* SW13 */ { KE_KEY, 0x00b8, { KEY_UP } }, /* SW13 */
{ 0x00e8, KEY_DOWN, }, /* SW11 */ { KE_KEY, 0x00e8, { KEY_DOWN } }, /* SW11 */
{ 0x0078, KEY_LEFT, }, /* SW14 */ { KE_KEY, 0x0078, { KEY_LEFT } }, /* SW14 */
{ 0x00f0, KEY_RIGHT, }, /* SW10 */ { KE_KEY, 0x00f0, { KEY_RIGHT } }, /* SW10 */
/* /*
* IR buttons ... codes assigned to match the universal remote * IR buttons ... codes assigned to match the universal remote
...@@ -65,35 +62,35 @@ static struct { ...@@ -65,35 +62,35 @@ static struct {
* RC5 codes are 14 bits, with two start bits (0x3 prefix) * RC5 codes are 14 bits, with two start bits (0x3 prefix)
* and a toggle bit (masked out below). * and a toggle bit (masked out below).
*/ */
{ 0x300c, KEY_POWER, }, /* NOTE: docs omit this */ { KE_KEY, 0x300c, { KEY_POWER } }, /* NOTE: docs omit this */
{ 0x3000, KEY_NUMERIC_0, }, { KE_KEY, 0x3000, { KEY_NUMERIC_0 } },
{ 0x3001, KEY_NUMERIC_1, }, { KE_KEY, 0x3001, { KEY_NUMERIC_1 } },
{ 0x3002, KEY_NUMERIC_2, }, { KE_KEY, 0x3002, { KEY_NUMERIC_2 } },
{ 0x3003, KEY_NUMERIC_3, }, { KE_KEY, 0x3003, { KEY_NUMERIC_3 } },
{ 0x3004, KEY_NUMERIC_4, }, { KE_KEY, 0x3004, { KEY_NUMERIC_4 } },
{ 0x3005, KEY_NUMERIC_5, }, { KE_KEY, 0x3005, { KEY_NUMERIC_5 } },
{ 0x3006, KEY_NUMERIC_6, }, { KE_KEY, 0x3006, { KEY_NUMERIC_6 } },
{ 0x3007, KEY_NUMERIC_7, }, { KE_KEY, 0x3007, { KEY_NUMERIC_7 } },
{ 0x3008, KEY_NUMERIC_8, }, { KE_KEY, 0x3008, { KEY_NUMERIC_8 } },
{ 0x3009, KEY_NUMERIC_9, }, { KE_KEY, 0x3009, { KEY_NUMERIC_9 } },
{ 0x3022, KEY_ENTER, }, { KE_KEY, 0x3022, { KEY_ENTER } },
{ 0x30ec, KEY_MODE, }, /* "tv/vcr/..." */ { KE_KEY, 0x30ec, { KEY_MODE } }, /* "tv/vcr/..." */
{ 0x300f, KEY_SELECT, }, /* "info" */ { KE_KEY, 0x300f, { KEY_SELECT } }, /* "info" */
{ 0x3020, KEY_CHANNELUP, }, /* "up" */ { KE_KEY, 0x3020, { KEY_CHANNELUP } }, /* "up" */
{ 0x302e, KEY_MENU, }, /* "in/out" */ { KE_KEY, 0x302e, { KEY_MENU } }, /* "in/out" */
{ 0x3011, KEY_VOLUMEDOWN, }, /* "left" */ { KE_KEY, 0x3011, { KEY_VOLUMEDOWN } }, /* "left" */
{ 0x300d, KEY_MUTE, }, /* "ok" */ { KE_KEY, 0x300d, { KEY_MUTE } }, /* "ok" */
{ 0x3010, KEY_VOLUMEUP, }, /* "right" */ { KE_KEY, 0x3010, { KEY_VOLUMEUP } }, /* "right" */
{ 0x301e, KEY_SUBTITLE, }, /* "cc" */ { KE_KEY, 0x301e, { KEY_SUBTITLE } }, /* "cc" */
{ 0x3021, KEY_CHANNELDOWN, }, /* "down" */ { KE_KEY, 0x3021, { KEY_CHANNELDOWN } },/* "down" */
{ 0x3022, KEY_PREVIOUS, }, { KE_KEY, 0x3022, { KEY_PREVIOUS } },
{ 0x3026, KEY_SLEEP, }, { KE_KEY, 0x3026, { KEY_SLEEP } },
{ 0x3172, KEY_REWIND, }, /* NOTE: docs wrongly say 0x30ca */ { KE_KEY, 0x3172, { KEY_REWIND } }, /* NOTE: docs wrongly say 0x30ca */
{ 0x3175, KEY_PLAY, }, { KE_KEY, 0x3175, { KEY_PLAY } },
{ 0x3174, KEY_FASTFORWARD, }, { KE_KEY, 0x3174, { KEY_FASTFORWARD } },
{ 0x3177, KEY_RECORD, }, { KE_KEY, 0x3177, { KEY_RECORD } },
{ 0x3176, KEY_STOP, }, { KE_KEY, 0x3176, { KEY_STOP } },
{ 0x3169, KEY_PAUSE, }, { KE_KEY, 0x3169, { KEY_PAUSE } },
}; };
/* /*
...@@ -105,19 +102,18 @@ static struct { ...@@ -105,19 +102,18 @@ static struct {
*/ */
static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
{ {
struct dm355evm_keys *keys = _keys; static u16 last_event;
int status; 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 /* For simplicity we ignore INPUT_COUNT and just read
* events until we get the "queue empty" indicator. * events until we get the "queue empty" indicator.
* Reading INPUT_LOW decrements the count. * Reading INPUT_LOW decrements the count.
*/ */
for (;;) { for (;;) {
static u16 last_event;
u16 event;
int keycode;
int i;
status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH); status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH);
if (status < 0) { if (status < 0) {
dev_dbg(keys->dev, "input high err %d\n", dev_dbg(keys->dev, "input high err %d\n",
...@@ -156,14 +152,9 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) ...@@ -156,14 +152,9 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
/* ignore the RC5 toggle bit */ /* ignore the RC5 toggle bit */
event &= ~0x0800; event &= ~0x0800;
/* find the key, or leave it as unknown */ /* find the key, or report it as unknown */
keycode = KEY_UNKNOWN; ke = sparse_keymap_entry_from_scancode(keys->input, event);
for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { keycode = ke ? ke->keycode : KEY_UNKNOWN;
if (dm355evm_keys[i].event != event)
continue;
keycode = dm355evm_keys[i].keycode;
break;
}
dev_dbg(keys->dev, dev_dbg(keys->dev,
"input event 0x%04x--> keycode %d\n", "input event 0x%04x--> keycode %d\n",
event, keycode); event, keycode);
...@@ -174,36 +165,8 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) ...@@ -174,36 +165,8 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
input_report_key(keys->input, keycode, 0); input_report_key(keys->input, keycode, 0);
input_sync(keys->input); input_sync(keys->input);
} }
return IRQ_HANDLED;
}
static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode) return IRQ_HANDLED;
{
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;
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
...@@ -213,7 +176,6 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev) ...@@ -213,7 +176,6 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
struct dm355evm_keys *keys; struct dm355evm_keys *keys;
struct input_dev *input; struct input_dev *input;
int status; int status;
int i;
/* allocate instance struct and input dev */ /* allocate instance struct and input dev */
keys = kzalloc(sizeof *keys, GFP_KERNEL); keys = kzalloc(sizeof *keys, GFP_KERNEL);
...@@ -242,31 +204,30 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev) ...@@ -242,31 +204,30 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
input->id.product = 0x0355; input->id.product = 0x0355;
input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV); input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
input->evbit[0] = BIT(EV_KEY); status = sparse_keymap_setup(input, dm355evm_keys, NULL);
for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) if (status)
__set_bit(dm355evm_keys[i].keycode, input->keybit); goto fail1;
input->setkeycode = dm355evm_setkeycode;
input->getkeycode = dm355evm_getkeycode;
/* REVISIT: flush the event queue? */ /* REVISIT: flush the event queue? */
status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq, status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq,
IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys); IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys);
if (status < 0) if (status < 0)
goto fail1; goto fail2;
/* register */ /* register */
status = input_register_device(input); status = input_register_device(input);
if (status < 0) if (status < 0)
goto fail2; goto fail3;
platform_set_drvdata(pdev, keys); platform_set_drvdata(pdev, keys);
return 0; return 0;
fail2: fail3:
free_irq(keys->irq, keys); free_irq(keys->irq, keys);
fail2:
sparse_keymap_free(input);
fail1: fail1:
input_free_device(input); input_free_device(input);
kfree(keys); kfree(keys);
...@@ -280,6 +241,7 @@ static int __devexit dm355evm_keys_remove(struct platform_device *pdev) ...@@ -280,6 +241,7 @@ static int __devexit dm355evm_keys_remove(struct platform_device *pdev)
struct dm355evm_keys *keys = platform_get_drvdata(pdev); struct dm355evm_keys *keys = platform_get_drvdata(pdev);
free_irq(keys->irq, keys); free_irq(keys->irq, keys);
sparse_keymap_free(keys->input);
input_unregister_device(keys->input); input_unregister_device(keys->input);
kfree(keys); kfree(keys);
......
...@@ -338,7 +338,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -338,7 +338,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
pm->input = input_dev; pm->input = input_dev;
usb_make_path(udev, pm->phys, sizeof(pm->phys)); 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); spin_lock_init(&pm->lock);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/input-polldev.h> #include <linux/input-polldev.h>
#include <linux/input/sparse-keymap.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -224,19 +225,8 @@ static void bios_set_state(u8 subsys, int enable) ...@@ -224,19 +225,8 @@ static void bios_set_state(u8 subsys, int enable)
/* Hardware database */ /* Hardware database */
struct key_entry { #define KE_WIFI (KE_LAST + 1)
char type; /* See KE_* below */ #define KE_BLUETOOTH (KE_LAST + 2)
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 FE_MAIL_LED 0x01 #define FE_MAIL_LED 0x01
#define FE_WIFI_LED 0x02 #define FE_WIFI_LED 0x02
...@@ -644,10 +634,10 @@ static struct key_entry keymap_prestigio[] __initdata = { ...@@ -644,10 +634,10 @@ static struct key_entry keymap_prestigio[] __initdata = {
* a list of buttons and their key codes (reported when loading this module * a list of buttons and their key codes (reported when loading this module
* with force=1) and the output of dmidecode to $MODULE_AUTHOR. * 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, .callback = dmi_matched,
.ident = "Fujitsu-Siemens Amilo Pro V2000",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"),
...@@ -655,8 +645,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -655,8 +645,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_fs_amilo_pro_v2000 .driver_data = keymap_fs_amilo_pro_v2000
}, },
{ {
/* Fujitsu-Siemens Amilo Pro Edition V3505 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Fujitsu-Siemens Amilo Pro Edition V3505",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"),
...@@ -664,8 +654,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -664,8 +654,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_fs_amilo_pro_v3505 .driver_data = keymap_fs_amilo_pro_v3505
}, },
{ {
/* Fujitsu-Siemens Amilo M7400 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Fujitsu-Siemens Amilo M7400",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "),
...@@ -673,8 +663,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -673,8 +663,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_fs_amilo_pro_v2000 .driver_data = keymap_fs_amilo_pro_v2000
}, },
{ {
/* Maxdata Pro 7000 DX */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Maxdata Pro 7000 DX",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"), DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"),
DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"), DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"),
...@@ -682,8 +672,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -682,8 +672,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_fs_amilo_pro_v2000 .driver_data = keymap_fs_amilo_pro_v2000
}, },
{ {
/* Fujitsu N3510 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Fujitsu N3510",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "N3510"), DMI_MATCH(DMI_PRODUCT_NAME, "N3510"),
...@@ -691,8 +681,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -691,8 +681,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_fujitsu_n3510 .driver_data = keymap_fujitsu_n3510
}, },
{ {
/* Acer Aspire 1500 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer Aspire 1500",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"),
...@@ -700,8 +690,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -700,8 +690,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_aspire_1500 .driver_data = keymap_acer_aspire_1500
}, },
{ {
/* Acer Aspire 1600 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer Aspire 1600",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"),
...@@ -709,8 +699,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -709,8 +699,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_aspire_1600 .driver_data = keymap_acer_aspire_1600
}, },
{ {
/* Acer Aspire 3020 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer Aspire 3020",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
...@@ -718,8 +708,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -718,8 +708,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_aspire_5020 .driver_data = keymap_acer_aspire_5020
}, },
{ {
/* Acer Aspire 5020 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer Aspire 5020",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
...@@ -727,8 +717,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -727,8 +717,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_aspire_5020 .driver_data = keymap_acer_aspire_5020
}, },
{ {
/* Acer TravelMate 2100 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 2100",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"),
...@@ -736,8 +726,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -736,8 +726,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_aspire_5020 .driver_data = keymap_acer_aspire_5020
}, },
{ {
/* Acer TravelMate 2410 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 2410",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"),
...@@ -745,8 +735,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -745,8 +735,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_2410 .driver_data = keymap_acer_travelmate_2410
}, },
{ {
/* Acer TravelMate C300 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate C300",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"),
...@@ -754,8 +744,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -754,8 +744,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_300 .driver_data = keymap_acer_travelmate_300
}, },
{ {
/* Acer TravelMate C100 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate C100",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"),
...@@ -763,8 +753,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -763,8 +753,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_300 .driver_data = keymap_acer_travelmate_300
}, },
{ {
/* Acer TravelMate C110 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate C110",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"),
...@@ -772,8 +762,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -772,8 +762,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_110 .driver_data = keymap_acer_travelmate_110
}, },
{ {
/* Acer TravelMate 380 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 380",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"),
...@@ -781,8 +771,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -781,8 +771,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_380 .driver_data = keymap_acer_travelmate_380
}, },
{ {
/* Acer TravelMate 370 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 370",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"),
...@@ -790,8 +780,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -790,8 +780,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */ .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
}, },
{ {
/* Acer TravelMate 220 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 220",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"),
...@@ -799,8 +789,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -799,8 +789,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_220 .driver_data = keymap_acer_travelmate_220
}, },
{ {
/* Acer TravelMate 260 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 260",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"),
...@@ -808,8 +798,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -808,8 +798,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_220 .driver_data = keymap_acer_travelmate_220
}, },
{ {
/* Acer TravelMate 230 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 230",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"),
...@@ -818,8 +808,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -818,8 +808,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_230 .driver_data = keymap_acer_travelmate_230
}, },
{ {
/* Acer TravelMate 280 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 280",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"),
...@@ -827,8 +817,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -827,8 +817,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_230 .driver_data = keymap_acer_travelmate_230
}, },
{ {
/* Acer TravelMate 240 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 240",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"),
...@@ -836,8 +826,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -836,8 +826,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_240 .driver_data = keymap_acer_travelmate_240
}, },
{ {
/* Acer TravelMate 250 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 250",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"),
...@@ -845,8 +835,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -845,8 +835,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_240 .driver_data = keymap_acer_travelmate_240
}, },
{ {
/* Acer TravelMate 2424NWXCi */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 2424NWXCi",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
...@@ -854,8 +844,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -854,8 +844,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_240 .driver_data = keymap_acer_travelmate_240
}, },
{ {
/* Acer TravelMate 350 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 350",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"),
...@@ -863,8 +853,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -863,8 +853,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_350 .driver_data = keymap_acer_travelmate_350
}, },
{ {
/* Acer TravelMate 360 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 360",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
...@@ -872,8 +862,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -872,8 +862,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_360 .driver_data = keymap_acer_travelmate_360
}, },
{ {
/* Acer TravelMate 610 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 610",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ACER"), DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"),
...@@ -881,8 +871,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -881,8 +871,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_610 .driver_data = keymap_acer_travelmate_610
}, },
{ {
/* Acer TravelMate 620 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 620",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"),
...@@ -890,8 +880,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -890,8 +880,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_630 .driver_data = keymap_acer_travelmate_630
}, },
{ {
/* Acer TravelMate 630 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer TravelMate 630",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"),
...@@ -899,8 +889,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -899,8 +889,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_acer_travelmate_630 .driver_data = keymap_acer_travelmate_630
}, },
{ {
/* AOpen 1559AS */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "AOpen 1559AS",
.matches = { .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "E2U"), DMI_MATCH(DMI_PRODUCT_NAME, "E2U"),
DMI_MATCH(DMI_BOARD_NAME, "E2U"), DMI_MATCH(DMI_BOARD_NAME, "E2U"),
...@@ -908,8 +898,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -908,8 +898,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_aopen_1559as .driver_data = keymap_aopen_1559as
}, },
{ {
/* Medion MD 9783 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Medion MD 9783",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"), DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"),
...@@ -917,8 +907,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -917,8 +907,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_wistron_ms2111 .driver_data = keymap_wistron_ms2111
}, },
{ {
/* Medion MD 40100 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Medion MD 40100",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"), DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"),
...@@ -926,8 +916,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -926,8 +916,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_wistron_md40100 .driver_data = keymap_wistron_md40100
}, },
{ {
/* Medion MD 2900 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Medion MD 2900",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"),
...@@ -935,8 +925,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -935,8 +925,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_wistron_md2900 .driver_data = keymap_wistron_md2900
}, },
{ {
/* Medion MD 42200 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Medion MD 42200",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Medion"), DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"),
...@@ -944,8 +934,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -944,8 +934,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_fs_amilo_pro_v2000 .driver_data = keymap_fs_amilo_pro_v2000
}, },
{ {
/* Medion MD 96500 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Medion MD 96500",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"),
...@@ -953,8 +943,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -953,8 +943,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_wistron_md96500 .driver_data = keymap_wistron_md96500
}, },
{ {
/* Medion MD 95400 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Medion MD 95400",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"),
...@@ -962,8 +952,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -962,8 +952,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_wistron_md96500 .driver_data = keymap_wistron_md96500
}, },
{ {
/* Fujitsu Siemens Amilo D7820 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Fujitsu Siemens Amilo D7820",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */
DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"), DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"),
...@@ -971,8 +961,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -971,8 +961,8 @@ static struct dmi_system_id dmi_ids[] __initdata = {
.driver_data = keymap_fs_amilo_d88x0 .driver_data = keymap_fs_amilo_d88x0
}, },
{ {
/* Fujitsu Siemens Amilo D88x0 */
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Fujitsu Siemens Amilo D88x0",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"),
...@@ -1037,21 +1027,6 @@ static unsigned long jiffies_last_press; ...@@ -1037,21 +1027,6 @@ static unsigned long jiffies_last_press;
static bool wifi_enabled; static bool wifi_enabled;
static bool bluetooth_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 */ /* led management */
static void wistron_mail_led_set(struct led_classdev *led_cdev, static void wistron_mail_led_set(struct led_classdev *led_cdev,
enum led_brightness value) enum led_brightness value)
...@@ -1128,43 +1103,13 @@ static inline void wistron_led_resume(void) ...@@ -1128,43 +1103,13 @@ static inline void wistron_led_resume(void)
led_classdev_resume(&wistron_wifi_led); 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) 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) { if (key) {
switch (key->type) { 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: case KE_WIFI:
if (have_wifi) { if (have_wifi) {
wifi_enabled = !wifi_enabled; wifi_enabled = !wifi_enabled;
...@@ -1180,7 +1125,9 @@ static void handle_key(u8 code) ...@@ -1180,7 +1125,9 @@ static void handle_key(u8 code)
break; break;
default: default:
BUG(); sparse_keymap_report_entry(wistron_idev->input,
key, 1, true);
break;
} }
jiffies_last_press = jiffies; jiffies_last_press = jiffies;
} else } else
...@@ -1220,42 +1167,39 @@ static void wistron_poll(struct input_polled_dev *dev) ...@@ -1220,42 +1167,39 @@ static void wistron_poll(struct input_polled_dev *dev)
dev->poll_interval = POLL_INTERVAL_DEFAULT; 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) { /* if wifi or bluetooth are not available, create normal keys */
*keycode = key->keycode; case KE_WIFI:
return 0; if (!have_wifi) {
} entry->type = KE_KEY;
entry->keycode = KEY_WLAN;
return -EINVAL; }
} break;
static int wistron_setkeycode(struct input_dev *dev, int scancode, int keycode) case KE_BLUETOOTH:
{ if (!have_bluetooth) {
struct key_entry *key; entry->type = KE_KEY;
int old_keycode; entry->keycode = KEY_BLUETOOTH;
}
if (keycode < 0 || keycode > KEY_MAX) break;
return -EINVAL;
case KE_END:
key = wistron_get_entry_by_scancode(scancode); if (entry->code & FE_UNTESTED)
if (key && key->type == KE_KEY) { printk(KERN_WARNING "Untested laptop multimedia keys, "
old_keycode = key->keycode; "please report success or failure to "
key->keycode = keycode; "eric.piel@tremplin-utc.net\n");
set_bit(keycode, dev->keybit); break;
if (!wistron_get_entry_by_keycode(old_keycode))
clear_bit(old_keycode, dev->keybit);
return 0;
} }
return -EINVAL; return 0;
} }
static int __devinit setup_input_dev(void) static int __devinit setup_input_dev(void)
{ {
struct key_entry *key;
struct input_dev *input_dev; struct input_dev *input_dev;
int error; int error;
...@@ -1263,7 +1207,7 @@ static int __devinit setup_input_dev(void) ...@@ -1263,7 +1207,7 @@ static int __devinit setup_input_dev(void)
if (!wistron_idev) if (!wistron_idev)
return -ENOMEM; return -ENOMEM;
wistron_idev->flush = wistron_flush; wistron_idev->open = wistron_flush;
wistron_idev->poll = wistron_poll; wistron_idev->poll = wistron_poll;
wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT; wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT;
...@@ -1273,56 +1217,21 @@ static int __devinit setup_input_dev(void) ...@@ -1273,56 +1217,21 @@ static int __devinit setup_input_dev(void)
input_dev->id.bustype = BUS_HOST; input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &wistron_device->dev; input_dev->dev.parent = &wistron_device->dev;
input_dev->getkeycode = wistron_getkeycode; error = sparse_keymap_setup(input_dev, keymap, wistron_setup_keymap);
input_dev->setkeycode = wistron_setkeycode; if (error)
goto err_free_dev;
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 = input_register_polled_device(wistron_idev); error = input_register_polled_device(wistron_idev);
if (error) { if (error)
input_free_polled_device(wistron_idev); goto err_free_keymap;
return error;
}
return 0; return 0;
err_free_keymap:
sparse_keymap_free(input_dev);
err_free_dev:
input_free_polled_device(wistron_idev);
return error;
} }
/* Driver core */ /* Driver core */
...@@ -1371,6 +1280,7 @@ static int __devexit wistron_remove(struct platform_device *dev) ...@@ -1371,6 +1280,7 @@ static int __devexit wistron_remove(struct platform_device *dev)
{ {
wistron_led_remove(); wistron_led_remove();
input_unregister_polled_device(wistron_idev); input_unregister_polled_device(wistron_idev);
sparse_keymap_free(wistron_idev->input);
input_free_polled_device(wistron_idev); input_free_polled_device(wistron_idev);
bios_detach(); bios_detach();
......
...@@ -28,13 +28,16 @@ ...@@ -28,13 +28,16 @@
#define dbg(format, arg...) do {} while (0) #define dbg(format, arg...) do {} while (0)
#endif #endif
#define ALPS_DUALPOINT 0x01
#define ALPS_WHEEL 0x02 #define ALPS_OLDPROTO 0x01 /* old style input */
#define ALPS_FW_BK_1 0x04 #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
#define ALPS_4BTN 0x08 #define ALPS_PASS 0x04 /* device has a pass-through port */
#define ALPS_OLDPROTO 0x10
#define ALPS_PASS 0x20 #define ALPS_WHEEL 0x08 /* hardware wheel present */
#define ALPS_FW_BK_2 0x40 #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[] = { static const struct alps_model_info alps_model_data[] = {
{ { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ { { 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[] = { ...@@ -56,7 +59,7 @@ static const struct alps_model_info alps_model_data[] = {
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ { { 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[] = { ...@@ -83,6 +86,7 @@ static const struct alps_model_info alps_model_data[] = {
static void alps_process_packet(struct psmouse *psmouse) static void alps_process_packet(struct psmouse *psmouse)
{ {
struct alps_data *priv = psmouse->private; struct alps_data *priv = psmouse->private;
const struct alps_model_info *model = priv->i;
unsigned char *packet = psmouse->packet; unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev; struct input_dev *dev = psmouse->dev;
struct input_dev *dev2 = priv->dev2; struct input_dev *dev2 = priv->dev2;
...@@ -101,7 +105,7 @@ static void alps_process_packet(struct psmouse *psmouse) ...@@ -101,7 +105,7 @@ static void alps_process_packet(struct psmouse *psmouse)
return; return;
} }
if (priv->i->flags & ALPS_OLDPROTO) { if (model->flags & ALPS_OLDPROTO) {
left = packet[2] & 0x10; left = packet[2] & 0x10;
right = packet[2] & 0x08; right = packet[2] & 0x08;
middle = 0; middle = 0;
...@@ -117,12 +121,12 @@ static void alps_process_packet(struct psmouse *psmouse) ...@@ -117,12 +121,12 @@ static void alps_process_packet(struct psmouse *psmouse)
z = packet[5]; z = packet[5];
} }
if (priv->i->flags & ALPS_FW_BK_1) { if (model->flags & ALPS_FW_BK_1) {
back = packet[0] & 0x10; back = packet[0] & 0x10;
forward = packet[2] & 4; forward = packet[2] & 4;
} }
if (priv->i->flags & ALPS_FW_BK_2) { if (model->flags & ALPS_FW_BK_2) {
back = packet[3] & 4; back = packet[3] & 4;
forward = packet[2] & 4; forward = packet[2] & 4;
if ((middle = forward && back)) if ((middle = forward && back))
...@@ -132,7 +136,7 @@ static void alps_process_packet(struct psmouse *psmouse) ...@@ -132,7 +136,7 @@ static void alps_process_packet(struct psmouse *psmouse)
ges = packet[2] & 1; ges = packet[2] & 1;
fin = packet[2] & 2; 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_X, (x > 383 ? (x - 768) : x));
input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
...@@ -150,7 +154,8 @@ static void alps_process_packet(struct psmouse *psmouse) ...@@ -150,7 +154,8 @@ static void alps_process_packet(struct psmouse *psmouse)
input_report_key(dev, BTN_MIDDLE, middle); input_report_key(dev, BTN_MIDDLE, middle);
/* Convert hardware tap to a reasonable Z value */ /* 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 * 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) ...@@ -166,8 +171,10 @@ static void alps_process_packet(struct psmouse *psmouse)
} }
priv->prev_fin = fin; priv->prev_fin = fin;
if (z > 30) input_report_key(dev, BTN_TOUCH, 1); if (z > 30)
if (z < 25) input_report_key(dev, BTN_TOUCH, 0); input_report_key(dev, BTN_TOUCH, 1);
if (z < 25)
input_report_key(dev, BTN_TOUCH, 0);
if (z > 0) { if (z > 0) {
input_report_abs(dev, ABS_X, x); input_report_abs(dev, ABS_X, x);
...@@ -177,14 +184,21 @@ static void alps_process_packet(struct psmouse *psmouse) ...@@ -177,14 +184,21 @@ static void alps_process_packet(struct psmouse *psmouse)
input_report_abs(dev, ABS_PRESSURE, z); input_report_abs(dev, ABS_PRESSURE, z);
input_report_key(dev, BTN_TOOL_FINGER, z > 0); 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)); 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_FORWARD, forward);
input_report_key(dev, BTN_BACK, back); 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); input_sync(dev);
} }
...@@ -393,15 +407,12 @@ static int alps_poll(struct psmouse *psmouse) ...@@ -393,15 +407,12 @@ static int alps_poll(struct psmouse *psmouse)
return 0; 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; struct alps_data *priv = psmouse->private;
const struct alps_model_info *model = priv->i;
priv->i = alps_get_model(psmouse, version); if ((model->flags & ALPS_PASS) &&
if (!priv->i)
return -1;
if ((priv->i->flags & ALPS_PASS) &&
alps_passthrough_mode(psmouse, true)) { alps_passthrough_mode(psmouse, true)) {
return -1; return -1;
} }
...@@ -416,7 +427,7 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) ...@@ -416,7 +427,7 @@ static int alps_hw_init(struct psmouse *psmouse, int *version)
return -1; return -1;
} }
if ((priv->i->flags & ALPS_PASS) && if ((model->flags & ALPS_PASS) &&
alps_passthrough_mode(psmouse, false)) { alps_passthrough_mode(psmouse, false)) {
return -1; return -1;
} }
...@@ -432,12 +443,15 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) ...@@ -432,12 +443,15 @@ static int alps_hw_init(struct psmouse *psmouse, int *version)
static int alps_reconnect(struct psmouse *psmouse) static int alps_reconnect(struct psmouse *psmouse)
{ {
const struct alps_model_info *model;
psmouse_reset(psmouse); psmouse_reset(psmouse);
if (alps_hw_init(psmouse, NULL)) model = alps_get_model(psmouse, NULL);
if (!model)
return -1; return -1;
return 0; return alps_hw_init(psmouse);
} }
static void alps_disconnect(struct psmouse *psmouse) static void alps_disconnect(struct psmouse *psmouse)
...@@ -452,6 +466,7 @@ static void alps_disconnect(struct psmouse *psmouse) ...@@ -452,6 +466,7 @@ static void alps_disconnect(struct psmouse *psmouse)
int alps_init(struct psmouse *psmouse) int alps_init(struct psmouse *psmouse)
{ {
struct alps_data *priv; struct alps_data *priv;
const struct alps_model_info *model;
struct input_dev *dev1 = psmouse->dev, *dev2; struct input_dev *dev1 = psmouse->dev, *dev2;
int version; int version;
...@@ -463,33 +478,48 @@ int alps_init(struct psmouse *psmouse) ...@@ -463,33 +478,48 @@ int alps_init(struct psmouse *psmouse)
priv->dev2 = dev2; priv->dev2 = dev2;
psmouse->private = priv; 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; goto init_fail;
dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); 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_TOUCH)] |= BIT_MASK(BTN_TOUCH);
dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER);
dev1->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | dev1->keybit[BIT_WORD(BTN_LEFT)] |=
BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); 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_X, 0, 1023, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 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->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); 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_FORWARD)] |= BIT_MASK(BTN_FORWARD);
dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); 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); snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
dev2->phys = priv->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.bustype = BUS_I8042;
dev2->id.vendor = 0x0002; dev2->id.vendor = 0x0002;
dev2->id.product = PSMOUSE_ALPS; dev2->id.product = PSMOUSE_ALPS;
...@@ -497,9 +527,9 @@ int alps_init(struct psmouse *psmouse) ...@@ -497,9 +527,9 @@ int alps_init(struct psmouse *psmouse)
dev2->dev.parent = &psmouse->ps2dev.serio->dev; dev2->dev.parent = &psmouse->ps2dev.serio->dev;
dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); 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->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
dev2->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | dev2->keybit[BIT_WORD(BTN_LEFT)] =
BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
if (input_register_device(priv->dev2)) if (input_register_device(priv->dev2))
goto init_fail; goto init_fail;
......
...@@ -420,6 +420,7 @@ static void elantech_set_input_params(struct psmouse *psmouse) ...@@ -420,6 +420,7 @@ static void elantech_set_input_params(struct psmouse *psmouse)
__set_bit(EV_KEY, dev->evbit); __set_bit(EV_KEY, dev->evbit);
__set_bit(EV_ABS, dev->evbit); __set_bit(EV_ABS, dev->evbit);
__clear_bit(EV_REL, dev->evbit);
__set_bit(BTN_LEFT, dev->keybit); __set_bit(BTN_LEFT, dev->keybit);
__set_bit(BTN_RIGHT, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit);
......
...@@ -430,19 +430,6 @@ static int hgpk_register(struct psmouse *psmouse) ...@@ -430,19 +430,6 @@ static int hgpk_register(struct psmouse *psmouse)
struct input_dev *dev = psmouse->dev; struct input_dev *dev = psmouse->dev;
int err; 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 */ /* register handlers */
psmouse->protocol_handler = hgpk_process_byte; psmouse->protocol_handler = hgpk_process_byte;
psmouse->poll = hgpk_poll; psmouse->poll = hgpk_poll;
......
...@@ -25,11 +25,13 @@ struct lifebook_data { ...@@ -25,11 +25,13 @@ struct lifebook_data {
char phys[32]; char phys[32];
}; };
static bool lifebook_present;
static const char *desired_serio_phys; 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; return 0;
} }
...@@ -41,53 +43,53 @@ static int lifebook_set_6byte_proto(const struct dmi_system_id *d) ...@@ -41,53 +43,53 @@ static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
return 0; 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 = { .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"), DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"),
}, },
}, },
{ {
.ident = "LifeBook B", /* LifeBook B */
.matches = { .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"),
}, },
}, },
{ {
.ident = "Lifebook B", /* Lifebook B */
.matches = { .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
}, },
}, },
{ {
.ident = "Lifebook B-2130", /* Lifebook B-2130 */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "ZEPHYR"), DMI_MATCH(DMI_BOARD_NAME, "ZEPHYR"),
}, },
}, },
{ {
.ident = "Lifebook B213x/B2150", /* Lifebook B213x/B2150 */
.matches = { .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"),
}, },
}, },
{ {
.ident = "Zephyr", /* Zephyr */
.matches = { .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"), DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"),
}, },
}, },
{ {
.ident = "CF-18", /* Panasonic CF-18 */
.matches = { .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
}, },
.callback = lifebook_set_serio_phys, .callback = lifebook_limit_serio3,
.driver_data = "isa0060/serio3",
}, },
{ {
.ident = "Panasonic CF-28", /* Panasonic CF-28 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"),
...@@ -95,7 +97,7 @@ static const struct dmi_system_id lifebook_dmi_table[] = { ...@@ -95,7 +97,7 @@ static const struct dmi_system_id lifebook_dmi_table[] = {
.callback = lifebook_set_6byte_proto, .callback = lifebook_set_6byte_proto,
}, },
{ {
.ident = "Panasonic CF-29", /* Panasonic CF-29 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
...@@ -103,21 +105,27 @@ static const struct dmi_system_id lifebook_dmi_table[] = { ...@@ -103,21 +105,27 @@ static const struct dmi_system_id lifebook_dmi_table[] = {
.callback = lifebook_set_6byte_proto, .callback = lifebook_set_6byte_proto,
}, },
{ {
.ident = "CF-72", /* Panasonic CF-72 */
.matches = { .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"),
}, },
.callback = lifebook_set_6byte_proto, .callback = lifebook_set_6byte_proto,
}, },
{ {
.ident = "Lifebook B142", /* Lifebook B142 */
.matches = { .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"), 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) static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
{ {
struct lifebook_data *priv = psmouse->private; struct lifebook_data *priv = psmouse->private;
...@@ -198,10 +206,10 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) ...@@ -198,10 +206,10 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
return -1; return -1;
/* /*
Enable absolute output -- ps2_command fails always but if * Enable absolute output -- ps2_command fails always but if
you leave this call out the touchsreen will never send * you leave this call out the touchsreen will never send
absolute coordinates * absolute coordinates
*/ */
param = lifebook_use_6byte_proto ? 0x08 : 0x07; param = lifebook_use_6byte_proto ? 0x08 : 0x07;
ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
...@@ -243,7 +251,7 @@ static void lifebook_disconnect(struct psmouse *psmouse) ...@@ -243,7 +251,7 @@ static void lifebook_disconnect(struct psmouse *psmouse)
int lifebook_detect(struct psmouse *psmouse, bool set_properties) int lifebook_detect(struct psmouse *psmouse, bool set_properties)
{ {
if (!dmi_check_system(lifebook_dmi_table)) if (!lifebook_present)
return -1; return -1;
if (desired_serio_phys && if (desired_serio_phys &&
...@@ -283,8 +291,8 @@ static int lifebook_create_relative_device(struct psmouse *psmouse) ...@@ -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->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->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
dev2->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | dev2->keybit[BIT_WORD(BTN_LEFT)] =
BIT_MASK(BTN_RIGHT); BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
error = input_register_device(priv->dev2); error = input_register_device(priv->dev2);
if (error) if (error)
...@@ -309,6 +317,7 @@ int lifebook_init(struct psmouse *psmouse) ...@@ -309,6 +317,7 @@ int lifebook_init(struct psmouse *psmouse)
dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
dev1->relbit[0] = 0; dev1->relbit[0] = 0;
dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0;
dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 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_X, 0, max_coord, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0); input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
......
...@@ -12,9 +12,13 @@ ...@@ -12,9 +12,13 @@
#define _LIFEBOOK_H #define _LIFEBOOK_H
#ifdef CONFIG_MOUSE_PS2_LIFEBOOK #ifdef CONFIG_MOUSE_PS2_LIFEBOOK
void lifebook_module_init(void);
int lifebook_detect(struct psmouse *psmouse, bool set_properties); int lifebook_detect(struct psmouse *psmouse, bool set_properties);
int lifebook_init(struct psmouse *psmouse); int lifebook_init(struct psmouse *psmouse);
#else #else
inline void lifebook_module_init(void)
{
}
inline int lifebook_detect(struct psmouse *psmouse, bool set_properties) inline int lifebook_detect(struct psmouse *psmouse, bool set_properties)
{ {
return -ENOSYS; return -ENOSYS;
......
...@@ -404,8 +404,8 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) ...@@ -404,8 +404,8 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties)
} }
} }
if (buttons < 3) if (buttons >= 3)
__clear_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
if (model_info) if (model_info)
ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
......
...@@ -425,6 +425,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties) ...@@ -425,6 +425,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties)
return -1; return -1;
if (set_properties) { if (set_properties) {
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
__set_bit(BTN_EXTRA, psmouse->dev->keybit); __set_bit(BTN_EXTRA, psmouse->dev->keybit);
__set_bit(BTN_SIDE, psmouse->dev->keybit); __set_bit(BTN_SIDE, psmouse->dev->keybit);
__set_bit(REL_WHEEL, psmouse->dev->relbit); __set_bit(REL_WHEEL, psmouse->dev->relbit);
...@@ -460,8 +461,10 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties) ...@@ -460,8 +461,10 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
__set_bit(BTN_MIDDLE, psmouse->dev->keybit); __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
__set_bit(REL_WHEEL, psmouse->dev->relbit); __set_bit(REL_WHEEL, psmouse->dev->relbit);
if (!psmouse->vendor) psmouse->vendor = "Generic"; if (!psmouse->vendor)
if (!psmouse->name) psmouse->name = "Wheel Mouse"; psmouse->vendor = "Generic";
if (!psmouse->name)
psmouse->name = "Wheel Mouse";
psmouse->pktsize = 4; psmouse->pktsize = 4;
} }
...@@ -504,8 +507,10 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) ...@@ -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_SIDE, psmouse->dev->keybit);
__set_bit(BTN_EXTRA, psmouse->dev->keybit); __set_bit(BTN_EXTRA, psmouse->dev->keybit);
if (!psmouse->vendor) psmouse->vendor = "Generic"; if (!psmouse->vendor)
if (!psmouse->name) psmouse->name = "Explorer Mouse"; psmouse->vendor = "Generic";
if (!psmouse->name)
psmouse->name = "Explorer Mouse";
psmouse->pktsize = 4; psmouse->pktsize = 4;
} }
...@@ -536,6 +541,7 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties) ...@@ -536,6 +541,7 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties)
return -1; return -1;
if (set_properties) { if (set_properties) {
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
__set_bit(BTN_EXTRA, psmouse->dev->keybit); __set_bit(BTN_EXTRA, psmouse->dev->keybit);
psmouse->vendor = "Kensington"; psmouse->vendor = "Kensington";
...@@ -551,8 +557,16 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties) ...@@ -551,8 +557,16 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties)
static int ps2bare_detect(struct psmouse *psmouse, bool set_properties) static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
{ {
if (set_properties) { if (set_properties) {
if (!psmouse->vendor) psmouse->vendor = "Generic"; if (!psmouse->vendor)
if (!psmouse->name) psmouse->name = "Mouse"; 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; return 0;
...@@ -567,6 +581,8 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties) ...@@ -567,6 +581,8 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties)
if (set_properties) { if (set_properties) {
psmouse->vendor = "Cortron"; psmouse->vendor = "Cortron";
psmouse->name = "PS/2 Trackball"; psmouse->name = "PS/2 Trackball";
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
__set_bit(BTN_SIDE, psmouse->dev->keybit); __set_bit(BTN_SIDE, psmouse->dev->keybit);
} }
...@@ -1184,15 +1200,16 @@ static void psmouse_disconnect(struct serio *serio) ...@@ -1184,15 +1200,16 @@ static void psmouse_disconnect(struct serio *serio)
mutex_unlock(&psmouse_mutex); 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; struct input_dev *input_dev = psmouse->dev;
input_dev->dev.parent = &psmouse->ps2dev.serio->dev; input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | input_dev->keybit[BIT_WORD(BTN_MOUSE)] =
BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
psmouse->set_rate = psmouse_set_rate; psmouse->set_rate = psmouse_set_rate;
...@@ -1209,8 +1226,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse ...@@ -1209,8 +1226,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse
return -1; return -1;
psmouse->type = proto->type; psmouse->type = proto->type;
} } else
else
psmouse->type = psmouse_extensions(psmouse, psmouse->type = psmouse_extensions(psmouse,
psmouse_max_proto, true); psmouse_max_proto, true);
...@@ -1680,6 +1696,9 @@ static int __init psmouse_init(void) ...@@ -1680,6 +1696,9 @@ static int __init psmouse_init(void)
{ {
int err; int err;
lifebook_module_init();
synaptics_module_init();
kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
if (!kpsmoused_wq) { if (!kpsmoused_wq) {
printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
......
...@@ -836,6 +836,7 @@ int fsp_init(struct psmouse *psmouse) ...@@ -836,6 +836,7 @@ int fsp_init(struct psmouse *psmouse)
priv->flags |= FSPDRV_FLAG_EN_OPC; priv->flags |= FSPDRV_FLAG_EN_OPC;
/* Set up various supported input event bits */ /* Set up various supported input event bits */
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
__set_bit(BTN_BACK, psmouse->dev->keybit); __set_bit(BTN_BACK, psmouse->dev->keybit);
__set_bit(BTN_FORWARD, psmouse->dev->keybit); __set_bit(BTN_FORWARD, psmouse->dev->keybit);
__set_bit(REL_WHEEL, psmouse->dev->relbit); __set_bit(REL_WHEEL, psmouse->dev->relbit);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/dmi.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/libps2.h> #include <linux/libps2.h>
...@@ -629,25 +630,26 @@ static int synaptics_reconnect(struct psmouse *psmouse) ...@@ -629,25 +630,26 @@ static int synaptics_reconnect(struct psmouse *psmouse)
return 0; return 0;
} }
#if defined(__i386__) static bool impaired_toshiba_kbc;
#include <linux/dmi.h>
static const struct dmi_system_id toshiba_dmi_table[] = { static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
{ {
.ident = "Toshiba Satellite", /* Toshiba Satellite */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"),
}, },
}, },
{ {
.ident = "Toshiba Dynabook", /* Toshiba Dynabook */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"), DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"),
}, },
}, },
{ {
.ident = "Toshiba Portege M300", /* Toshiba Portege M300 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"), DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"),
...@@ -655,7 +657,7 @@ static const struct dmi_system_id toshiba_dmi_table[] = { ...@@ -655,7 +657,7 @@ static const struct dmi_system_id toshiba_dmi_table[] = {
}, },
{ {
.ident = "Toshiba Portege M300", /* Toshiba Portege M300 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"), DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"),
...@@ -664,8 +666,13 @@ static const struct dmi_system_id toshiba_dmi_table[] = { ...@@ -664,8 +666,13 @@ static const struct dmi_system_id toshiba_dmi_table[] = {
}, },
{ } { }
};
#endif #endif
};
void __init synaptics_module_init(void)
{
impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
}
int synaptics_init(struct psmouse *psmouse) int synaptics_init(struct psmouse *psmouse)
{ {
...@@ -718,18 +725,16 @@ int synaptics_init(struct psmouse *psmouse) ...@@ -718,18 +725,16 @@ int synaptics_init(struct psmouse *psmouse)
if (SYN_CAP_PASS_THROUGH(priv->capabilities)) if (SYN_CAP_PASS_THROUGH(priv->capabilities))
synaptics_pt_create(psmouse); synaptics_pt_create(psmouse);
#if defined(__i386__)
/* /*
* Toshiba's KBC seems to have trouble handling data from * Toshiba's KBC seems to have trouble handling data from
* Synaptics as full rate, switch to lower rate which is roughly * Synaptics as full rate, switch to lower rate which is roughly
* thye same as rate of standard PS/2 mouse. * 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", printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
dmi_get_system_info(DMI_PRODUCT_NAME)); dmi_get_system_info(DMI_PRODUCT_NAME));
psmouse->rate = 40; psmouse->rate = 40;
} }
#endif
return 0; return 0;
...@@ -740,6 +745,10 @@ int synaptics_init(struct psmouse *psmouse) ...@@ -740,6 +745,10 @@ int synaptics_init(struct psmouse *psmouse)
#else /* CONFIG_MOUSE_PS2_SYNAPTICS */ #else /* CONFIG_MOUSE_PS2_SYNAPTICS */
void __init synaptics_module_init(void)
{
}
int synaptics_init(struct psmouse *psmouse) int synaptics_init(struct psmouse *psmouse)
{ {
return -ENOSYS; return -ENOSYS;
......
...@@ -105,6 +105,7 @@ struct synaptics_data { ...@@ -105,6 +105,7 @@ struct synaptics_data {
int scroll; int scroll;
}; };
void synaptics_module_init(void);
int synaptics_detect(struct psmouse *psmouse, bool set_properties); int synaptics_detect(struct psmouse *psmouse, bool set_properties);
int synaptics_init(struct psmouse *psmouse); int synaptics_init(struct psmouse *psmouse);
void synaptics_reset(struct psmouse *psmouse); void synaptics_reset(struct psmouse *psmouse);
......
...@@ -420,8 +420,8 @@ static void synaptics_i2c_check_params(struct synaptics_i2c *touch) ...@@ -420,8 +420,8 @@ static void synaptics_i2c_check_params(struct synaptics_i2c *touch)
} }
/* Control the Device polling rate / Work Handler sleep time */ /* Control the Device polling rate / Work Handler sleep time */
unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch, static unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch,
bool have_data) bool have_data)
{ {
unsigned long delay, nodata_count_thres; unsigned long delay, nodata_count_thres;
...@@ -520,7 +520,7 @@ static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch) ...@@ -520,7 +520,7 @@ static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch)
__set_bit(BTN_LEFT, input->keybit); __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; struct synaptics_i2c *touch;
......
...@@ -86,7 +86,8 @@ int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties) ...@@ -86,7 +86,8 @@ int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties)
if (set_properties) { if (set_properties) {
dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 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_X, 0, TOUCHKIT_MAX_XC, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0); input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0);
......
...@@ -284,7 +284,6 @@ static int trackpoint_reconnect(struct psmouse *psmouse) ...@@ -284,7 +284,6 @@ static int trackpoint_reconnect(struct psmouse *psmouse)
int trackpoint_detect(struct psmouse *psmouse, bool set_properties) int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
{ {
struct trackpoint_data *priv;
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char firmware_id; unsigned char firmware_id;
unsigned char button_info; unsigned char button_info;
...@@ -301,8 +300,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) ...@@ -301,8 +300,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
button_info = 0; button_info = 0;
} }
psmouse->private = priv = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL); psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
if (!priv) if (!psmouse->private)
return -1; return -1;
psmouse->vendor = "IBM"; psmouse->vendor = "IBM";
...@@ -311,7 +310,10 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) ...@@ -311,7 +310,10 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
psmouse->reconnect = trackpoint_reconnect; psmouse->reconnect = trackpoint_reconnect;
psmouse->disconnect = trackpoint_disconnect; 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); trackpoint_sync(psmouse);
error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group);
...@@ -319,7 +321,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) ...@@ -319,7 +321,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
printk(KERN_ERR printk(KERN_ERR
"trackpoint.c: failed to create sysfs attributes, error: %d\n", "trackpoint.c: failed to create sysfs attributes, error: %d\n",
error); error);
kfree(priv); kfree(psmouse->private);
psmouse->private = NULL;
return -1; return -1;
} }
......
...@@ -86,27 +86,28 @@ ...@@ -86,27 +86,28 @@
#define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet" #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_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
MODULE_DESCRIPTION (DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
#undef VSXXXAA_DEBUG #undef VSXXXAA_DEBUG
#ifdef VSXXXAA_DEBUG #ifdef VSXXXAA_DEBUG
#define DBG(x...) printk (x) #define DBG(x...) printk(x)
#else #else
#define DBG(x...) do {} while (0) #define DBG(x...) do {} while (0)
#endif #endif
#define VSXXXAA_INTRO_MASK 0x80 #define VSXXXAA_INTRO_MASK 0x80
#define VSXXXAA_INTRO_HEAD 0x80 #define VSXXXAA_INTRO_HEAD 0x80
#define IS_HDR_BYTE(x) (((x) & VSXXXAA_INTRO_MASK) \ #define IS_HDR_BYTE(x) \
== VSXXXAA_INTRO_HEAD) (((x) & VSXXXAA_INTRO_MASK) == VSXXXAA_INTRO_HEAD)
#define VSXXXAA_PACKET_MASK 0xe0 #define VSXXXAA_PACKET_MASK 0xe0
#define VSXXXAA_PACKET_REL 0x80 #define VSXXXAA_PACKET_REL 0x80
#define VSXXXAA_PACKET_ABS 0xc0 #define VSXXXAA_PACKET_ABS 0xc0
#define VSXXXAA_PACKET_POR 0xa0 #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 { ...@@ -123,52 +124,50 @@ struct vsxxxaa {
char phys[32]; char phys[32];
}; };
static void static void vsxxxaa_drop_bytes(struct vsxxxaa *mouse, int num)
vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num)
{ {
if (num >= mouse->count) if (num >= mouse->count) {
mouse->count = 0; mouse->count = 0;
else { } else {
memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num); memmove(mouse->buf, mouse->buf + num - 1, BUFLEN - num);
mouse->count -= num; mouse->count -= num;
} }
} }
static void static void vsxxxaa_queue_byte(struct vsxxxaa *mouse, unsigned char byte)
vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte)
{ {
if (mouse->count == BUFLEN) { if (mouse->count == BUFLEN) {
printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", printk(KERN_ERR "%s on %s: Dropping a byte of full buffer.\n",
mouse->name, mouse->phys); mouse->name, mouse->phys);
vsxxxaa_drop_bytes (mouse, 1); 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; mouse->buf[mouse->count++] = byte;
} }
static void static void vsxxxaa_detection_done(struct vsxxxaa *mouse)
vsxxxaa_detection_done (struct vsxxxaa *mouse)
{ {
switch (mouse->type) { switch (mouse->type) {
case 0x02: case 0x02:
strlcpy (mouse->name, "DEC VSXXX-AA/-GA mouse", strlcpy(mouse->name, "DEC VSXXX-AA/-GA mouse",
sizeof (mouse->name)); sizeof(mouse->name));
break; break;
case 0x04: case 0x04:
strlcpy (mouse->name, "DEC VSXXX-AB digitizer", strlcpy(mouse->name, "DEC VSXXX-AB digitizer",
sizeof (mouse->name)); sizeof(mouse->name));
break; break;
default: default:
snprintf (mouse->name, sizeof (mouse->name), snprintf(mouse->name, sizeof(mouse->name),
"unknown DEC pointer device (type = 0x%02x)", "unknown DEC pointer device (type = 0x%02x)",
mouse->type); mouse->type);
break; break;
} }
printk (KERN_INFO printk(KERN_INFO
"Found %s version 0x%02x from country 0x%02x on port %s\n", "Found %s version 0x%02x from country 0x%02x on port %s\n",
mouse->name, mouse->version, mouse->country, mouse->phys); mouse->name, mouse->version, mouse->country, mouse->phys);
} }
...@@ -176,42 +175,38 @@ vsxxxaa_detection_done (struct vsxxxaa *mouse) ...@@ -176,42 +175,38 @@ vsxxxaa_detection_done (struct vsxxxaa *mouse)
/* /*
* Returns number of bytes to be dropped, 0 if packet is okay. * Returns number of bytes to be dropped, 0 if packet is okay.
*/ */
static int static int vsxxxaa_check_packet(struct vsxxxaa *mouse, int packet_len)
vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len)
{ {
int i; int i;
/* First byte must be a header byte */ /* First byte must be a header byte */
if (!IS_HDR_BYTE (mouse->buf[0])) { if (!IS_HDR_BYTE(mouse->buf[0])) {
DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]); DBG("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]);
return 1; return 1;
} }
/* Check all following bytes */ /* Check all following bytes */
if (packet_len > 1) { for (i = 1; i < packet_len; i++) {
for (i = 1; i < packet_len; i++) { if (IS_HDR_BYTE(mouse->buf[i])) {
if (IS_HDR_BYTE (mouse->buf[i])) { printk(KERN_ERR
printk (KERN_ERR "Need to drop %d bytes " "Need to drop %d bytes of a broken packet.\n",
"of a broken packet.\n", i - 1);
i - 1); DBG(KERN_INFO "check: len=%d, b[%d]=0x%02x\n",
DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n", packet_len, i, mouse->buf[i]);
packet_len, i, mouse->buf[i]); return i - 1;
return i - 1;
}
} }
} }
return 0; return 0;
} }
static __inline__ int static inline int vsxxxaa_smells_like_packet(struct vsxxxaa *mouse,
vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len) 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 static void vsxxxaa_handle_REL_packet(struct vsxxxaa *mouse)
vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse)
{ {
struct input_dev *dev = mouse->dev; struct input_dev *dev = mouse->dev;
unsigned char *buf = mouse->buf; unsigned char *buf = mouse->buf;
...@@ -232,43 +227,42 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse) ...@@ -232,43 +227,42 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse)
* 0, bit 4 of byte 0 is direction. * 0, bit 4 of byte 0 is direction.
*/ */
dx = buf[1] & 0x7f; 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 * Low 7 bit of byte 2 are abs(dy), bit 7 is
* 0, bit 3 of byte 0 is direction. * 0, bit 3 of byte 0 is direction.
*/ */
dy = buf[2] & 0x7f; 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 * Get button state. It's the low three bits
* (for three buttons) of byte 0. * (for three buttons) of byte 0.
*/ */
left = (buf[0] & 0x04)? 1: 0; left = buf[0] & 0x04;
middle = (buf[0] & 0x02)? 1: 0; middle = buf[0] & 0x02;
right = (buf[0] & 0x01)? 1: 0; 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", DBG(KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n",
mouse->name, mouse->phys, dx, dy, mouse->name, mouse->phys, dx, dy,
left? "L": "l", middle? "M": "m", right? "R": "r"); left ? "L" : "l", middle ? "M" : "m", right ? "R" : "r");
/* /*
* Report what we've found so far... * Report what we've found so far...
*/ */
input_report_key (dev, BTN_LEFT, left); input_report_key(dev, BTN_LEFT, left);
input_report_key (dev, BTN_MIDDLE, middle); input_report_key(dev, BTN_MIDDLE, middle);
input_report_key (dev, BTN_RIGHT, right); input_report_key(dev, BTN_RIGHT, right);
input_report_key (dev, BTN_TOUCH, 0); input_report_key(dev, BTN_TOUCH, 0);
input_report_rel (dev, REL_X, dx); input_report_rel(dev, REL_X, dx);
input_report_rel (dev, REL_Y, dy); input_report_rel(dev, REL_Y, dy);
input_sync (dev); input_sync(dev);
} }
static void static void vsxxxaa_handle_ABS_packet(struct vsxxxaa *mouse)
vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse)
{ {
struct input_dev *dev = mouse->dev; struct input_dev *dev = mouse->dev;
unsigned char *buf = mouse->buf; unsigned char *buf = mouse->buf;
...@@ -296,32 +290,31 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse) ...@@ -296,32 +290,31 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse)
/* /*
* Get button state. It's bits <4..1> of byte 0. * Get button state. It's bits <4..1> of byte 0.
*/ */
left = (buf[0] & 0x02)? 1: 0; left = buf[0] & 0x02;
middle = (buf[0] & 0x04)? 1: 0; middle = buf[0] & 0x04;
right = (buf[0] & 0x08)? 1: 0; right = buf[0] & 0x08;
touch = (buf[0] & 0x10)? 1: 0; 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", DBG(KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n",
mouse->name, mouse->phys, x, y, mouse->name, mouse->phys, x, y,
left? "L": "l", middle? "M": "m", left ? "L" : "l", middle ? "M" : "m",
right? "R": "r", touch? "T": "t"); right ? "R" : "r", touch ? "T" : "t");
/* /*
* Report what we've found so far... * Report what we've found so far...
*/ */
input_report_key (dev, BTN_LEFT, left); input_report_key(dev, BTN_LEFT, left);
input_report_key (dev, BTN_MIDDLE, middle); input_report_key(dev, BTN_MIDDLE, middle);
input_report_key (dev, BTN_RIGHT, right); input_report_key(dev, BTN_RIGHT, right);
input_report_key (dev, BTN_TOUCH, touch); input_report_key(dev, BTN_TOUCH, touch);
input_report_abs (dev, ABS_X, x); input_report_abs(dev, ABS_X, x);
input_report_abs (dev, ABS_Y, y); input_report_abs(dev, ABS_Y, y);
input_sync (dev); input_sync(dev);
} }
static void static void vsxxxaa_handle_POR_packet(struct vsxxxaa *mouse)
vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
{ {
struct input_dev *dev = mouse->dev; struct input_dev *dev = mouse->dev;
unsigned char *buf = mouse->buf; unsigned char *buf = mouse->buf;
...@@ -356,24 +349,24 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) ...@@ -356,24 +349,24 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
* (for three buttons) of byte 0. Maybe even the bit <3> * (for three buttons) of byte 0. Maybe even the bit <3>
* has some meaning if a tablet is attached. * has some meaning if a tablet is attached.
*/ */
left = (buf[0] & 0x04)? 1: 0; left = buf[0] & 0x04;
middle = (buf[0] & 0x02)? 1: 0; middle = buf[0] & 0x02;
right = (buf[0] & 0x01)? 1: 0; right = buf[0] & 0x01;
vsxxxaa_drop_bytes (mouse, 4); vsxxxaa_drop_bytes(mouse, 4);
vsxxxaa_detection_done (mouse); vsxxxaa_detection_done(mouse);
if (error <= 0x1f) { if (error <= 0x1f) {
/* No (serious) error. Report buttons */ /* No (serious) error. Report buttons */
input_report_key (dev, BTN_LEFT, left); input_report_key(dev, BTN_LEFT, left);
input_report_key (dev, BTN_MIDDLE, middle); input_report_key(dev, BTN_MIDDLE, middle);
input_report_key (dev, BTN_RIGHT, right); input_report_key(dev, BTN_RIGHT, right);
input_report_key (dev, BTN_TOUCH, 0); input_report_key(dev, BTN_TOUCH, 0);
input_sync (dev); input_sync(dev);
if (error != 0) if (error != 0)
printk (KERN_INFO "Your %s on %s reports error=0x%02x\n", printk(KERN_INFO "Your %s on %s reports error=0x%02x\n",
mouse->name, mouse->phys, error); mouse->name, mouse->phys, error);
} }
...@@ -381,18 +374,18 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) ...@@ -381,18 +374,18 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
* If the mouse was hot-plugged, we need to force differential mode * If the mouse was hot-plugged, we need to force differential mode
* now... However, give it a second to recover from it's reset. * now... However, give it a second to recover from it's reset.
*/ */
printk (KERN_NOTICE "%s on %s: Forceing standard packet format, " printk(KERN_NOTICE
"incremental streaming mode and 72 samples/sec\n", "%s on %s: Forcing standard packet format, "
mouse->name, mouse->phys); "incremental streaming mode and 72 samples/sec\n",
serio_write (mouse->serio, 'S'); /* Standard format */ mouse->name, mouse->phys);
mdelay (50); serio_write(mouse->serio, 'S'); /* Standard format */
serio_write (mouse->serio, 'R'); /* Incremental */ mdelay(50);
mdelay (50); serio_write(mouse->serio, 'R'); /* Incremental */
serio_write (mouse->serio, 'L'); /* 72 samples/sec */ mdelay(50);
serio_write(mouse->serio, 'L'); /* 72 samples/sec */
} }
static void static void vsxxxaa_parse_buffer(struct vsxxxaa *mouse)
vsxxxaa_parse_buffer (struct vsxxxaa *mouse)
{ {
unsigned char *buf = mouse->buf; unsigned char *buf = mouse->buf;
int stray_bytes; int stray_bytes;
...@@ -409,122 +402,107 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse) ...@@ -409,122 +402,107 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse)
* activity on the mouse. * activity on the mouse.
*/ */
while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) { while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) {
printk (KERN_ERR "%s on %s: Dropping a byte to regain " printk(KERN_ERR "%s on %s: Dropping a byte to regain "
"sync with mouse data stream...\n", "sync with mouse data stream...\n",
mouse->name, mouse->phys); mouse->name, mouse->phys);
vsxxxaa_drop_bytes (mouse, 1); vsxxxaa_drop_bytes(mouse, 1);
} }
/* /*
* Check for packets we know about. * 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 */ /* Check for broken packet */
stray_bytes = vsxxxaa_check_packet (mouse, 3); stray_bytes = vsxxxaa_check_packet(mouse, 3);
if (stray_bytes > 0) { if (!stray_bytes)
printk (KERN_ERR "Dropping %d bytes now...\n", vsxxxaa_handle_REL_packet(mouse);
stray_bytes);
vsxxxaa_drop_bytes (mouse, stray_bytes);
continue;
}
vsxxxaa_handle_REL_packet (mouse);
continue; /* More to parse? */
}
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 */ /* Check for broken packet */
stray_bytes = vsxxxaa_check_packet (mouse, 5); stray_bytes = vsxxxaa_check_packet(mouse, 5);
if (stray_bytes > 0) { if (!stray_bytes)
printk (KERN_ERR "Dropping %d bytes now...\n", vsxxxaa_handle_ABS_packet(mouse);
stray_bytes);
vsxxxaa_drop_bytes (mouse, stray_bytes);
continue;
}
vsxxxaa_handle_ABS_packet (mouse);
continue; /* More to parse? */
}
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 */ /* Check for broken packet */
stray_bytes = vsxxxaa_check_packet (mouse, 4); stray_bytes = vsxxxaa_check_packet(mouse, 4);
if (stray_bytes > 0) { if (!stray_bytes)
printk (KERN_ERR "Dropping %d bytes now...\n", vsxxxaa_handle_POR_packet(mouse);
stray_bytes);
vsxxxaa_drop_bytes (mouse, stray_bytes); } else {
continue; break; /* No REL, ABS or POR packet found */
} }
vsxxxaa_handle_POR_packet (mouse); if (stray_bytes > 0) {
continue; /* More to parse? */ 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); } while (1);
} }
static irqreturn_t static irqreturn_t vsxxxaa_interrupt(struct serio *serio,
vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags) 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_queue_byte(mouse, data);
vsxxxaa_parse_buffer (mouse); vsxxxaa_parse_buffer(mouse);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void static void vsxxxaa_disconnect(struct serio *serio)
vsxxxaa_disconnect (struct serio *serio)
{ {
struct vsxxxaa *mouse = serio_get_drvdata (serio); struct vsxxxaa *mouse = serio_get_drvdata(serio);
serio_close (serio); serio_close(serio);
serio_set_drvdata (serio, NULL); serio_set_drvdata(serio, NULL);
input_unregister_device (mouse->dev); input_unregister_device(mouse->dev);
kfree (mouse); kfree(mouse);
} }
static int static int vsxxxaa_connect(struct serio *serio, struct serio_driver *drv)
vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
{ {
struct vsxxxaa *mouse; struct vsxxxaa *mouse;
struct input_dev *input_dev; struct input_dev *input_dev;
int err = -ENOMEM; int err = -ENOMEM;
mouse = kzalloc (sizeof (struct vsxxxaa), GFP_KERNEL); mouse = kzalloc(sizeof(struct vsxxxaa), GFP_KERNEL);
input_dev = input_allocate_device (); input_dev = input_allocate_device();
if (!mouse || !input_dev) if (!mouse || !input_dev)
goto fail1; goto fail1;
mouse->dev = input_dev; mouse->dev = input_dev;
mouse->serio = serio; mouse->serio = serio;
strlcat (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer", strlcat(mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer",
sizeof (mouse->name)); sizeof(mouse->name));
snprintf (mouse->phys, sizeof (mouse->phys), "%s/input0", serio->phys); snprintf(mouse->phys, sizeof(mouse->phys), "%s/input0", serio->phys);
input_dev->name = mouse->name; input_dev->name = mouse->name;
input_dev->phys = mouse->phys; input_dev->phys = mouse->phys;
input_dev->id.bustype = BUS_RS232; input_dev->id.bustype = BUS_RS232;
input_dev->dev.parent = &serio->dev; input_dev->dev.parent = &serio->dev;
set_bit (EV_KEY, input_dev->evbit); /* We have buttons */ __set_bit(EV_KEY, input_dev->evbit); /* We have buttons */
set_bit (EV_REL, input_dev->evbit); __set_bit(EV_REL, input_dev->evbit);
set_bit (EV_ABS, input_dev->evbit); __set_bit(EV_ABS, input_dev->evbit);
set_bit (BTN_LEFT, input_dev->keybit); /* We have 3 buttons */ __set_bit(BTN_LEFT, input_dev->keybit); /* We have 3 buttons */
set_bit (BTN_MIDDLE, input_dev->keybit); __set_bit(BTN_MIDDLE, input_dev->keybit);
set_bit (BTN_RIGHT, input_dev->keybit); __set_bit(BTN_RIGHT, input_dev->keybit);
set_bit (BTN_TOUCH, input_dev->keybit); /* ...and Tablet */ __set_bit(BTN_TOUCH, input_dev->keybit); /* ...and Tablet */
set_bit (REL_X, input_dev->relbit); __set_bit(REL_X, input_dev->relbit);
set_bit (REL_Y, 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_X, 0, 1023, 0, 0);
input_set_abs_params (input_dev, ABS_Y, 0, 1023, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
serio_set_drvdata (serio, mouse); serio_set_drvdata(serio, mouse);
err = serio_open (serio, drv); err = serio_open(serio, drv);
if (err) if (err)
goto fail2; goto fail2;
...@@ -532,18 +510,18 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) ...@@ -532,18 +510,18 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
* Request selftest. Standard packet format and differential * Request selftest. Standard packet format and differential
* mode will be requested after the device ID'ed successfully. * 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) if (err)
goto fail3; goto fail3;
return 0; return 0;
fail3: serio_close (serio); fail3: serio_close(serio);
fail2: serio_set_drvdata (serio, NULL); fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device (input_dev); fail1: input_free_device(input_dev);
kfree (mouse); kfree(mouse);
return err; return err;
} }
...@@ -570,18 +548,16 @@ static struct serio_driver vsxxxaa_drv = { ...@@ -570,18 +548,16 @@ static struct serio_driver vsxxxaa_drv = {
.disconnect = vsxxxaa_disconnect, .disconnect = vsxxxaa_disconnect,
}; };
static int __init static int __init vsxxxaa_init(void)
vsxxxaa_init (void)
{ {
return serio_register_driver(&vsxxxaa_drv); return serio_register_driver(&vsxxxaa_drv);
} }
static void __exit static void __exit vsxxxaa_exit(void)
vsxxxaa_exit (void)
{ {
serio_unregister_driver(&vsxxxaa_drv); serio_unregister_driver(&vsxxxaa_drv);
} }
module_init (vsxxxaa_init); module_init(vsxxxaa_init);
module_exit (vsxxxaa_exit); module_exit(vsxxxaa_exit);
...@@ -201,4 +201,12 @@ config SERIO_XILINX_XPS_PS2 ...@@ -201,4 +201,12 @@ config SERIO_XILINX_XPS_PS2
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called xilinx_ps2. 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 endif
...@@ -22,3 +22,4 @@ obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o ...@@ -22,3 +22,4 @@ obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
obj-$(CONFIG_SERIO_RAW) += serio_raw.o obj-$(CONFIG_SERIO_RAW) += serio_raw.o
obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o
obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o
/*
* 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);
...@@ -67,10 +67,12 @@ static inline void i8042_write_command(int val) ...@@ -67,10 +67,12 @@ static inline void i8042_write_command(int val)
#include <linux/dmi.h> #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 = { .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"), DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"),
DMI_MATCH(DMI_BOARD_NAME, "HDAMB"), DMI_MATCH(DMI_BOARD_NAME, "HDAMB"),
...@@ -78,7 +80,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -78,7 +80,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
.ident = "ASUS G1S", /* ASUS G1S */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
DMI_MATCH(DMI_BOARD_NAME, "G1S"), DMI_MATCH(DMI_BOARD_NAME, "G1S"),
...@@ -86,8 +88,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -86,8 +88,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
/* AUX LOOP command does not raise AUX IRQ */ /* ASUS P65UP5 - AUX LOOP command does not raise AUX IRQ */
.ident = "ASUS P65UP5",
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"), DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"),
...@@ -95,7 +96,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -95,7 +96,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
.ident = "Compaq Proliant 8500",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
...@@ -103,7 +103,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -103,7 +103,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
.ident = "Compaq Proliant DL760",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
...@@ -111,7 +110,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -111,7 +110,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
.ident = "OQO Model 01", /* OQO Model 01 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "OQO"), DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
...@@ -119,8 +118,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -119,8 +118,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
/* AUX LOOP does not work properly */ /* ULI EV4873 - AUX LOOP does not work properly */
.ident = "ULI EV4873",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ULI"), DMI_MATCH(DMI_SYS_VENDOR, "ULI"),
DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"), DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"),
...@@ -128,7 +126,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -128,7 +126,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
.ident = "Microsoft Virtual Machine", /* Microsoft Virtual Machine */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
...@@ -136,7 +134,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -136,7 +134,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
.ident = "Medion MAM 2070", /* Medion MAM 2070 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"), DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"),
...@@ -144,7 +142,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -144,7 +142,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
.ident = "Blue FB5601", /* Blue FB5601 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "blue"), DMI_MATCH(DMI_SYS_VENDOR, "blue"),
DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"), DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"),
...@@ -152,7 +150,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -152,7 +150,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
.ident = "Gigabyte M912", /* Gigabyte M912 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "M912"), DMI_MATCH(DMI_PRODUCT_NAME, "M912"),
...@@ -160,7 +158,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -160,7 +158,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
}, },
}, },
{ {
.ident = "HP DV9700",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"),
...@@ -177,72 +174,72 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { ...@@ -177,72 +174,72 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
* ... apparently some Toshibas don't like MUX mode either and * ... apparently some Toshibas don't like MUX mode either and
* die horrible death on reboot. * 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 = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "P7010"), DMI_MATCH(DMI_PRODUCT_NAME, "P7010"),
}, },
}, },
{ {
.ident = "Fujitsu Lifebook P7010", /* Fujitsu Lifebook P7010 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"), DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"),
}, },
}, },
{ {
.ident = "Fujitsu Lifebook P5020D", /* Fujitsu Lifebook P5020D */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"),
}, },
}, },
{ {
.ident = "Fujitsu Lifebook S2000", /* Fujitsu Lifebook S2000 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"),
}, },
}, },
{ {
.ident = "Fujitsu Lifebook S6230", /* Fujitsu Lifebook S6230 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
}, },
}, },
{ {
.ident = "Fujitsu T70H", /* Fujitsu T70H */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"),
}, },
}, },
{ {
.ident = "Fujitsu-Siemens Lifebook T3010", /* Fujitsu-Siemens Lifebook T3010 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"),
}, },
}, },
{ {
.ident = "Fujitsu-Siemens Lifebook E4010", /* Fujitsu-Siemens Lifebook E4010 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"),
}, },
}, },
{ {
.ident = "Fujitsu-Siemens Amilo Pro 2010", /* Fujitsu-Siemens Amilo Pro 2010 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"),
}, },
}, },
{ {
.ident = "Fujitsu-Siemens Amilo Pro 2030", /* Fujitsu-Siemens Amilo Pro 2030 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"),
...@@ -253,7 +250,7 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -253,7 +250,7 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
* No data is coming from the touchscreen unless KBC * No data is coming from the touchscreen unless KBC
* is in legacy mode. * is in legacy mode.
*/ */
.ident = "Panasonic CF-29", /* Panasonic CF-29 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
...@@ -261,10 +258,10 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -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. * causing "spurious NAK" messages.
*/ */
.ident = "HP Pavilion DV4017EA",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"),
...@@ -272,9 +269,9 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -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 = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"),
...@@ -283,44 +280,41 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -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 = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"),
}, },
}, },
{ {
.ident = "Toshiba P10",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
}, },
}, },
{ {
.ident = "Toshiba Equium A110",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"),
}, },
}, },
{ {
.ident = "Alienware Sentia",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"),
}, },
}, },
{ {
.ident = "Sharp Actius MM20", /* Sharp Actius MM20 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SHARP"), DMI_MATCH(DMI_SYS_VENDOR, "SHARP"),
DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"), DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"),
}, },
}, },
{ {
.ident = "Sony Vaio FS-115b", /* Sony Vaio FS-115b */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
...@@ -328,73 +322,72 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -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. * sometimes being delivered to AUX3.
*/ */
.ident = "Sony Vaio FZ-240E",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"),
}, },
}, },
{ {
.ident = "Amoi M636/A737", /* Amoi M636/A737 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."), DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"),
}, },
}, },
{ {
.ident = "Lenovo 3000 n100", /* Lenovo 3000 n100 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "076804U"), DMI_MATCH(DMI_PRODUCT_NAME, "076804U"),
}, },
}, },
{ {
.ident = "Acer Aspire 1360",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
}, },
}, },
{ {
.ident = "Gericom Bellagio", /* Gericom Bellagio */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), DMI_MATCH(DMI_SYS_VENDOR, "Gericom"),
DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"),
}, },
}, },
{ {
.ident = "IBM 2656", /* IBM 2656 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "IBM"), DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
DMI_MATCH(DMI_PRODUCT_NAME, "2656"), DMI_MATCH(DMI_PRODUCT_NAME, "2656"),
}, },
}, },
{ {
.ident = "Dell XPS M1530", /* Dell XPS M1530 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"), DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"),
}, },
}, },
{ {
.ident = "Compal HEL80I", /* Compal HEL80I */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"), DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"),
DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"),
}, },
}, },
{ {
.ident = "Dell Vostro 1510", /* Dell Vostro 1510 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"),
}, },
}, },
{ {
.ident = "Acer Aspire 5536", /* Acer Aspire 5536 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"),
...@@ -404,65 +397,65 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -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 = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "U-100"), DMI_MATCH(DMI_BOARD_NAME, "U-100"),
DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
}, },
}, },
{ {
.ident = "LG Electronics X110", /* LG Electronics X110 */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "X110"), DMI_MATCH(DMI_BOARD_NAME, "X110"),
DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."), DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."),
}, },
}, },
{ {
.ident = "Acer Aspire One 150", /* Acer Aspire One 150 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
}, },
}, },
{ {
.ident = "Advent 4211", /* Advent 4211 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"), DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"),
DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"), DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"),
}, },
}, },
{ {
.ident = "Medion Akoya Mini E1210", /* Medion Akoya Mini E1210 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
DMI_MATCH(DMI_PRODUCT_NAME, "E1210"), DMI_MATCH(DMI_PRODUCT_NAME, "E1210"),
}, },
}, },
{ {
.ident = "Mivvy M310", /* Mivvy M310 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"), DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"),
DMI_MATCH(DMI_PRODUCT_NAME, "N10"), DMI_MATCH(DMI_PRODUCT_NAME, "N10"),
}, },
}, },
{ {
.ident = "Dell Vostro 1320", /* Dell Vostro 1320 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"),
}, },
}, },
{ {
.ident = "Dell Vostro 1520", /* Dell Vostro 1520 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"),
}, },
}, },
{ {
.ident = "Dell Vostro 1720", /* Dell Vostro 1720 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"),
...@@ -472,16 +465,16 @@ static struct dmi_system_id __initdata i8042_dmi_reset_table[] = { ...@@ -472,16 +465,16 @@ static struct dmi_system_id __initdata i8042_dmi_reset_table[] = {
}; };
#ifdef CONFIG_PNP #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 = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "D845PESV"), DMI_MATCH(DMI_BOARD_NAME, "D845PESV"),
DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
}, },
}, },
{ {
.ident = "MSI Wind U-100", /* MSI Wind U-100 */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "U-100"), DMI_MATCH(DMI_BOARD_NAME, "U-100"),
DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
...@@ -490,27 +483,23 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { ...@@ -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 = { .matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
}, },
}, },
{ {
.ident = "Laptop",
.matches = { .matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */ DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
}, },
}, },
{ {
.ident = "Notebook",
.matches = { .matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
}, },
}, },
{ {
.ident = "Sub-Notebook",
.matches = { .matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
}, },
...@@ -525,58 +514,58 @@ static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = { ...@@ -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 * Originally, this was just confined to older laptops, but a few Acer laptops
* have turned up in 2007 that also need this again. * 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 = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
}, },
}, },
{ {
.ident = "Acer Aspire 5650", /* Acer Aspire 5650 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
}, },
}, },
{ {
.ident = "Acer Aspire 5680", /* Acer Aspire 5680 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
}, },
}, },
{ {
.ident = "Acer Aspire 5720", /* Acer Aspire 5720 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
}, },
}, },
{ {
.ident = "Acer Aspire 9110", /* Acer Aspire 9110 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
}, },
}, },
{ {
.ident = "Acer TravelMate 660", /* Acer TravelMate 660 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
}, },
}, },
{ {
.ident = "Acer TravelMate 2490", /* Acer TravelMate 2490 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
}, },
}, },
{ {
.ident = "Acer TravelMate 4280", /* Acer TravelMate 4280 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"),
......
/*
* 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);
...@@ -111,6 +111,18 @@ config TOUCHSCREEN_DA9034 ...@@ -111,6 +111,18 @@ config TOUCHSCREEN_DA9034
Say Y here to enable the support for the touchscreen found Say Y here to enable the support for the touchscreen found
on Dialog Semiconductor DA9034 PMIC. 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 config TOUCHSCREEN_EETI
tristate "EETI touchscreen panel support" tristate "EETI touchscreen panel support"
depends on I2C depends on I2C
...@@ -133,6 +145,18 @@ config TOUCHSCREEN_FUJITSU ...@@ -133,6 +145,18 @@ config TOUCHSCREEN_FUJITSU
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called fujitsu-ts. 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 config TOUCHSCREEN_GUNZE
tristate "Gunze AHL-51S touchscreen" tristate "Gunze AHL-51S touchscreen"
select SERIO select SERIO
...@@ -297,7 +321,7 @@ config TOUCHSCREEN_TOUCHWIN ...@@ -297,7 +321,7 @@ config TOUCHSCREEN_TOUCHWIN
config TOUCHSCREEN_ATMEL_TSADCC config TOUCHSCREEN_ATMEL_TSADCC
tristate "Atmel Touchscreen Interface" tristate "Atmel Touchscreen Interface"
depends on ARCH_AT91SAM9RL depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
help help
Say Y here if you have a 4-wire touchscreen connected to the Say Y here if you have a 4-wire touchscreen connected to the
ADC Controller on your Atmel SoC (such as the AT91SAM9RL). ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
...@@ -418,6 +442,7 @@ config TOUCHSCREEN_USB_COMPOSITE ...@@ -418,6 +442,7 @@ config TOUCHSCREEN_USB_COMPOSITE
- IdealTEK URTC1000 - IdealTEK URTC1000
- GoTop Super_Q2/GogoPen/PenPower tablets - GoTop Super_Q2/GogoPen/PenPower tablets
- JASTEC USB Touch Controller/DigiTech DTR-02U - JASTEC USB Touch Controller/DigiTech DTR-02U
- Zytronic controllers
Have a look at <http://linux.chapter7.ch/touchkit/> for Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff. a usage description and the required user-space stuff.
...@@ -490,6 +515,16 @@ config TOUCHSCREEN_USB_E2I ...@@ -490,6 +515,16 @@ config TOUCHSCREEN_USB_E2I
bool "e2i Touchscreen controller (e.g. from Mimo 740)" bool "e2i Touchscreen controller (e.g. from Mimo 740)"
depends on TOUCHSCREEN_USB_COMPOSITE 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 config TOUCHSCREEN_TOUCHIT213
tristate "Sahara TouchIT-213 touchscreen" tristate "Sahara TouchIT-213 touchscreen"
select SERIO select SERIO
......
...@@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o ...@@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
...@@ -25,7 +26,9 @@ obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o ...@@ -25,7 +26,9 @@ obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
...@@ -41,4 +44,3 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.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_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
...@@ -29,10 +29,9 @@ ...@@ -29,10 +29,9 @@
#include <linux/spi/ads7846.h> #include <linux/spi/ads7846.h>
#include <asm/irq.h> #include <asm/irq.h>
/* /*
* This code has been heavily tested on a Nokia 770, and lightly * 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. * TSC2046 is just newer ads7846 silicon.
* Support for ads7843 tested on Atmel at91sam926x-EK. * Support for ads7843 tested on Atmel at91sam926x-EK.
* Support for ads7845 has only been stubbed in. * Support for ads7845 has only been stubbed in.
...@@ -43,7 +42,7 @@ ...@@ -43,7 +42,7 @@
* have to maintain our own SW IRQ disabled status. This should be * have to maintain our own SW IRQ disabled status. This should be
* removed as soon as the affected platform's IRQ handling is fixed. * 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 * that ought to help in situations like LCDs inducing noise (which
* can also be helped by using synch signals) and more generally. * can also be helped by using synch signals) and more generally.
* This driver tries to utilize the measures described in the app * This driver tries to utilize the measures described in the app
...@@ -566,10 +565,8 @@ static void ads7846_rx(void *ads) ...@@ -566,10 +565,8 @@ static void ads7846_rx(void *ads)
* once more the measurement * once more the measurement
*/ */
if (packet->tc.ignore || Rt > ts->pressure_max) { if (packet->tc.ignore || Rt > ts->pressure_max) {
#ifdef VERBOSE dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
pr_debug("%s: ignored %d pressure %d\n", packet->tc.ignore, Rt);
dev_name(&ts->spi->dev), packet->tc.ignore, Rt);
#endif
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
HRTIMER_MODE_REL); HRTIMER_MODE_REL);
return; return;
...@@ -598,9 +595,7 @@ static void ads7846_rx(void *ads) ...@@ -598,9 +595,7 @@ static void ads7846_rx(void *ads)
if (!ts->pendown) { if (!ts->pendown) {
input_report_key(input, BTN_TOUCH, 1); input_report_key(input, BTN_TOUCH, 1);
ts->pendown = 1; ts->pendown = 1;
#ifdef VERBOSE dev_vdbg(&ts->spi->dev, "DOWN\n");
dev_dbg(&ts->spi->dev, "DOWN\n");
#endif
} }
if (ts->swap_xy) if (ts->swap_xy)
...@@ -608,12 +603,10 @@ static void ads7846_rx(void *ads) ...@@ -608,12 +603,10 @@ static void ads7846_rx(void *ads)
input_report_abs(input, ABS_X, x); input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y); 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); input_sync(input);
#ifdef VERBOSE dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
#endif
} }
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
...@@ -723,9 +716,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) ...@@ -723,9 +716,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
input_sync(input); input_sync(input);
ts->pendown = 0; ts->pendown = 0;
#ifdef VERBOSE dev_vdbg(&ts->spi->dev, "UP\n");
dev_dbg(&ts->spi->dev, "UP\n");
#endif
} }
/* measurement cycle ended */ /* measurement cycle ended */
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/io.h> #include <linux/io.h>
#include <mach/board.h>
#include <mach/cpu.h>
/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ /* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
...@@ -36,7 +38,9 @@ ...@@ -36,7 +38,9 @@
#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */ #define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */ #define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ #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_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_STARTUP (0x7f << 16) /* Start Up time */
#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */ #define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */
#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */ #define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */
...@@ -84,7 +88,13 @@ ...@@ -84,7 +88,13 @@
#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */ #define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */
#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */ #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 atmel_tsadcc {
struct input_dev *input; struct input_dev *input;
...@@ -172,6 +182,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) ...@@ -172,6 +182,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
struct atmel_tsadcc *ts_dev; struct atmel_tsadcc *ts_dev;
struct input_dev *input_dev; struct input_dev *input_dev;
struct resource *res; struct resource *res;
struct at91_tsadcc_data *pdata = pdev->dev.platform_data;
int err = 0; int err = 0;
unsigned int prsc; unsigned int prsc;
unsigned int reg; unsigned int reg;
...@@ -242,31 +253,49 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) ...@@ -242,31 +253,49 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
input_dev->phys = ts_dev->phys; input_dev->phys = ts_dev->phys;
input_dev->dev.parent = &pdev->dev; input_dev->dev.parent = &pdev->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); __set_bit(EV_ABS, input_dev->evbit);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0); 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_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() always returns 0, no need to check it */
clk_enable(ts_dev->clk); clk_enable(ts_dev->clk);
prsc = clk_get_rate(ts_dev->clk); prsc = clk_get_rate(ts_dev->clk);
dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); 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 | reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */ ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */
((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */ ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */
((prsc << 8) & ATMEL_TSADCC_PRESCAL) | /* PRESCAL */ (prsc << 8) |
((0x13 << 16) & ATMEL_TSADCC_STARTUP) | /* STARTUP */ ((0x26 << 16) & ATMEL_TSADCC_STARTUP) |
((0x0F << 28) & ATMEL_TSADCC_PENDBC); /* PENDBC */ ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST); atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST);
atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); 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_read(ATMEL_TSADCC_SR);
atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
......
/*
* 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);
/*
* 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");
...@@ -355,10 +355,13 @@ static int ucb1400_ts_probe(struct platform_device *dev) ...@@ -355,10 +355,13 @@ static int ucb1400_ts_probe(struct platform_device *dev)
goto err; goto err;
} }
error = ucb1400_ts_detect_irq(ucb); /* Only in case the IRQ line wasn't supplied, try detecting it */
if (error) { if (ucb->irq < 0) {
printk(KERN_ERR "UCB1400: IRQ probe failed\n"); error = ucb1400_ts_detect_irq(ucb);
goto err_free_devs; if (error) {
printk(KERN_ERR "UCB1400: IRQ probe failed\n");
goto err_free_devs;
}
} }
init_waitqueue_head(&ucb->ts_wait); init_waitqueue_head(&ucb->ts_wait);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* - General Touch * - General Touch
* - GoTop Super_Q2/GogoPen/PenPower tablets * - GoTop Super_Q2/GogoPen/PenPower tablets
* - JASTEC USB touch controller/DigiTech DTR-02U * - JASTEC USB touch controller/DigiTech DTR-02U
* - Zytronic capacitive touchscreen
* *
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch> * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c) * Copyright (C) by Todd E. Johnson (mtouchusb.c)
...@@ -73,6 +74,15 @@ struct usbtouch_device_info { ...@@ -73,6 +74,15 @@ struct usbtouch_device_info {
int min_press, max_press; int min_press, max_press;
int rept_size; int rept_size;
/*
* Always service the USB devices irq not just when the input device is
* open. This is useful when devices have a watchdog which prevents us
* from periodically polling the device. Leave this unset unless your
* touchscreen device requires it, as it does consume more of the USB
* bandwidth.
*/
bool irq_always;
void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len); void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
/* /*
...@@ -121,6 +131,8 @@ enum { ...@@ -121,6 +131,8 @@ enum {
DEVTYPE_GOTOP, DEVTYPE_GOTOP,
DEVTYPE_JASTEC, DEVTYPE_JASTEC,
DEVTYPE_E2I, DEVTYPE_E2I,
DEVTYPE_ZYTRONIC,
DEVTYPE_TC5UH,
}; };
#define USB_DEVICE_HID_CLASS(vend, prod) \ #define USB_DEVICE_HID_CLASS(vend, prod) \
...@@ -201,6 +213,15 @@ static struct usb_device_id usbtouch_devices[] = { ...@@ -201,6 +213,15 @@ static struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_E2I #ifdef CONFIG_TOUCHSCREEN_USB_E2I
{USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I}, {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
#endif #endif
#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
{USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
{USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
#endif
{} {}
}; };
...@@ -538,6 +559,19 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) ...@@ -538,6 +559,19 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
} }
#endif #endif
/*****************************************************************************
* ET&T TC5UH part
*/
#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
static int tc5uh_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
dev->touch = pkt[0] & 0x01;
return 1;
}
#endif
/***************************************************************************** /*****************************************************************************
* IdealTEK URTC1000 Part * IdealTEK URTC1000 Part
...@@ -621,6 +655,39 @@ static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt) ...@@ -621,6 +655,39 @@ static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
} }
#endif #endif
/*****************************************************************************
* Zytronic Part
*/
#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
switch (pkt[0]) {
case 0x3A: /* command response */
dbg("%s: Command response %d", __func__, pkt[1]);
break;
case 0xC0: /* down */
dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
dev->touch = 1;
dbg("%s: down %d,%d", __func__, dev->x, dev->y);
return 1;
case 0x80: /* up */
dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
dev->touch = 0;
dbg("%s: up %d,%d", __func__, dev->x, dev->y);
return 1;
default:
dbg("%s: Unknown return %d", __func__, pkt[0]);
break;
}
return 0;
}
#endif
/***************************************************************************** /*****************************************************************************
* the different device descriptors * the different device descriptors
...@@ -783,6 +850,29 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { ...@@ -783,6 +850,29 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.read_data = e2i_read_data, .read_data = e2i_read_data,
}, },
#endif #endif
#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
[DEVTYPE_ZYTRONIC] = {
.min_xc = 0x0,
.max_xc = 0x03ff,
.min_yc = 0x0,
.max_yc = 0x03ff,
.rept_size = 5,
.read_data = zytronic_read_data,
.irq_always = true,
},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
[DEVTYPE_TC5UH] = {
.min_xc = 0x0,
.max_xc = 0x0fff,
.min_yc = 0x0,
.max_yc = 0x0fff,
.rept_size = 5,
.read_data = tc5uh_read_data,
},
#endif
}; };
...@@ -933,8 +1023,10 @@ static int usbtouch_open(struct input_dev *input) ...@@ -933,8 +1023,10 @@ static int usbtouch_open(struct input_dev *input)
usbtouch->irq->dev = usbtouch->udev; usbtouch->irq->dev = usbtouch->udev;
if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) if (!usbtouch->type->irq_always) {
return -EIO; if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
return -EIO;
}
return 0; return 0;
} }
...@@ -943,7 +1035,8 @@ static void usbtouch_close(struct input_dev *input) ...@@ -943,7 +1035,8 @@ static void usbtouch_close(struct input_dev *input)
{ {
struct usbtouch_usb *usbtouch = input_get_drvdata(input); struct usbtouch_usb *usbtouch = input_get_drvdata(input);
usb_kill_urb(usbtouch->irq); if (!usbtouch->type->irq_always)
usb_kill_urb(usbtouch->irq);
} }
...@@ -1066,6 +1159,9 @@ static int usbtouch_probe(struct usb_interface *intf, ...@@ -1066,6 +1159,9 @@ static int usbtouch_probe(struct usb_interface *intf,
usb_set_intfdata(intf, usbtouch); usb_set_intfdata(intf, usbtouch);
if (usbtouch->type->irq_always)
usb_submit_urb(usbtouch->irq, GFP_KERNEL);
return 0; return 0;
out_free_buffers: out_free_buffers:
...@@ -1087,7 +1183,7 @@ static void usbtouch_disconnect(struct usb_interface *intf) ...@@ -1087,7 +1183,7 @@ static void usbtouch_disconnect(struct usb_interface *intf)
dbg("%s - usbtouch is initialized, cleaning up", __func__); dbg("%s - usbtouch is initialized, cleaning up", __func__);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
usb_kill_urb(usbtouch->irq); /* this will stop IO via close */
input_unregister_device(usbtouch->input); input_unregister_device(usbtouch->input);
usb_free_urb(usbtouch->irq); usb_free_urb(usbtouch->irq);
usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
......
...@@ -51,6 +51,7 @@ static int ucb1400_core_probe(struct device *dev) ...@@ -51,6 +51,7 @@ static int ucb1400_core_probe(struct device *dev)
struct ucb1400_ts ucb_ts; struct ucb1400_ts ucb_ts;
struct ucb1400_gpio ucb_gpio; struct ucb1400_gpio ucb_gpio;
struct snd_ac97 *ac97; struct snd_ac97 *ac97;
struct ucb1400_pdata *pdata = dev->platform_data;
memset(&ucb_ts, 0, sizeof(ucb_ts)); memset(&ucb_ts, 0, sizeof(ucb_ts));
memset(&ucb_gpio, 0, sizeof(ucb_gpio)); memset(&ucb_gpio, 0, sizeof(ucb_gpio));
...@@ -88,6 +89,12 @@ static int ucb1400_core_probe(struct device *dev) ...@@ -88,6 +89,12 @@ static int ucb1400_core_probe(struct device *dev)
/* TOUCHSCREEN */ /* TOUCHSCREEN */
ucb_ts.ac97 = ac97; ucb_ts.ac97 = ac97;
if (pdata != NULL && pdata->irq >= 0)
ucb_ts.irq = pdata->irq;
else
ucb_ts.irq = -1;
ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1); ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1);
if (!ucb->ucb1400_ts) { if (!ucb->ucb1400_ts) {
err = -ENOMEM; err = -ENOMEM;
......
...@@ -14,12 +14,19 @@ ...@@ -14,12 +14,19 @@
/** /**
* struct input_polled_dev - simple polled input device * struct input_polled_dev - simple polled input device
* @private: private driver data * @private: private driver data.
* @flush: driver-supplied method that flushes device's state upon * @open: driver-supplied method that prepares device for polling
* opening (optional) * (enabled the device and maybe flushes device state).
* @close: driver-supplied method that is called when device is no
* longer being polled. Used to put device into low power mode.
* @poll: driver-supplied method that polls the device and posts * @poll: driver-supplied method that polls the device and posts
* input events (mandatory). * input events (mandatory).
* @poll_interval: specifies how often the poll() method shoudl be called. * @poll_interval: specifies how often the poll() method should be called.
* Defaults to 500 msec unless overriden when registering the device.
* @poll_interval_max: specifies upper bound for the poll interval.
* Defaults to the initial value of @poll_interval.
* @poll_interval_min: specifies lower bound for the poll interval.
* Defaults to 0.
* @input: input device structire associated with the polled device. * @input: input device structire associated with the polled device.
* Must be properly initialized by the driver (id, name, phys, bits). * Must be properly initialized by the driver (id, name, phys, bits).
* *
...@@ -30,11 +37,16 @@ ...@@ -30,11 +37,16 @@
struct input_polled_dev { struct input_polled_dev {
void *private; void *private;
void (*flush)(struct input_polled_dev *dev); void (*open)(struct input_polled_dev *dev);
void (*close)(struct input_polled_dev *dev);
void (*poll)(struct input_polled_dev *dev); void (*poll)(struct input_polled_dev *dev);
unsigned int poll_interval; /* msec */ unsigned int poll_interval; /* msec */
unsigned int poll_interval_max; /* msec */
unsigned int poll_interval_min; /* msec */
struct input_dev *input; struct input_dev *input;
/* private: */
struct delayed_work work; struct delayed_work work;
}; };
......
...@@ -895,7 +895,7 @@ struct ff_periodic_effect { ...@@ -895,7 +895,7 @@ struct ff_periodic_effect {
struct ff_envelope envelope; struct ff_envelope envelope;
__u32 custom_len; __u32 custom_len;
__s16 *custom_data; __s16 __user *custom_data;
}; };
/** /**
...@@ -1021,9 +1021,12 @@ struct ff_effect { ...@@ -1021,9 +1021,12 @@ struct ff_effect {
* @keycodesize: size of elements in keycode table * @keycodesize: size of elements in keycode table
* @keycode: map of scancodes to keycodes for this device * @keycode: map of scancodes to keycodes for this device
* @setkeycode: optional method to alter current keymap, used to implement * @setkeycode: optional method to alter current keymap, used to implement
* sparse keymaps. If not supplied default mechanism will be used * sparse keymaps. If not supplied default mechanism will be used.
* The method is being called while holding event_lock and thus must
* not sleep
* @getkeycode: optional method to retrieve current keymap. If not supplied * @getkeycode: optional method to retrieve current keymap. If not supplied
* default mechanism will be used * default mechanism will be used. The method is being called while
* holding event_lock and thus must not sleep
* @ff: force feedback structure associated with the device if device * @ff: force feedback structure associated with the device if device
* supports force feedback effects * supports force feedback effects
* @repeat_key: stores key code of the last key pressed; used to implement * @repeat_key: stores key code of the last key pressed; used to implement
...@@ -1040,6 +1043,7 @@ struct ff_effect { ...@@ -1040,6 +1043,7 @@ struct ff_effect {
* @absmin: minimum values for events coming from absolute axes * @absmin: minimum values for events coming from absolute axes
* @absfuzz: describes noisiness for axes * @absfuzz: describes noisiness for axes
* @absflat: size of the center flat position (used by joydev) * @absflat: size of the center flat position (used by joydev)
* @absres: resolution used for events coming form absolute axes
* @open: this method is called when the very first user calls * @open: this method is called when the very first user calls
* input_open_device(). The driver must prepare the device * input_open_device(). The driver must prepare the device
* to start generating events (start polling thread, * to start generating events (start polling thread,
...@@ -1294,6 +1298,9 @@ void input_unregister_device(struct input_dev *); ...@@ -1294,6 +1298,9 @@ void input_unregister_device(struct input_dev *);
int __must_check input_register_handler(struct input_handler *); int __must_check input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *); void input_unregister_handler(struct input_handler *);
int input_handler_for_each_handle(struct input_handler *, void *data,
int (*fn)(struct input_handle *, void *));
int input_register_handle(struct input_handle *); int input_register_handle(struct input_handle *);
void input_unregister_handle(struct input_handle *); void input_unregister_handle(struct input_handle *);
......
...@@ -41,6 +41,9 @@ struct matrix_keymap_data { ...@@ -41,6 +41,9 @@ struct matrix_keymap_data {
* @col_scan_delay_us: delay, measured in microseconds, that is * @col_scan_delay_us: delay, measured in microseconds, that is
* needed before we can keypad after activating column gpio * needed before we can keypad after activating column gpio
* @debounce_ms: debounce interval in milliseconds * @debounce_ms: debounce interval in milliseconds
* @active_low: gpio polarity
* @wakeup: controls whether the device should be set up as wakeup
* source
* *
* This structure represents platform-specific data that use used by * This structure represents platform-specific data that use used by
* matrix_keypad driver to perform proper initialization. * matrix_keypad driver to perform proper initialization.
......
#ifndef _SPARSE_KEYMAP_H
#define _SPARSE_KEYMAP_H
/*
* Copyright (c) 2009 Dmitry Torokhov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#define KE_END 0 /* Indicates end of keymap */
#define KE_KEY 1 /* Ordinary key/button */
#define KE_SW 2 /* Switch (predetermined value) */
#define KE_VSW 3 /* Switch (value supplied at runtime) */
#define KE_IGNORE 4 /* Known entry that should be ignored */
#define KE_LAST KE_IGNORE
/**
* struct key_entry - keymap entry for use in sparse keymap
* @type: Type of the key entry (KE_KEY, KE_SW, KE_VSW, KE_END);
* drivers are allowed to extend the list with their own
* private definitions.
* @code: Device-specific data identifying the button/switch
* @keycode: KEY_* code assigned to a key/button
* @sw.code: SW_* code assigned to a switch
* @sw.value: Value that should be sent in an input even when KE_SW
* switch is toggled. KE_VSW switches ignore this field and
* expect driver to supply value for the event.
*
* This structure defines an entry in a sparse keymap used by some
* input devices for which traditional table-based approach is not
* suitable.
*/
struct key_entry {
int type; /* See KE_* above */
u32 code;
union {
u16 keycode; /* For KE_KEY */
struct { /* For KE_SW, KE_VSW */
u8 code;
u8 value; /* For KE_SW, ignored by KE_VSW */
} sw;
};
};
struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
unsigned int code);
struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
unsigned int code);
int sparse_keymap_setup(struct input_dev *dev,
const struct key_entry *keymap,
int (*setup)(struct input_dev *, struct key_entry *));
void sparse_keymap_free(struct input_dev *dev);
void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke,
unsigned int value, bool autorelease);
bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code,
unsigned int value, bool autorelease);
#endif /* _SPARSE_KEYMAP_H */
...@@ -215,5 +215,6 @@ static inline void serio_unpin_driver(struct serio *serio) ...@@ -215,5 +215,6 @@ static inline void serio_unpin_driver(struct serio *serio)
#define SERIO_INEXIO 0x37 #define SERIO_INEXIO 0x37
#define SERIO_TOUCHIT213 0x38 #define SERIO_TOUCHIT213 0x38
#define SERIO_W8001 0x39 #define SERIO_W8001 0x39
#define SERIO_DYNAPRO 0x3a
#endif #endif
...@@ -110,6 +110,10 @@ struct ucb1400 { ...@@ -110,6 +110,10 @@ struct ucb1400 {
struct platform_device *ucb1400_gpio; struct platform_device *ucb1400_gpio;
}; };
struct ucb1400_pdata {
int irq;
};
static inline u16 ucb1400_reg_read(struct snd_ac97 *ac97, u16 reg) static inline u16 ucb1400_reg_read(struct snd_ac97 *ac97, u16 reg)
{ {
return ac97->bus->ops->read(ac97, reg); return ac97->bus->ops->read(ac97, reg);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment