提交 fa395aae 编写于 作者: L 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
  ...
...@@ -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;
} }
......
此差异已折叠。
...@@ -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);
/*
* 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);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -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
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册