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