Commit 49327ad2 authored by Dmitry Torokhov's avatar Dmitry Torokhov

Merge branch 'next' into for-linus

parents f9ce6eb5 6521d0bf
...@@ -18,12 +18,14 @@ ...@@ -18,12 +18,14 @@
#include <linux/amba/pl022.h> #include <linux/amba/pl022.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/mfd/ab8500.h> #include <linux/mfd/ab8500.h>
#include <linux/input/matrix_keypad.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <plat/pincfg.h> #include <plat/pincfg.h>
#include <plat/i2c.h> #include <plat/i2c.h>
#include <plat/ske.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/setup.h> #include <mach/setup.h>
...@@ -47,6 +49,24 @@ static pin_cfg_t mop500_pins[] = { ...@@ -47,6 +49,24 @@ static pin_cfg_t mop500_pins[] = {
GPIO11_I2C2_SCL, GPIO11_I2C2_SCL,
GPIO229_I2C3_SDA, GPIO229_I2C3_SDA,
GPIO230_I2C3_SCL, GPIO230_I2C3_SCL,
/* SKE keypad */
GPIO153_KP_I7,
GPIO154_KP_I6,
GPIO155_KP_I5,
GPIO156_KP_I4,
GPIO157_KP_O7,
GPIO158_KP_O6,
GPIO159_KP_O5,
GPIO160_KP_O4,
GPIO161_KP_I3,
GPIO162_KP_I2,
GPIO163_KP_I1,
GPIO164_KP_I0,
GPIO165_KP_O3,
GPIO166_KP_O2,
GPIO167_KP_O1,
GPIO168_KP_O0,
}; };
static void ab4500_spi_cs_control(u32 command) static void ab4500_spi_cs_control(u32 command)
...@@ -134,12 +154,120 @@ static struct amba_device *amba_devs[] __initdata = { ...@@ -134,12 +154,120 @@ static struct amba_device *amba_devs[] __initdata = {
&u8500_ssp0_device, &u8500_ssp0_device,
}; };
static const unsigned int ux500_keymap[] = {
KEY(2, 5, KEY_END),
KEY(4, 1, KEY_POWER),
KEY(3, 5, KEY_VOLUMEDOWN),
KEY(1, 3, KEY_3),
KEY(5, 2, KEY_RIGHT),
KEY(5, 0, KEY_9),
KEY(0, 5, KEY_MENU),
KEY(7, 6, KEY_ENTER),
KEY(4, 5, KEY_0),
KEY(6, 7, KEY_2),
KEY(3, 4, KEY_UP),
KEY(3, 3, KEY_DOWN),
KEY(6, 4, KEY_SEND),
KEY(6, 2, KEY_BACK),
KEY(4, 2, KEY_VOLUMEUP),
KEY(5, 5, KEY_1),
KEY(4, 3, KEY_LEFT),
KEY(3, 2, KEY_7),
};
static const struct matrix_keymap_data ux500_keymap_data = {
.keymap = ux500_keymap,
.keymap_size = ARRAY_SIZE(ux500_keymap),
};
/*
* Nomadik SKE keypad
*/
#define ROW_PIN_I0 164
#define ROW_PIN_I1 163
#define ROW_PIN_I2 162
#define ROW_PIN_I3 161
#define ROW_PIN_I4 156
#define ROW_PIN_I5 155
#define ROW_PIN_I6 154
#define ROW_PIN_I7 153
#define COL_PIN_O0 168
#define COL_PIN_O1 167
#define COL_PIN_O2 166
#define COL_PIN_O3 165
#define COL_PIN_O4 160
#define COL_PIN_O5 159
#define COL_PIN_O6 158
#define COL_PIN_O7 157
#define SKE_KPD_MAX_ROWS 8
#define SKE_KPD_MAX_COLS 8
static int ske_kp_rows[] = {
ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3,
ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7,
};
/*
* ske_set_gpio_row: request and set gpio rows
*/
static int ske_set_gpio_row(int gpio)
{
int ret;
ret = gpio_request(gpio, "ske-kp");
if (ret < 0) {
pr_err("ske_set_gpio_row: gpio request failed\n");
return ret;
}
ret = gpio_direction_output(gpio, 1);
if (ret < 0) {
pr_err("ske_set_gpio_row: gpio direction failed\n");
gpio_free(gpio);
}
return ret;
}
/*
* ske_kp_init - enable the gpio configuration
*/
static int ske_kp_init(void)
{
int ret, i;
for (i = 0; i < SKE_KPD_MAX_ROWS; i++) {
ret = ske_set_gpio_row(ske_kp_rows[i]);
if (ret < 0) {
pr_err("ske_kp_init: failed init\n");
return ret;
}
}
return 0;
}
static struct ske_keypad_platform_data ske_keypad_board = {
.init = ske_kp_init,
.keymap_data = &ux500_keymap_data,
.no_autorepeat = true,
.krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */
.kcol = SKE_KPD_MAX_COLS,
.debounce_ms = 40, /* in millsecs */
};
/* add any platform devices here - TODO */ /* add any platform devices here - TODO */
static struct platform_device *platform_devs[] __initdata = { static struct platform_device *platform_devs[] __initdata = {
&u8500_i2c0_device, &u8500_i2c0_device,
&ux500_i2c1_device, &ux500_i2c1_device,
&ux500_i2c2_device, &ux500_i2c2_device,
&ux500_i2c3_device, &ux500_i2c3_device,
&ux500_ske_keypad_device,
}; };
static void __init u8500_init_machine(void) static void __init u8500_init_machine(void)
...@@ -154,6 +282,7 @@ static void __init u8500_init_machine(void) ...@@ -154,6 +282,7 @@ static void __init u8500_init_machine(void)
ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data; ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data;
ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data; ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data;
ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data; ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data;
ux500_ske_keypad_device.dev.platform_data = &ske_keypad_board;
u8500_ssp0_device.dev.platform_data = &ssp0_platform_data; u8500_ssp0_device.dev.platform_data = &ssp0_platform_data;
......
...@@ -477,6 +477,7 @@ static struct clk_lookup u8500_common_clks[] = { ...@@ -477,6 +477,7 @@ static struct clk_lookup u8500_common_clks[] = {
CLK(sdi5, "sdi5", NULL), CLK(sdi5, "sdi5", NULL),
CLK(uart2, "uart2", NULL), CLK(uart2, "uart2", NULL),
CLK(ske, "ske", NULL), CLK(ske, "ske", NULL),
CLK(ske, "nmk-ske-keypad", NULL),
CLK(sdi2, "sdi2", NULL), CLK(sdi2, "sdi2", NULL),
CLK(i2c0, "nmk-i2c.0", NULL), CLK(i2c0, "nmk-i2c.0", NULL),
CLK(fsmc, "fsmc", NULL), CLK(fsmc, "fsmc", NULL),
......
...@@ -216,3 +216,23 @@ void dma40_u8500ed_fixup(void) ...@@ -216,3 +216,23 @@ void dma40_u8500ed_fixup(void)
dma40_resources[1].start = U8500_DMA_LCPA_BASE_ED; dma40_resources[1].start = U8500_DMA_LCPA_BASE_ED;
dma40_resources[1].end = U8500_DMA_LCPA_BASE_ED + 2 * SZ_1K - 1; dma40_resources[1].end = U8500_DMA_LCPA_BASE_ED + 2 * SZ_1K - 1;
} }
struct resource keypad_resources[] = {
[0] = {
.start = U8500_SKE_BASE,
.end = U8500_SKE_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_DB8500_KB,
.end = IRQ_DB8500_KB,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device ux500_ske_keypad_device = {
.name = "nmk-ske-keypad",
.id = -1,
.num_resources = ARRAY_SIZE(keypad_resources),
.resource = keypad_resources,
};
...@@ -26,6 +26,7 @@ extern struct platform_device ux500_i2c3_device; ...@@ -26,6 +26,7 @@ extern struct platform_device ux500_i2c3_device;
extern struct platform_device u8500_i2c0_device; extern struct platform_device u8500_i2c0_device;
extern struct platform_device u8500_i2c4_device; extern struct platform_device u8500_i2c4_device;
extern struct platform_device u8500_dma40_device; extern struct platform_device u8500_dma40_device;
extern struct platform_device ux500_ske_keypad_device;
void dma40_u8500ed_fixup(void); void dma40_u8500ed_fixup(void);
......
...@@ -459,82 +459,82 @@ ...@@ -459,82 +459,82 @@
#define GPIO152_KP_O9 PIN_CFG(152, ALT_C) #define GPIO152_KP_O9 PIN_CFG(152, ALT_C)
#define GPIO153_GPIO PIN_CFG(153, GPIO) #define GPIO153_GPIO PIN_CFG(153, GPIO)
#define GPIO153_KP_I7 PIN_CFG(153, ALT_A) #define GPIO153_KP_I7 PIN_CFG_PULL(153, ALT_A, DOWN)
#define GPIO153_LCD_D24 PIN_CFG(153, ALT_B) #define GPIO153_LCD_D24 PIN_CFG(153, ALT_B)
#define GPIO153_U2_RXD PIN_CFG(153, ALT_C) #define GPIO153_U2_RXD PIN_CFG(153, ALT_C)
#define GPIO154_GPIO PIN_CFG(154, GPIO) #define GPIO154_GPIO PIN_CFG(154, GPIO)
#define GPIO154_KP_I6 PIN_CFG(154, ALT_A) #define GPIO154_KP_I6 PIN_CFG_PULL(154, ALT_A, DOWN)
#define GPIO154_LCD_D25 PIN_CFG(154, ALT_B) #define GPIO154_LCD_D25 PIN_CFG(154, ALT_B)
#define GPIO154_U2_TXD PIN_CFG(154, ALT_C) #define GPIO154_U2_TXD PIN_CFG(154, ALT_C)
#define GPIO155_GPIO PIN_CFG(155, GPIO) #define GPIO155_GPIO PIN_CFG(155, GPIO)
#define GPIO155_KP_I5 PIN_CFG(155, ALT_A) #define GPIO155_KP_I5 PIN_CFG_PULL(155, ALT_A, DOWN)
#define GPIO155_LCD_D26 PIN_CFG(155, ALT_B) #define GPIO155_LCD_D26 PIN_CFG(155, ALT_B)
#define GPIO155_STMAPE_CLK PIN_CFG(155, ALT_C) #define GPIO155_STMAPE_CLK PIN_CFG(155, ALT_C)
#define GPIO156_GPIO PIN_CFG(156, GPIO) #define GPIO156_GPIO PIN_CFG(156, GPIO)
#define GPIO156_KP_I4 PIN_CFG(156, ALT_A) #define GPIO156_KP_I4 PIN_CFG_PULL(156, ALT_A, DOWN)
#define GPIO156_LCD_D27 PIN_CFG(156, ALT_B) #define GPIO156_LCD_D27 PIN_CFG(156, ALT_B)
#define GPIO156_STMAPE_DAT3 PIN_CFG(156, ALT_C) #define GPIO156_STMAPE_DAT3 PIN_CFG(156, ALT_C)
#define GPIO157_GPIO PIN_CFG(157, GPIO) #define GPIO157_GPIO PIN_CFG(157, GPIO)
#define GPIO157_KP_O7 PIN_CFG(157, ALT_A) #define GPIO157_KP_O7 PIN_CFG_PULL(157, ALT_A, UP)
#define GPIO157_LCD_D28 PIN_CFG(157, ALT_B) #define GPIO157_LCD_D28 PIN_CFG(157, ALT_B)
#define GPIO157_STMAPE_DAT2 PIN_CFG(157, ALT_C) #define GPIO157_STMAPE_DAT2 PIN_CFG(157, ALT_C)
#define GPIO158_GPIO PIN_CFG(158, GPIO) #define GPIO158_GPIO PIN_CFG(158, GPIO)
#define GPIO158_KP_O6 PIN_CFG(158, ALT_A) #define GPIO158_KP_O6 PIN_CFG_PULL(158, ALT_A, UP)
#define GPIO158_LCD_D29 PIN_CFG(158, ALT_B) #define GPIO158_LCD_D29 PIN_CFG(158, ALT_B)
#define GPIO158_STMAPE_DAT1 PIN_CFG(158, ALT_C) #define GPIO158_STMAPE_DAT1 PIN_CFG(158, ALT_C)
#define GPIO159_GPIO PIN_CFG(159, GPIO) #define GPIO159_GPIO PIN_CFG(159, GPIO)
#define GPIO159_KP_O5 PIN_CFG(159, ALT_A) #define GPIO159_KP_O5 PIN_CFG_PULL(159, ALT_A, UP)
#define GPIO159_LCD_D30 PIN_CFG(159, ALT_B) #define GPIO159_LCD_D30 PIN_CFG(159, ALT_B)
#define GPIO159_STMAPE_DAT0 PIN_CFG(159, ALT_C) #define GPIO159_STMAPE_DAT0 PIN_CFG(159, ALT_C)
#define GPIO160_GPIO PIN_CFG(160, GPIO) #define GPIO160_GPIO PIN_CFG(160, GPIO)
#define GPIO160_KP_O4 PIN_CFG(160, ALT_A) #define GPIO160_KP_O4 PIN_CFG_PULL(160, ALT_A, UP)
#define GPIO160_LCD_D31 PIN_CFG(160, ALT_B) #define GPIO160_LCD_D31 PIN_CFG(160, ALT_B)
#define GPIO160_NONE PIN_CFG(160, ALT_C) #define GPIO160_NONE PIN_CFG(160, ALT_C)
#define GPIO161_GPIO PIN_CFG(161, GPIO) #define GPIO161_GPIO PIN_CFG(161, GPIO)
#define GPIO161_KP_I3 PIN_CFG(161, ALT_A) #define GPIO161_KP_I3 PIN_CFG_PULL(161, ALT_A, DOWN)
#define GPIO161_LCD_D32 PIN_CFG(161, ALT_B) #define GPIO161_LCD_D32 PIN_CFG(161, ALT_B)
#define GPIO161_UARTMOD_RXD PIN_CFG(161, ALT_C) #define GPIO161_UARTMOD_RXD PIN_CFG(161, ALT_C)
#define GPIO162_GPIO PIN_CFG(162, GPIO) #define GPIO162_GPIO PIN_CFG(162, GPIO)
#define GPIO162_KP_I2 PIN_CFG(162, ALT_A) #define GPIO162_KP_I2 PIN_CFG_PULL(162, ALT_A, DOWN)
#define GPIO162_LCD_D33 PIN_CFG(162, ALT_B) #define GPIO162_LCD_D33 PIN_CFG(162, ALT_B)
#define GPIO162_UARTMOD_TXD PIN_CFG(162, ALT_C) #define GPIO162_UARTMOD_TXD PIN_CFG(162, ALT_C)
#define GPIO163_GPIO PIN_CFG(163, GPIO) #define GPIO163_GPIO PIN_CFG(163, GPIO)
#define GPIO163_KP_I1 PIN_CFG(163, ALT_A) #define GPIO163_KP_I1 PIN_CFG_PULL(163, ALT_A, DOWN)
#define GPIO163_LCD_D34 PIN_CFG(163, ALT_B) #define GPIO163_LCD_D34 PIN_CFG(163, ALT_B)
#define GPIO163_STMMOD_CLK PIN_CFG(163, ALT_C) #define GPIO163_STMMOD_CLK PIN_CFG(163, ALT_C)
#define GPIO164_GPIO PIN_CFG(164, GPIO) #define GPIO164_GPIO PIN_CFG(164, GPIO)
#define GPIO164_KP_I0 PIN_CFG(164, ALT_A) #define GPIO164_KP_I0 PIN_CFG_PULL(164, ALT_A, UP)
#define GPIO164_LCD_D35 PIN_CFG(164, ALT_B) #define GPIO164_LCD_D35 PIN_CFG(164, ALT_B)
#define GPIO164_STMMOD_DAT3 PIN_CFG(164, ALT_C) #define GPIO164_STMMOD_DAT3 PIN_CFG(164, ALT_C)
#define GPIO165_GPIO PIN_CFG(165, GPIO) #define GPIO165_GPIO PIN_CFG(165, GPIO)
#define GPIO165_KP_O3 PIN_CFG(165, ALT_A) #define GPIO165_KP_O3 PIN_CFG_PULL(165, ALT_A, UP)
#define GPIO165_LCD_D36 PIN_CFG(165, ALT_B) #define GPIO165_LCD_D36 PIN_CFG(165, ALT_B)
#define GPIO165_STMMOD_DAT2 PIN_CFG(165, ALT_C) #define GPIO165_STMMOD_DAT2 PIN_CFG(165, ALT_C)
#define GPIO166_GPIO PIN_CFG(166, GPIO) #define GPIO166_GPIO PIN_CFG(166, GPIO)
#define GPIO166_KP_O2 PIN_CFG(166, ALT_A) #define GPIO166_KP_O2 PIN_CFG_PULL(166, ALT_A, UP)
#define GPIO166_LCD_D37 PIN_CFG(166, ALT_B) #define GPIO166_LCD_D37 PIN_CFG(166, ALT_B)
#define GPIO166_STMMOD_DAT1 PIN_CFG(166, ALT_C) #define GPIO166_STMMOD_DAT1 PIN_CFG(166, ALT_C)
#define GPIO167_GPIO PIN_CFG(167, GPIO) #define GPIO167_GPIO PIN_CFG(167, GPIO)
#define GPIO167_KP_O1 PIN_CFG(167, ALT_A) #define GPIO167_KP_O1 PIN_CFG_PULL(167, ALT_A, UP)
#define GPIO167_LCD_D38 PIN_CFG(167, ALT_B) #define GPIO167_LCD_D38 PIN_CFG(167, ALT_B)
#define GPIO167_STMMOD_DAT0 PIN_CFG(167, ALT_C) #define GPIO167_STMMOD_DAT0 PIN_CFG(167, ALT_C)
#define GPIO168_GPIO PIN_CFG(168, GPIO) #define GPIO168_GPIO PIN_CFG(168, GPIO)
#define GPIO168_KP_O0 PIN_CFG(168, ALT_A) #define GPIO168_KP_O0 PIN_CFG_PULL(168, ALT_A, UP)
#define GPIO168_LCD_D39 PIN_CFG(168, ALT_B) #define GPIO168_LCD_D39 PIN_CFG(168, ALT_B)
#define GPIO168_NONE PIN_CFG(168, ALT_C) #define GPIO168_NONE PIN_CFG(168, ALT_C)
......
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
*
* ux500 Scroll key and Keypad Encoder (SKE) header
*/
#ifndef __SKE_H
#define __SKE_H
#include <linux/input/matrix_keypad.h>
/* register definitions for SKE peripheral */
#define SKE_CR 0x00
#define SKE_VAL0 0x04
#define SKE_VAL1 0x08
#define SKE_DBCR 0x0C
#define SKE_IMSC 0x10
#define SKE_RIS 0x14
#define SKE_MIS 0x18
#define SKE_ICR 0x1C
/*
* Keypad module
*/
/**
* struct keypad_platform_data - structure for platform specific data
* @init: pointer to keypad init function
* @exit: pointer to keypad deinitialisation function
* @keymap_data: matrix scan code table for keycodes
* @krow: maximum number of rows
* @kcol: maximum number of columns
* @debounce_ms: platform specific debounce time
* @no_autorepeat: flag for auto repetition
* @wakeup_enable: allow waking up the system
*/
struct ske_keypad_platform_data {
int (*init)(void);
int (*exit)(void);
const struct matrix_keymap_data *keymap_data;
u8 krow;
u8 kcol;
u8 debounce_ms;
bool no_autorepeat;
bool wakeup_enable;
};
#endif /*__SKE_KPD_H*/
#ifndef ARCH_ARM_PLAT_OMAP4_KEYPAD_H
#define ARCH_ARM_PLAT_OMAP4_KEYPAD_H
#include <linux/input/matrix_keypad.h>
struct omap4_keypad_platform_data {
const struct matrix_keymap_data *keymap_data;
u8 rows;
u8 cols;
};
extern int omap4_keyboard_init(struct omap4_keypad_platform_data *);
#endif
...@@ -175,8 +175,7 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier); ...@@ -175,8 +175,7 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
*/ */
struct getset_keycode_data { struct getset_keycode_data {
unsigned int scancode; struct input_keymap_entry ke;
unsigned int keycode;
int error; int error;
}; };
...@@ -184,32 +183,50 @@ static int getkeycode_helper(struct input_handle *handle, void *data) ...@@ -184,32 +183,50 @@ static int getkeycode_helper(struct input_handle *handle, void *data)
{ {
struct getset_keycode_data *d = data; struct getset_keycode_data *d = data;
d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode); d->error = input_get_keycode(handle->dev, &d->ke);
return d->error == 0; /* stop as soon as we successfully get one */ return d->error == 0; /* stop as soon as we successfully get one */
} }
int getkeycode(unsigned int scancode) int getkeycode(unsigned int scancode)
{ {
struct getset_keycode_data d = { scancode, 0, -ENODEV }; struct getset_keycode_data d = {
.ke = {
.flags = 0,
.len = sizeof(scancode),
.keycode = 0,
},
.error = -ENODEV,
};
memcpy(d.ke.scancode, &scancode, sizeof(scancode));
input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper); input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
return d.error ?: d.keycode; return d.error ?: d.ke.keycode;
} }
static int setkeycode_helper(struct input_handle *handle, void *data) static int setkeycode_helper(struct input_handle *handle, void *data)
{ {
struct getset_keycode_data *d = data; struct getset_keycode_data *d = data;
d->error = input_set_keycode(handle->dev, d->scancode, d->keycode); d->error = input_set_keycode(handle->dev, &d->ke);
return d->error == 0; /* stop as soon as we successfully set one */ return d->error == 0; /* stop as soon as we successfully set one */
} }
int setkeycode(unsigned int scancode, unsigned int keycode) int setkeycode(unsigned int scancode, unsigned int keycode)
{ {
struct getset_keycode_data d = { scancode, keycode, -ENODEV }; struct getset_keycode_data d = {
.ke = {
.flags = 0,
.len = sizeof(scancode),
.keycode = keycode,
},
.error = -ENODEV,
};
memcpy(d.ke.scancode, &scancode, sizeof(scancode));
input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper); input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
......
...@@ -566,10 +566,16 @@ static const unsigned char sysrq_xlate[KEY_MAX + 1] = ...@@ -566,10 +566,16 @@ static const unsigned char sysrq_xlate[KEY_MAX + 1] =
static bool sysrq_down; static bool sysrq_down;
static int sysrq_alt_use; static int sysrq_alt_use;
static int sysrq_alt; static int sysrq_alt;
static DEFINE_SPINLOCK(sysrq_event_lock);
static bool sysrq_filter(struct input_handle *handle, unsigned int type, static bool sysrq_filter(struct input_handle *handle, unsigned int type,
unsigned int code, int value) unsigned int code, int value)
{ {
bool suppress;
/* We are called with interrupts disabled, just take the lock */
spin_lock(&sysrq_event_lock);
if (type != EV_KEY) if (type != EV_KEY)
goto out; goto out;
...@@ -601,7 +607,10 @@ static bool sysrq_filter(struct input_handle *handle, unsigned int type, ...@@ -601,7 +607,10 @@ static bool sysrq_filter(struct input_handle *handle, unsigned int type,
} }
out: out:
return sysrq_down; suppress = sysrq_down;
spin_unlock(&sysrq_event_lock);
return suppress;
} }
static int sysrq_connect(struct input_handler *handler, static int sysrq_connect(struct input_handler *handler,
...@@ -652,8 +661,8 @@ static void sysrq_disconnect(struct input_handle *handle) ...@@ -652,8 +661,8 @@ static void sysrq_disconnect(struct input_handle *handle)
} }
/* /*
* We are matching on KEY_LEFTALT insteard of KEY_SYSRQ because not all * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
* keyboards have SysRq ikey predefined and so user may add it to keymap * keyboards have SysRq key predefined and so user may add it to keymap
* later, but we expect all such keyboards to have left alt. * later, but we expect all such keyboards to have left alt.
*/ */
static const struct input_device_id sysrq_ids[] = { static const struct input_device_id sysrq_ids[] = {
......
...@@ -1766,6 +1766,11 @@ static bool hid_ignore(struct hid_device *hdev) ...@@ -1766,6 +1766,11 @@ static bool hid_ignore(struct hid_device *hdev)
hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST) hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST)
return true; return true;
break; break;
case USB_VENDOR_ID_HANWANG:
if (hdev->product >= USB_DEVICE_ID_HANWANG_TABLET_FIRST &&
hdev->product <= USB_DEVICE_ID_HANWANG_TABLET_LAST)
return true;
break;
} }
if (hdev->type == HID_TYPE_USBMOUSE && if (hdev->type == HID_TYPE_USBMOUSE &&
......
...@@ -291,6 +291,10 @@ ...@@ -291,6 +291,10 @@
#define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003 #define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003
#define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008 #define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008
#define USB_VENDOR_ID_HANWANG 0x0b57
#define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000
#define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff
#define USB_VENDOR_ID_HAPP 0x078b #define USB_VENDOR_ID_HAPP 0x078b
#define USB_DEVICE_ID_UGCI_DRIVING 0x0010 #define USB_DEVICE_ID_UGCI_DRIVING 0x0010
#define USB_DEVICE_ID_UGCI_FLYING 0x0020 #define USB_DEVICE_ID_UGCI_FLYING 0x0020
......
...@@ -68,79 +68,121 @@ static const struct { ...@@ -68,79 +68,121 @@ static const struct {
#define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \ #define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \
&max, EV_KEY, (c)) &max, EV_KEY, (c))
static inline int match_scancode(unsigned int code, unsigned int scancode) static bool match_scancode(struct hid_usage *usage,
unsigned int cur_idx, unsigned int scancode)
{ {
if (scancode == 0) return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
return 1;
return (code & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
} }
static inline int match_keycode(unsigned int code, unsigned int keycode) static bool match_keycode(struct hid_usage *usage,
unsigned int cur_idx, unsigned int keycode)
{ {
if (keycode == 0) /*
return 1; * We should exclude unmapped usages when doing lookup by keycode.
*/
return (usage->type == EV_KEY && usage->code == keycode);
}
return code == keycode; static bool match_index(struct hid_usage *usage,
unsigned int cur_idx, unsigned int idx)
{
return cur_idx == idx;
} }
typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage,
unsigned int cur_idx, unsigned int val);
static struct hid_usage *hidinput_find_key(struct hid_device *hid, static struct hid_usage *hidinput_find_key(struct hid_device *hid,
unsigned int scancode, hid_usage_cmp_t match,
unsigned int keycode) unsigned int value,
unsigned int *usage_idx)
{ {
int i, j, k; unsigned int i, j, k, cur_idx = 0;
struct hid_report *report; struct hid_report *report;
struct hid_usage *usage; struct hid_usage *usage;
for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
list_for_each_entry(report, &hid->report_enum[k].report_list, list) { list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
for (i = 0; i < report->maxfield; i++) { for (i = 0; i < report->maxfield; i++) {
for ( j = 0; j < report->field[i]->maxusage; j++) { for (j = 0; j < report->field[i]->maxusage; j++) {
usage = report->field[i]->usage + j; usage = report->field[i]->usage + j;
if (usage->type == EV_KEY && if (usage->type == EV_KEY || usage->type == 0) {
match_scancode(usage->hid, scancode) && if (match(usage, cur_idx, value)) {
match_keycode(usage->code, keycode)) if (usage_idx)
*usage_idx = cur_idx;
return usage; return usage;
} }
cur_idx++;
}
}
} }
} }
} }
return NULL; return NULL;
} }
static struct hid_usage *hidinput_locate_usage(struct hid_device *hid,
const struct input_keymap_entry *ke,
unsigned int *index)
{
struct hid_usage *usage;
unsigned int scancode;
if (ke->flags & INPUT_KEYMAP_BY_INDEX)
usage = hidinput_find_key(hid, match_index, ke->index, index);
else if (input_scancode_to_scalar(ke, &scancode) == 0)
usage = hidinput_find_key(hid, match_scancode, scancode, index);
else
usage = NULL;
return usage;
}
static int hidinput_getkeycode(struct input_dev *dev, static int hidinput_getkeycode(struct input_dev *dev,
unsigned int scancode, unsigned int *keycode) struct input_keymap_entry *ke)
{ {
struct hid_device *hid = input_get_drvdata(dev); struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage; struct hid_usage *usage;
unsigned int scancode, index;
usage = hidinput_find_key(hid, scancode, 0); usage = hidinput_locate_usage(hid, ke, &index);
if (usage) { if (usage) {
*keycode = usage->code; ke->keycode = usage->type == EV_KEY ?
usage->code : KEY_RESERVED;
ke->index = index;
scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE);
ke->len = sizeof(scancode);
memcpy(ke->scancode, &scancode, sizeof(scancode));
return 0; return 0;
} }
return -EINVAL; return -EINVAL;
} }
static int hidinput_setkeycode(struct input_dev *dev, static int hidinput_setkeycode(struct input_dev *dev,
unsigned int scancode, unsigned int keycode) const struct input_keymap_entry *ke,
unsigned int *old_keycode)
{ {
struct hid_device *hid = input_get_drvdata(dev); struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage; struct hid_usage *usage;
int old_keycode;
usage = hidinput_find_key(hid, scancode, 0); usage = hidinput_locate_usage(hid, ke, NULL);
if (usage) { if (usage) {
old_keycode = usage->code; *old_keycode = usage->type == EV_KEY ?
usage->code = keycode; usage->code : KEY_RESERVED;
usage->code = ke->keycode;
clear_bit(old_keycode, dev->keybit); clear_bit(*old_keycode, dev->keybit);
set_bit(usage->code, dev->keybit); set_bit(usage->code, dev->keybit);
dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode); dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n",
/* Set the keybit for the old keycode if the old keycode is used usage->code, usage->hid);
* by another key */
if (hidinput_find_key (hid, 0, old_keycode)) /*
set_bit(old_keycode, dev->keybit); * Set the keybit for the old keycode if the old keycode is used
* by another key
*/
if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL))
set_bit(*old_keycode, dev->keybit);
return 0; return 0;
} }
...@@ -748,8 +790,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -748,8 +790,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
hid->ll_driver->hidinput_input_event; hid->ll_driver->hidinput_input_event;
input_dev->open = hidinput_open; input_dev->open = hidinput_open;
input_dev->close = hidinput_close; input_dev->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode; input_dev->setkeycode_new = hidinput_setkeycode;
input_dev->getkeycode = hidinput_getkeycode; input_dev->getkeycode_new = hidinput_getkeycode;
input_dev->name = hid->name; input_dev->name = hid->name;
input_dev->phys = hid->phys; input_dev->phys = hid->phys;
......
...@@ -534,6 +534,80 @@ static int handle_eviocgbit(struct input_dev *dev, ...@@ -534,6 +534,80 @@ static int handle_eviocgbit(struct input_dev *dev,
} }
#undef OLD_KEY_MAX #undef OLD_KEY_MAX
static int evdev_handle_get_keycode(struct input_dev *dev,
void __user *p, size_t size)
{
struct input_keymap_entry ke;
int error;
memset(&ke, 0, sizeof(ke));
if (size == sizeof(unsigned int[2])) {
/* legacy case */
int __user *ip = (int __user *)p;
if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
return -EFAULT;
ke.len = sizeof(unsigned int);
ke.flags = 0;
error = input_get_keycode(dev, &ke);
if (error)
return error;
if (put_user(ke.keycode, ip + 1))
return -EFAULT;
} else {
size = min(size, sizeof(ke));
if (copy_from_user(&ke, p, size))
return -EFAULT;
error = input_get_keycode(dev, &ke);
if (error)
return error;
if (copy_to_user(p, &ke, size))
return -EFAULT;
}
return 0;
}
static int evdev_handle_set_keycode(struct input_dev *dev,
void __user *p, size_t size)
{
struct input_keymap_entry ke;
memset(&ke, 0, sizeof(ke));
if (size == sizeof(unsigned int[2])) {
/* legacy case */
int __user *ip = (int __user *)p;
if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
return -EFAULT;
if (get_user(ke.keycode, ip + 1))
return -EFAULT;
ke.len = sizeof(unsigned int);
ke.flags = 0;
} else {
size = min(size, sizeof(ke));
if (copy_from_user(&ke, p, size))
return -EFAULT;
if (ke.len > sizeof(ke.scancode))
return -EINVAL;
}
return input_set_keycode(dev, &ke);
}
static long evdev_do_ioctl(struct file *file, unsigned int cmd, static long evdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p, int compat_mode) void __user *p, int compat_mode)
{ {
...@@ -580,25 +654,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -580,25 +654,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return 0; return 0;
case EVIOCGKEYCODE:
if (get_user(t, ip))
return -EFAULT;
error = input_get_keycode(dev, t, &v);
if (error)
return error;
if (put_user(v, ip + 1))
return -EFAULT;
return 0;
case EVIOCSKEYCODE:
if (get_user(t, ip) || get_user(v, ip + 1))
return -EFAULT;
return input_set_keycode(dev, t, v);
case EVIOCRMFF: case EVIOCRMFF:
return input_ff_erase(dev, (int)(unsigned long) p, file); return input_ff_erase(dev, (int)(unsigned long) p, file);
...@@ -620,7 +675,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -620,7 +675,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
/* Now check variable-length commands */ /* Now check variable-length commands */
#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) #define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
switch (EVIOC_MASK_SIZE(cmd)) { switch (EVIOC_MASK_SIZE(cmd)) {
case EVIOCGKEY(0): case EVIOCGKEY(0):
...@@ -654,6 +708,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -654,6 +708,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return -EFAULT; return -EFAULT;
return error; return error;
case EVIOC_MASK_SIZE(EVIOCGKEYCODE):
return evdev_handle_get_keycode(dev, p, size);
case EVIOC_MASK_SIZE(EVIOCSKEYCODE):
return evdev_handle_set_keycode(dev, p, size);
} }
/* Multi-number variable-length handlers */ /* Multi-number variable-length handlers */
......
...@@ -59,44 +59,52 @@ MODULE_DEVICE_TABLE(pci, emu_tbl); ...@@ -59,44 +59,52 @@ MODULE_DEVICE_TABLE(pci, emu_tbl);
static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
int ioport, iolen;
struct emu *emu; struct emu *emu;
struct gameport *port; struct gameport *port;
int error;
if (pci_enable_device(pdev))
return -EBUSY;
ioport = pci_resource_start(pdev, 0);
iolen = pci_resource_len(pdev, 0);
if (!request_region(ioport, iolen, "emu10k1-gp"))
return -EBUSY;
emu = kzalloc(sizeof(struct emu), GFP_KERNEL); emu = kzalloc(sizeof(struct emu), GFP_KERNEL);
port = gameport_allocate_port(); port = gameport_allocate_port();
if (!emu || !port) { if (!emu || !port) {
printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n"); printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
release_region(ioport, iolen); error = -ENOMEM;
kfree(emu); goto err_out_free;
gameport_free_port(port);
return -ENOMEM;
} }
emu->io = ioport; error = pci_enable_device(pdev);
emu->size = iolen; if (error)
goto err_out_free;
emu->io = pci_resource_start(pdev, 0);
emu->size = pci_resource_len(pdev, 0);
emu->dev = pdev; emu->dev = pdev;
emu->gameport = port; emu->gameport = port;
gameport_set_name(port, "EMU10K1"); gameport_set_name(port, "EMU10K1");
gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev)); gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
port->dev.parent = &pdev->dev; port->dev.parent = &pdev->dev;
port->io = ioport; port->io = emu->io;
if (!request_region(emu->io, emu->size, "emu10k1-gp")) {
printk(KERN_ERR "emu10k1-gp: unable to grab region 0x%x-0x%x\n",
emu->io, emu->io + emu->size - 1);
error = -EBUSY;
goto err_out_disable_dev;
}
pci_set_drvdata(pdev, emu); pci_set_drvdata(pdev, emu);
gameport_register_port(port); gameport_register_port(port);
return 0; return 0;
err_out_disable_dev:
pci_disable_device(pdev);
err_out_free:
gameport_free_port(port);
kfree(emu);
return error;
} }
static void __devexit emu_remove(struct pci_dev *pdev) static void __devexit emu_remove(struct pci_dev *pdev)
...@@ -106,6 +114,8 @@ static void __devexit emu_remove(struct pci_dev *pdev) ...@@ -106,6 +114,8 @@ static void __devexit emu_remove(struct pci_dev *pdev)
gameport_unregister_port(emu->gameport); gameport_unregister_port(emu->gameport);
release_region(emu->io, emu->size); release_region(emu->io, emu->size);
kfree(emu); kfree(emu);
pci_disable_device(pdev);
} }
static struct pci_driver emu_driver = { static struct pci_driver emu_driver = {
......
...@@ -133,11 +133,11 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci) ...@@ -133,11 +133,11 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci)
{ {
struct fm801_gp *gp = pci_get_drvdata(pci); struct fm801_gp *gp = pci_get_drvdata(pci);
if (gp) {
gameport_unregister_port(gp->gameport); gameport_unregister_port(gp->gameport);
release_resource(gp->res_port); release_resource(gp->res_port);
kfree(gp); kfree(gp);
}
pci_disable_device(pci);
} }
static const struct pci_device_id fm801_gp_id_table[] = { static const struct pci_device_id fm801_gp_id_table[] = {
......
...@@ -171,7 +171,7 @@ static int input_handle_abs_event(struct input_dev *dev, ...@@ -171,7 +171,7 @@ static int input_handle_abs_event(struct input_dev *dev,
if (code == ABS_MT_SLOT) { if (code == ABS_MT_SLOT) {
/* /*
* "Stage" the event; we'll flush it later, when we * "Stage" the event; we'll flush it later, when we
* get actiual touch data. * get actual touch data.
*/ */
if (*pval >= 0 && *pval < dev->mtsize) if (*pval >= 0 && *pval < dev->mtsize)
dev->slot = *pval; dev->slot = *pval;
...@@ -188,7 +188,7 @@ static int input_handle_abs_event(struct input_dev *dev, ...@@ -188,7 +188,7 @@ static int input_handle_abs_event(struct input_dev *dev,
pold = &mtslot->abs[code - ABS_MT_FIRST]; pold = &mtslot->abs[code - ABS_MT_FIRST];
} else { } else {
/* /*
* Bypass filtering for multitouch events when * Bypass filtering for multi-touch events when
* not employing slots. * not employing slots.
*/ */
pold = NULL; pold = NULL;
...@@ -634,78 +634,141 @@ static void input_disconnect_device(struct input_dev *dev) ...@@ -634,78 +634,141 @@ static void input_disconnect_device(struct input_dev *dev)
spin_unlock_irq(&dev->event_lock); spin_unlock_irq(&dev->event_lock);
} }
static int input_fetch_keycode(struct input_dev *dev, int scancode) /**
* input_scancode_to_scalar() - converts scancode in &struct input_keymap_entry
* @ke: keymap entry containing scancode to be converted.
* @scancode: pointer to the location where converted scancode should
* be stored.
*
* This function is used to convert scancode stored in &struct keymap_entry
* into scalar form understood by legacy keymap handling methods. These
* methods expect scancodes to be represented as 'unsigned int'.
*/
int input_scancode_to_scalar(const struct input_keymap_entry *ke,
unsigned int *scancode)
{
switch (ke->len) {
case 1:
*scancode = *((u8 *)ke->scancode);
break;
case 2:
*scancode = *((u16 *)ke->scancode);
break;
case 4:
*scancode = *((u32 *)ke->scancode);
break;
default:
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(input_scancode_to_scalar);
/*
* Those routines handle the default case where no [gs]etkeycode() is
* defined. In this case, an array indexed by the scancode is used.
*/
static unsigned int input_fetch_keycode(struct input_dev *dev,
unsigned int index)
{ {
switch (dev->keycodesize) { switch (dev->keycodesize) {
case 1: case 1:
return ((u8 *)dev->keycode)[scancode]; return ((u8 *)dev->keycode)[index];
case 2: case 2:
return ((u16 *)dev->keycode)[scancode]; return ((u16 *)dev->keycode)[index];
default: default:
return ((u32 *)dev->keycode)[scancode]; return ((u32 *)dev->keycode)[index];
} }
} }
static int input_default_getkeycode(struct input_dev *dev, static int input_default_getkeycode(struct input_dev *dev,
unsigned int scancode, struct input_keymap_entry *ke)
unsigned int *keycode)
{ {
unsigned int index;
int error;
if (!dev->keycodesize) if (!dev->keycodesize)
return -EINVAL; return -EINVAL;
if (scancode >= dev->keycodemax) if (ke->flags & INPUT_KEYMAP_BY_INDEX)
index = ke->index;
else {
error = input_scancode_to_scalar(ke, &index);
if (error)
return error;
}
if (index >= dev->keycodemax)
return -EINVAL; return -EINVAL;
*keycode = input_fetch_keycode(dev, scancode); ke->keycode = input_fetch_keycode(dev, index);
ke->index = index;
ke->len = sizeof(index);
memcpy(ke->scancode, &index, sizeof(index));
return 0; return 0;
} }
static int input_default_setkeycode(struct input_dev *dev, static int input_default_setkeycode(struct input_dev *dev,
unsigned int scancode, const struct input_keymap_entry *ke,
unsigned int keycode) unsigned int *old_keycode)
{ {
int old_keycode; unsigned int index;
int error;
int i; int i;
if (scancode >= dev->keycodemax) if (!dev->keycodesize)
return -EINVAL; return -EINVAL;
if (!dev->keycodesize) if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
index = ke->index;
} else {
error = input_scancode_to_scalar(ke, &index);
if (error)
return error;
}
if (index >= dev->keycodemax)
return -EINVAL; return -EINVAL;
if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) if (dev->keycodesize < sizeof(dev->keycode) &&
(ke->keycode >> (dev->keycodesize * 8)))
return -EINVAL; return -EINVAL;
switch (dev->keycodesize) { switch (dev->keycodesize) {
case 1: { case 1: {
u8 *k = (u8 *)dev->keycode; u8 *k = (u8 *)dev->keycode;
old_keycode = k[scancode]; *old_keycode = k[index];
k[scancode] = keycode; k[index] = ke->keycode;
break; break;
} }
case 2: { case 2: {
u16 *k = (u16 *)dev->keycode; u16 *k = (u16 *)dev->keycode;
old_keycode = k[scancode]; *old_keycode = k[index];
k[scancode] = keycode; k[index] = ke->keycode;
break; break;
} }
default: { default: {
u32 *k = (u32 *)dev->keycode; u32 *k = (u32 *)dev->keycode;
old_keycode = k[scancode]; *old_keycode = k[index];
k[scancode] = keycode; k[index] = ke->keycode;
break; break;
} }
} }
__clear_bit(old_keycode, dev->keybit); __clear_bit(*old_keycode, dev->keybit);
__set_bit(keycode, dev->keybit); __set_bit(ke->keycode, dev->keybit);
for (i = 0; i < dev->keycodemax; i++) { for (i = 0; i < dev->keycodemax; i++) {
if (input_fetch_keycode(dev, i) == old_keycode) { if (input_fetch_keycode(dev, i) == *old_keycode) {
__set_bit(old_keycode, dev->keybit); __set_bit(*old_keycode, dev->keybit);
break; /* Setting the bit twice is useless, so break */ break; /* Setting the bit twice is useless, so break */
} }
} }
...@@ -716,53 +779,86 @@ static int input_default_setkeycode(struct input_dev *dev, ...@@ -716,53 +779,86 @@ static int input_default_setkeycode(struct input_dev *dev,
/** /**
* input_get_keycode - retrieve keycode currently mapped to a given scancode * input_get_keycode - retrieve keycode currently mapped to a given scancode
* @dev: input device which keymap is being queried * @dev: input device which keymap is being queried
* @scancode: scancode (or its equivalent for device in question) for which * @ke: keymap entry
* keycode is needed
* @keycode: result
* *
* This function should be called by anyone interested in retrieving current * This function should be called by anyone interested in retrieving current
* keymap. Presently keyboard and evdev handlers use it. * keymap. Presently evdev handlers use it.
*/ */
int input_get_keycode(struct input_dev *dev, int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke)
unsigned int scancode, unsigned int *keycode)
{ {
unsigned long flags; unsigned long flags;
int retval; int retval;
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
retval = dev->getkeycode(dev, scancode, keycode);
spin_unlock_irqrestore(&dev->event_lock, flags);
if (dev->getkeycode) {
/*
* Support for legacy drivers, that don't implement the new
* ioctls
*/
u32 scancode = ke->index;
memcpy(ke->scancode, &scancode, sizeof(scancode));
ke->len = sizeof(scancode);
retval = dev->getkeycode(dev, scancode, &ke->keycode);
} else {
retval = dev->getkeycode_new(dev, ke);
}
spin_unlock_irqrestore(&dev->event_lock, flags);
return retval; return retval;
} }
EXPORT_SYMBOL(input_get_keycode); EXPORT_SYMBOL(input_get_keycode);
/** /**
* input_get_keycode - assign new keycode to a given scancode * input_set_keycode - attribute a keycode to a given scancode
* @dev: input device which keymap is being updated * @dev: input device which keymap is being updated
* @scancode: scancode (or its equivalent for device in question) * @ke: new keymap entry
* @keycode: new keycode to be assigned to the scancode
* *
* This function should be called by anyone needing to update current * This function should be called by anyone needing to update current
* keymap. Presently keyboard and evdev handlers use it. * keymap. Presently keyboard and evdev handlers use it.
*/ */
int input_set_keycode(struct input_dev *dev, int input_set_keycode(struct input_dev *dev,
unsigned int scancode, unsigned int keycode) const struct input_keymap_entry *ke)
{ {
unsigned long flags; unsigned long flags;
unsigned int old_keycode; unsigned int old_keycode;
int retval; int retval;
if (keycode > KEY_MAX) if (ke->keycode > KEY_MAX)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
if (dev->setkeycode) {
/*
* Support for legacy drivers, that don't implement the new
* ioctls
*/
unsigned int scancode;
retval = input_scancode_to_scalar(ke, &scancode);
if (retval)
goto out;
/*
* We need to know the old scancode, in order to generate a
* keyup effect, if the set operation happens successfully
*/
if (!dev->getkeycode) {
retval = -EINVAL;
goto out;
}
retval = dev->getkeycode(dev, scancode, &old_keycode); retval = dev->getkeycode(dev, scancode, &old_keycode);
if (retval) if (retval)
goto out; goto out;
retval = dev->setkeycode(dev, scancode, keycode); retval = dev->setkeycode(dev, scancode, ke->keycode);
} else {
retval = dev->setkeycode_new(dev, ke, &old_keycode);
}
if (retval) if (retval)
goto out; goto out;
...@@ -1601,7 +1697,7 @@ EXPORT_SYMBOL(input_free_device); ...@@ -1601,7 +1697,7 @@ EXPORT_SYMBOL(input_free_device);
* *
* This function allocates all necessary memory for MT slot handling in the * This function allocates all necessary memory for MT slot handling in the
* input device, and adds ABS_MT_SLOT to the device capabilities. All slots * input device, and adds ABS_MT_SLOT to the device capabilities. All slots
* are initially marked as unused iby setting ABS_MT_TRACKING_ID to -1. * are initially marked as unused by setting ABS_MT_TRACKING_ID to -1.
*/ */
int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots) int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
{ {
...@@ -1759,11 +1855,11 @@ int input_register_device(struct input_dev *dev) ...@@ -1759,11 +1855,11 @@ int input_register_device(struct input_dev *dev)
dev->rep[REP_PERIOD] = 33; dev->rep[REP_PERIOD] = 33;
} }
if (!dev->getkeycode) if (!dev->getkeycode && !dev->getkeycode_new)
dev->getkeycode = input_default_getkeycode; dev->getkeycode_new = input_default_getkeycode;
if (!dev->setkeycode) if (!dev->setkeycode && !dev->setkeycode_new)
dev->setkeycode = input_default_setkeycode; dev->setkeycode_new = input_default_setkeycode;
dev_set_name(&dev->dev, "input%ld", dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1); (unsigned long) atomic_inc_return(&input_no) - 1);
......
...@@ -327,6 +327,16 @@ config KEYBOARD_NEWTON ...@@ -327,6 +327,16 @@ config KEYBOARD_NEWTON
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called newtonkbd. module will be called newtonkbd.
config KEYBOARD_NOMADIK
tristate "ST-Ericsson Nomadik SKE keyboard"
depends on PLAT_NOMADIK
help
Say Y here if you want to use a keypad provided on the SKE controller
used on the Ux500 and Nomadik platforms
To compile this driver as a module, choose M here: the
module will be called nmk-ske-keypad.
config KEYBOARD_OPENCORES config KEYBOARD_OPENCORES
tristate "OpenCores Keyboard Controller" tristate "OpenCores Keyboard Controller"
help help
...@@ -424,6 +434,15 @@ config KEYBOARD_OMAP ...@@ -424,6 +434,15 @@ config KEYBOARD_OMAP
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called omap-keypad. module will be called omap-keypad.
config KEYBOARD_OMAP4
tristate "TI OMAP4 keypad support"
depends on ARCH_OMAP4
help
Say Y here if you want to use the OMAP4 keypad.
To compile this driver as a module, choose M here: the
module will be called omap4-keypad.
config KEYBOARD_TWL4030 config KEYBOARD_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support" tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
depends on TWL4030_CORE depends on TWL4030_CORE
......
...@@ -28,7 +28,9 @@ obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o ...@@ -28,7 +28,9 @@ obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
......
...@@ -660,7 +660,7 @@ static const struct dev_pm_ops adp5588_dev_pm_ops = { ...@@ -660,7 +660,7 @@ static const struct dev_pm_ops adp5588_dev_pm_ops = {
#endif #endif
static const struct i2c_device_id adp5588_id[] = { static const struct i2c_device_id adp5588_id[] = {
{ KBUILD_MODNAME, 0 }, { "adp5588-keys", 0 },
{ "adp5587-keys", 0 }, { "adp5587-keys", 0 },
{ } { }
}; };
......
...@@ -570,6 +570,8 @@ static struct serio_device_id hil_dev_ids[] = { ...@@ -570,6 +570,8 @@ static struct serio_device_id hil_dev_ids[] = {
{ 0 } { 0 }
}; };
MODULE_DEVICE_TABLE(serio, hil_dev_ids);
static struct serio_driver hil_serio_drv = { static struct serio_driver hil_serio_drv = {
.driver = { .driver = {
.name = "hil_dev", .name = "hil_dev",
......
This diff is collapsed.
/*
* OMAP4 Keypad Driver
*
* Copyright (C) 2010 Texas Instruments
*
* Author: Abraham Arce <x0066660@ti.com>
* Initial Code: Syed Rafiuddin <rafiuddin.syed@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/platform_device.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <plat/omap4-keypad.h>
/* OMAP4 registers */
#define OMAP4_KBD_REVISION 0x00
#define OMAP4_KBD_SYSCONFIG 0x10
#define OMAP4_KBD_SYSSTATUS 0x14
#define OMAP4_KBD_IRQSTATUS 0x18
#define OMAP4_KBD_IRQENABLE 0x1C
#define OMAP4_KBD_WAKEUPENABLE 0x20
#define OMAP4_KBD_PENDING 0x24
#define OMAP4_KBD_CTRL 0x28
#define OMAP4_KBD_DEBOUNCINGTIME 0x2C
#define OMAP4_KBD_LONGKEYTIME 0x30
#define OMAP4_KBD_TIMEOUT 0x34
#define OMAP4_KBD_STATEMACHINE 0x38
#define OMAP4_KBD_ROWINPUTS 0x3C
#define OMAP4_KBD_COLUMNOUTPUTS 0x40
#define OMAP4_KBD_FULLCODE31_0 0x44
#define OMAP4_KBD_FULLCODE63_32 0x48
/* OMAP4 bit definitions */
#define OMAP4_DEF_IRQENABLE_EVENTEN (1 << 0)
#define OMAP4_DEF_IRQENABLE_LONGKEY (1 << 1)
#define OMAP4_DEF_IRQENABLE_TIMEOUTEN (1 << 2)
#define OMAP4_DEF_WUP_EVENT_ENA (1 << 0)
#define OMAP4_DEF_WUP_LONG_KEY_ENA (1 << 1)
#define OMAP4_DEF_CTRL_NOSOFTMODE (1 << 1)
#define OMAP4_DEF_CTRLPTVVALUE (1 << 2)
#define OMAP4_DEF_CTRLPTV (1 << 1)
/* OMAP4 values */
#define OMAP4_VAL_IRQDISABLE 0x00
#define OMAP4_VAL_DEBOUNCINGTIME 0x07
#define OMAP4_VAL_FUNCTIONALCFG 0x1E
#define OMAP4_MASK_IRQSTATUSDISABLE 0xFFFF
struct omap4_keypad {
struct input_dev *input;
void __iomem *base;
int irq;
unsigned int rows;
unsigned int cols;
unsigned int row_shift;
unsigned char key_state[8];
unsigned short keymap[];
};
static void __devinit omap4_keypad_config(struct omap4_keypad *keypad_data)
{
__raw_writel(OMAP4_VAL_FUNCTIONALCFG,
keypad_data->base + OMAP4_KBD_CTRL);
__raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
__raw_writel(OMAP4_VAL_IRQDISABLE,
keypad_data->base + OMAP4_KBD_IRQSTATUS);
__raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
keypad_data->base + OMAP4_KBD_IRQENABLE);
__raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
}
/* Interrupt handler */
static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
{
struct omap4_keypad *keypad_data = dev_id;
struct input_dev *input_dev = keypad_data->input;
unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)];
unsigned int col, row, code, changed;
u32 *new_state = (u32 *) key_state;
/* Disable interrupts */
__raw_writel(OMAP4_VAL_IRQDISABLE,
keypad_data->base + OMAP4_KBD_IRQENABLE);
*new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0);
*(new_state + 1) = __raw_readl(keypad_data->base
+ OMAP4_KBD_FULLCODE63_32);
for (row = 0; row < keypad_data->rows; row++) {
changed = key_state[row] ^ keypad_data->key_state[row];
if (!changed)
continue;
for (col = 0; col < keypad_data->cols; col++) {
if (changed & (1 << col)) {
code = MATRIX_SCAN_CODE(row, col,
keypad_data->row_shift);
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev,
keypad_data->keymap[code],
key_state[row] & (1 << col));
}
}
}
input_sync(input_dev);
memcpy(keypad_data->key_state, key_state,
sizeof(keypad_data->key_state));
/* clear pending interrupts */
__raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
keypad_data->base + OMAP4_KBD_IRQSTATUS);
/* enable interrupts */
__raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
keypad_data->base + OMAP4_KBD_IRQENABLE);
return IRQ_HANDLED;
}
static int __devinit omap4_keypad_probe(struct platform_device *pdev)
{
const struct omap4_keypad_platform_data *pdata;
struct omap4_keypad *keypad_data;
struct input_dev *input_dev;
struct resource *res;
resource_size_t size;
unsigned int row_shift, max_keys;
int irq;
int error;
/* platform data */
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data defined\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no base address specified\n");
return -EINVAL;
}
irq = platform_get_irq(pdev, 0);
if (!irq) {
dev_err(&pdev->dev, "no keyboard irq assigned\n");
return -EINVAL;
}
if (!pdata->keymap_data) {
dev_err(&pdev->dev, "no keymap data defined\n");
return -EINVAL;
}
row_shift = get_count_order(pdata->cols);
max_keys = pdata->rows << row_shift;
keypad_data = kzalloc(sizeof(struct omap4_keypad) +
max_keys * sizeof(keypad_data->keymap[0]),
GFP_KERNEL);
if (!keypad_data) {
dev_err(&pdev->dev, "keypad_data memory allocation failed\n");
return -ENOMEM;
}
size = resource_size(res);
res = request_mem_region(res->start, size, pdev->name);
if (!res) {
dev_err(&pdev->dev, "can't request mem region\n");
error = -EBUSY;
goto err_free_keypad;
}
keypad_data->base = ioremap(res->start, resource_size(res));
if (!keypad_data->base) {
dev_err(&pdev->dev, "can't ioremap mem resource\n");
error = -ENOMEM;
goto err_release_mem;
}
keypad_data->irq = irq;
keypad_data->row_shift = row_shift;
keypad_data->rows = pdata->rows;
keypad_data->cols = pdata->cols;
/* input device allocation */
keypad_data->input = input_dev = input_allocate_device();
if (!input_dev) {
error = -ENOMEM;
goto err_unmap;
}
input_dev->name = pdev->name;
input_dev->dev.parent = &pdev->dev;
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0001;
input_dev->keycode = keypad_data->keymap;
input_dev->keycodesize = sizeof(keypad_data->keymap[0]);
input_dev->keycodemax = max_keys;
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad_data);
matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
input_dev->keycode, input_dev->keybit);
omap4_keypad_config(keypad_data);
error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
IRQF_TRIGGER_RISING,
"omap4-keypad", keypad_data);
if (error) {
dev_err(&pdev->dev, "failed to register interrupt\n");
goto err_free_input;
}
error = input_register_device(keypad_data->input);
if (error < 0) {
dev_err(&pdev->dev, "failed to register input device\n");
goto err_free_irq;
}
platform_set_drvdata(pdev, keypad_data);
return 0;
err_free_irq:
free_irq(keypad_data->irq, keypad_data);
err_free_input:
input_free_device(input_dev);
err_unmap:
iounmap(keypad_data->base);
err_release_mem:
release_mem_region(res->start, size);
err_free_keypad:
kfree(keypad_data);
return error;
}
static int __devexit omap4_keypad_remove(struct platform_device *pdev)
{
struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
struct resource *res;
free_irq(keypad_data->irq, keypad_data);
input_unregister_device(keypad_data->input);
iounmap(keypad_data->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
kfree(keypad_data);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver omap4_keypad_driver = {
.probe = omap4_keypad_probe,
.remove = __devexit_p(omap4_keypad_remove),
.driver = {
.name = "omap4-keypad",
.owner = THIS_MODULE,
},
};
static int __init omap4_keypad_init(void)
{
return platform_driver_register(&omap4_keypad_driver);
}
module_init(omap4_keypad_init);
static void __exit omap4_keypad_exit(void)
{
platform_driver_unregister(&omap4_keypad_driver);
}
module_exit(omap4_keypad_exit);
MODULE_AUTHOR("Texas Instruments");
MODULE_DESCRIPTION("OMAP4 Keypad Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:omap4-keypad");
...@@ -406,23 +406,22 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev) ...@@ -406,23 +406,22 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
if (error) { if (error) {
dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n", dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n",
kp->irq); kp->irq);
goto err3; goto err2;
} }
/* Enable KP and TO interrupts now. */ /* Enable KP and TO interrupts now. */
reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO); reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) { if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) {
error = -EIO; error = -EIO;
goto err4; goto err3;
} }
platform_set_drvdata(pdev, kp); platform_set_drvdata(pdev, kp);
return 0; return 0;
err4: err3:
/* mask all events - we don't care about the result */ /* mask all events - we don't care about the result */
(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1); (void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
err3:
free_irq(kp->irq, NULL); free_irq(kp->irq, NULL);
err2: err2:
input_unregister_device(input); input_unregister_device(input);
......
...@@ -22,6 +22,16 @@ config INPUT_88PM860X_ONKEY ...@@ -22,6 +22,16 @@ config INPUT_88PM860X_ONKEY
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called 88pm860x_onkey. will be called 88pm860x_onkey.
config INPUT_AB8500_PONKEY
tristate "AB8500 Pon (PowerOn) Key"
depends on AB8500_CORE
help
Say Y here to use the PowerOn Key for ST-Ericsson's AB8500
Mix-Sig PMIC.
To compile this driver as a module, choose M here: the module
will be called ab8500-ponkey.
config INPUT_AD714X config INPUT_AD714X
tristate "Analog Devices AD714x Capacitance Touch Sensor" tristate "Analog Devices AD714x Capacitance Touch Sensor"
help help
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
# Each configuration option enables a list of files. # Each configuration option enables a list of files.
obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o
obj-$(CONFIG_INPUT_AD714X) += ad714x.o obj-$(CONFIG_INPUT_AD714X) += ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
......
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
*
* AB8500 Power-On Key handler
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/mfd/ab8500.h>
#include <linux/slab.h>
/**
* struct ab8500_ponkey - ab8500 ponkey information
* @input_dev: pointer to input device
* @ab8500: ab8500 parent
* @irq_dbf: irq number for falling transition
* @irq_dbr: irq number for rising transition
*/
struct ab8500_ponkey {
struct input_dev *idev;
struct ab8500 *ab8500;
int irq_dbf;
int irq_dbr;
};
/* AB8500 gives us an interrupt when ONKEY is held */
static irqreturn_t ab8500_ponkey_handler(int irq, void *data)
{
struct ab8500_ponkey *ponkey = data;
if (irq == ponkey->irq_dbf)
input_report_key(ponkey->idev, KEY_POWER, true);
else if (irq == ponkey->irq_dbr)
input_report_key(ponkey->idev, KEY_POWER, false);
input_sync(ponkey->idev);
return IRQ_HANDLED;
}
static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
{
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
struct ab8500_ponkey *ponkey;
struct input_dev *input;
int irq_dbf, irq_dbr;
int error;
irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
if (irq_dbf < 0) {
dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf);
return irq_dbf;
}
irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
if (irq_dbr < 0) {
dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr);
return irq_dbr;
}
ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL);
input = input_allocate_device();
if (!ponkey || !input) {
error = -ENOMEM;
goto err_free_mem;
}
ponkey->idev = input;
ponkey->ab8500 = ab8500;
ponkey->irq_dbf = irq_dbf;
ponkey->irq_dbr = irq_dbr;
input->name = "AB8500 POn(PowerOn) Key";
input->dev.parent = &pdev->dev;
input_set_capability(input, EV_KEY, KEY_POWER);
error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler,
0, "ab8500-ponkey-dbf", ponkey);
if (error < 0) {
dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
ponkey->irq_dbf, error);
goto err_free_mem;
}
error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler,
0, "ab8500-ponkey-dbr", ponkey);
if (error < 0) {
dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
ponkey->irq_dbr, error);
goto err_free_dbf_irq;
}
error = input_register_device(ponkey->idev);
if (error) {
dev_err(ab8500->dev, "Can't register input device: %d\n", error);
goto err_free_dbr_irq;
}
platform_set_drvdata(pdev, ponkey);
return 0;
err_free_dbr_irq:
free_irq(ponkey->irq_dbr, ponkey);
err_free_dbf_irq:
free_irq(ponkey->irq_dbf, ponkey);
err_free_mem:
input_free_device(input);
kfree(ponkey);
return error;
}
static int __devexit ab8500_ponkey_remove(struct platform_device *pdev)
{
struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev);
free_irq(ponkey->irq_dbf, ponkey);
free_irq(ponkey->irq_dbr, ponkey);
input_unregister_device(ponkey->idev);
kfree(ponkey);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver ab8500_ponkey_driver = {
.driver = {
.name = "ab8500-poweron-key",
.owner = THIS_MODULE,
},
.probe = ab8500_ponkey_probe,
.remove = __devexit_p(ab8500_ponkey_remove),
};
static int __init ab8500_ponkey_init(void)
{
return platform_driver_register(&ab8500_ponkey_driver);
}
module_init(ab8500_ponkey_init);
static void __exit ab8500_ponkey_exit(void)
{
platform_driver_unregister(&ab8500_ponkey_driver);
}
module_exit(ab8500_ponkey_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver");
...@@ -483,51 +483,88 @@ static void ati_remote2_complete_key(struct urb *urb) ...@@ -483,51 +483,88 @@ static void ati_remote2_complete_key(struct urb *urb)
} }
static int ati_remote2_getkeycode(struct input_dev *idev, static int ati_remote2_getkeycode(struct input_dev *idev,
unsigned int scancode, unsigned int *keycode) struct input_keymap_entry *ke)
{ {
struct ati_remote2 *ar2 = input_get_drvdata(idev); struct ati_remote2 *ar2 = input_get_drvdata(idev);
unsigned int mode; unsigned int mode;
int index; int offset;
unsigned int index;
unsigned int scancode;
if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
index = ke->index;
if (index >= ATI_REMOTE2_MODES *
ARRAY_SIZE(ati_remote2_key_table))
return -EINVAL;
mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
scancode = (mode << 8) + ati_remote2_key_table[offset].hw_code;
} else {
if (input_scancode_to_scalar(ke, &scancode))
return -EINVAL;
mode = scancode >> 8; mode = scancode >> 8;
if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask)) if (mode > ATI_REMOTE2_PC)
return -EINVAL; return -EINVAL;
index = ati_remote2_lookup(scancode & 0xFF); offset = ati_remote2_lookup(scancode & 0xff);
if (index < 0) if (offset < 0)
return -EINVAL; return -EINVAL;
*keycode = ar2->keycode[mode][index]; index = mode * ARRAY_SIZE(ati_remote2_key_table) + offset;
}
ke->keycode = ar2->keycode[mode][offset];
ke->len = sizeof(scancode);
memcpy(&ke->scancode, &scancode, sizeof(scancode));
ke->index = index;
return 0; return 0;
} }
static int ati_remote2_setkeycode(struct input_dev *idev, static int ati_remote2_setkeycode(struct input_dev *idev,
unsigned int scancode, unsigned int keycode) const struct input_keymap_entry *ke,
unsigned int *old_keycode)
{ {
struct ati_remote2 *ar2 = input_get_drvdata(idev); struct ati_remote2 *ar2 = input_get_drvdata(idev);
unsigned int mode, old_keycode; unsigned int mode;
int index; int offset;
unsigned int index;
unsigned int scancode;
if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
if (ke->index >= ATI_REMOTE2_MODES *
ARRAY_SIZE(ati_remote2_key_table))
return -EINVAL;
mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
} else {
if (input_scancode_to_scalar(ke, &scancode))
return -EINVAL;
mode = scancode >> 8; mode = scancode >> 8;
if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask)) if (mode > ATI_REMOTE2_PC)
return -EINVAL; return -EINVAL;
index = ati_remote2_lookup(scancode & 0xFF); offset = ati_remote2_lookup(scancode & 0xff);
if (index < 0) if (offset < 0)
return -EINVAL; return -EINVAL;
}
old_keycode = ar2->keycode[mode][index]; *old_keycode = ar2->keycode[mode][offset];
ar2->keycode[mode][index] = keycode; ar2->keycode[mode][offset] = ke->keycode;
__set_bit(keycode, idev->keybit); __set_bit(ke->keycode, idev->keybit);
for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) { for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) { for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
if (ar2->keycode[mode][index] == old_keycode) if (ar2->keycode[mode][index] == *old_keycode)
return 0; return 0;
} }
} }
__clear_bit(old_keycode, idev->keybit); __clear_bit(*old_keycode, idev->keybit);
return 0; return 0;
} }
...@@ -575,8 +612,8 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) ...@@ -575,8 +612,8 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
idev->open = ati_remote2_open; idev->open = ati_remote2_open;
idev->close = ati_remote2_close; idev->close = ati_remote2_close;
idev->getkeycode = ati_remote2_getkeycode; idev->getkeycode_new = ati_remote2_getkeycode;
idev->setkeycode = ati_remote2_setkeycode; idev->setkeycode_new = ati_remote2_setkeycode;
idev->name = ar2->name; idev->name = ar2->name;
idev->phys = ar2->phys; idev->phys = ar2->phys;
......
...@@ -280,7 +280,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev ...@@ -280,7 +280,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev
pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL); pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL);
if (!pm->configcr) if (!pm->configcr)
return -1; return -ENOMEM;
return 0; return 0;
} }
......
...@@ -699,7 +699,7 @@ int elantech_init(struct psmouse *psmouse) ...@@ -699,7 +699,7 @@ int elantech_init(struct psmouse *psmouse)
psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL); psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
if (!etd) if (!etd)
return -1; return -ENOMEM;
etd->parity[0] = 1; etd->parity[0] = 1;
for (i = 1; i < 256; i++) for (i = 1; i < 256; i++)
......
...@@ -1584,10 +1584,10 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co ...@@ -1584,10 +1584,10 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
if (!new_dev) if (!new_dev)
return -ENOMEM; return -ENOMEM;
while (serio->child) { while (!list_empty(&serio->children)) {
if (++retry > 3) { if (++retry > 3) {
printk(KERN_WARNING printk(KERN_WARNING
"psmouse: failed to destroy child port, " "psmouse: failed to destroy children ports, "
"protocol change aborted.\n"); "protocol change aborted.\n");
input_free_device(new_dev); input_free_device(new_dev);
return -EIO; return -EIO;
......
...@@ -294,7 +294,29 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c) ...@@ -294,7 +294,29 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c)
return 0; return 0;
} }
static inline int synaptics_is_pt_packet(unsigned char *buf) static int synaptics_pt_start(struct serio *serio)
{
struct psmouse *parent = serio_get_drvdata(serio->parent);
struct synaptics_data *priv = parent->private;
serio_pause_rx(parent->ps2dev.serio);
priv->pt_port = serio;
serio_continue_rx(parent->ps2dev.serio);
return 0;
}
static void synaptics_pt_stop(struct serio *serio)
{
struct psmouse *parent = serio_get_drvdata(serio->parent);
struct synaptics_data *priv = parent->private;
serio_pause_rx(parent->ps2dev.serio);
priv->pt_port = NULL;
serio_continue_rx(parent->ps2dev.serio);
}
static int synaptics_is_pt_packet(unsigned char *buf)
{ {
return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
} }
...@@ -315,9 +337,8 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet ...@@ -315,9 +337,8 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
static void synaptics_pt_activate(struct psmouse *psmouse) static void synaptics_pt_activate(struct psmouse *psmouse)
{ {
struct serio *ptport = psmouse->ps2dev.serio->child;
struct psmouse *child = serio_get_drvdata(ptport);
struct synaptics_data *priv = psmouse->private; struct synaptics_data *priv = psmouse->private;
struct psmouse *child = serio_get_drvdata(priv->pt_port);
/* adjust the touchpad to child's choice of protocol */ /* adjust the touchpad to child's choice of protocol */
if (child) { if (child) {
...@@ -345,6 +366,8 @@ static void synaptics_pt_create(struct psmouse *psmouse) ...@@ -345,6 +366,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
serio->write = synaptics_pt_write; serio->write = synaptics_pt_write;
serio->start = synaptics_pt_start;
serio->stop = synaptics_pt_stop;
serio->parent = psmouse->ps2dev.serio; serio->parent = psmouse->ps2dev.serio;
psmouse->pt_activate = synaptics_pt_activate; psmouse->pt_activate = synaptics_pt_activate;
...@@ -578,9 +601,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) ...@@ -578,9 +601,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
if (unlikely(priv->pkt_type == SYN_NEWABS)) if (unlikely(priv->pkt_type == SYN_NEWABS))
priv->pkt_type = synaptics_detect_pkt_type(psmouse); priv->pkt_type = synaptics_detect_pkt_type(psmouse);
if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
if (psmouse->ps2dev.serio->child) synaptics_is_pt_packet(psmouse->packet)) {
synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet); if (priv->pt_port)
synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
} else } else
synaptics_process_packet(psmouse); synaptics_process_packet(psmouse);
...@@ -731,7 +755,7 @@ int synaptics_init(struct psmouse *psmouse) ...@@ -731,7 +755,7 @@ int synaptics_init(struct psmouse *psmouse)
psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv) if (!priv)
return -1; return -ENOMEM;
psmouse_reset(psmouse); psmouse_reset(psmouse);
......
...@@ -110,6 +110,8 @@ struct synaptics_data { ...@@ -110,6 +110,8 @@ struct synaptics_data {
unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char pkt_type; /* packet type - old, new, etc */
unsigned char mode; /* current mode byte */ unsigned char mode; /* current mode byte */
int scroll; int scroll;
struct serio *pt_port; /* Pass-through serio port */
}; };
void synaptics_module_init(void); void synaptics_module_init(void);
......
...@@ -303,7 +303,7 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) ...@@ -303,7 +303,7 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL); psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
if (!psmouse->private) if (!psmouse->private)
return -1; return -ENOMEM;
psmouse->vendor = "IBM"; psmouse->vendor = "IBM";
psmouse->name = "TrackPoint"; psmouse->name = "TrackPoint";
......
...@@ -866,7 +866,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev, ...@@ -866,7 +866,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
spin_lock_init(&mousedev->client_lock); spin_lock_init(&mousedev->client_lock);
mutex_init(&mousedev->mutex); mutex_init(&mousedev->mutex);
lockdep_set_subclass(&mousedev->mutex, lockdep_set_subclass(&mousedev->mutex,
minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0); minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0);
init_waitqueue_head(&mousedev->wait); init_waitqueue_head(&mousedev->wait);
if (minor == MOUSEDEV_MIX) if (minor == MOUSEDEV_MIX)
......
...@@ -226,4 +226,13 @@ config SERIO_AMS_DELTA ...@@ -226,4 +226,13 @@ config SERIO_AMS_DELTA
To compile this driver as a module, choose M here; To compile this driver as a module, choose M here;
the module will be called ams_delta_serio. the module will be called ams_delta_serio.
config SERIO_PS2MULT
tristate "TQC PS/2 multiplexer"
help
Say Y here if you have the PS/2 line multiplexer like the one
present on TQC boads.
To compile this driver as a module, choose M here: the
module will be called ps2mult.
endif endif
...@@ -18,6 +18,7 @@ obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o ...@@ -18,6 +18,7 @@ obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_HP_SDC) += hp_sdc.o obj-$(CONFIG_HP_SDC) += hp_sdc.o
obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
obj-$(CONFIG_SERIO_RAW) += serio_raw.o obj-$(CONFIG_SERIO_RAW) += serio_raw.o
......
...@@ -1063,7 +1063,7 @@ static long i8042_panic_blink(int state) ...@@ -1063,7 +1063,7 @@ static long i8042_panic_blink(int state)
#ifdef CONFIG_X86 #ifdef CONFIG_X86
static void i8042_dritek_enable(void) static void i8042_dritek_enable(void)
{ {
char param = 0x90; unsigned char param = 0x90;
int error; int error;
error = i8042_command(&param, 0x1059); error = i8042_command(&param, 0x1059);
......
/*
* TQC PS/2 Multiplexer driver
*
* Copyright (C) 2010 Dmitry Eremin-Solenikov
*
* 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/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/serio.h>
MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>");
MODULE_DESCRIPTION("TQC PS/2 Multiplexer driver");
MODULE_LICENSE("GPL");
#define PS2MULT_KB_SELECTOR 0xA0
#define PS2MULT_MS_SELECTOR 0xA1
#define PS2MULT_ESCAPE 0x7D
#define PS2MULT_BSYNC 0x7E
#define PS2MULT_SESSION_START 0x55
#define PS2MULT_SESSION_END 0x56
struct ps2mult_port {
struct serio *serio;
unsigned char sel;
bool registered;
};
#define PS2MULT_NUM_PORTS 2
#define PS2MULT_KBD_PORT 0
#define PS2MULT_MOUSE_PORT 1
struct ps2mult {
struct serio *mx_serio;
struct ps2mult_port ports[PS2MULT_NUM_PORTS];
spinlock_t lock;
struct ps2mult_port *in_port;
struct ps2mult_port *out_port;
bool escape;
};
/* First MUST come PS2MULT_NUM_PORTS selectors */
static const unsigned char ps2mult_controls[] = {
PS2MULT_KB_SELECTOR, PS2MULT_MS_SELECTOR,
PS2MULT_ESCAPE, PS2MULT_BSYNC,
PS2MULT_SESSION_START, PS2MULT_SESSION_END,
};
static const struct serio_device_id ps2mult_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_PS2MULT,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, ps2mult_serio_ids);
static void ps2mult_select_port(struct ps2mult *psm, struct ps2mult_port *port)
{
struct serio *mx_serio = psm->mx_serio;
serio_write(mx_serio, port->sel);
psm->out_port = port;
dev_dbg(&mx_serio->dev, "switched to sel %02x\n", port->sel);
}
static int ps2mult_serio_write(struct serio *serio, unsigned char data)
{
struct serio *mx_port = serio->parent;
struct ps2mult *psm = serio_get_drvdata(mx_port);
struct ps2mult_port *port = serio->port_data;
bool need_escape;
unsigned long flags;
spin_lock_irqsave(&psm->lock, flags);
if (psm->out_port != port)
ps2mult_select_port(psm, port);
need_escape = memchr(ps2mult_controls, data, sizeof(ps2mult_controls));
dev_dbg(&serio->dev,
"write: %s%02x\n", need_escape ? "ESC " : "", data);
if (need_escape)
serio_write(mx_port, PS2MULT_ESCAPE);
serio_write(mx_port, data);
spin_unlock_irqrestore(&psm->lock, flags);
return 0;
}
static int ps2mult_serio_start(struct serio *serio)
{
struct ps2mult *psm = serio_get_drvdata(serio->parent);
struct ps2mult_port *port = serio->port_data;
unsigned long flags;
spin_lock_irqsave(&psm->lock, flags);
port->registered = true;
spin_unlock_irqrestore(&psm->lock, flags);
return 0;
}
static void ps2mult_serio_stop(struct serio *serio)
{
struct ps2mult *psm = serio_get_drvdata(serio->parent);
struct ps2mult_port *port = serio->port_data;
unsigned long flags;
spin_lock_irqsave(&psm->lock, flags);
port->registered = false;
spin_unlock_irqrestore(&psm->lock, flags);
}
static int ps2mult_create_port(struct ps2mult *psm, int i)
{
struct serio *mx_serio = psm->mx_serio;
struct serio *serio;
serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!serio)
return -ENOMEM;
strlcpy(serio->name, "TQC PS/2 Multiplexer", sizeof(serio->name));
snprintf(serio->phys, sizeof(serio->phys),
"%s/port%d", mx_serio->phys, i);
serio->id.type = SERIO_8042;
serio->write = ps2mult_serio_write;
serio->start = ps2mult_serio_start;
serio->stop = ps2mult_serio_stop;
serio->parent = psm->mx_serio;
serio->port_data = &psm->ports[i];
psm->ports[i].serio = serio;
return 0;
}
static void ps2mult_reset(struct ps2mult *psm)
{
unsigned long flags;
spin_lock_irqsave(&psm->lock, flags);
serio_write(psm->mx_serio, PS2MULT_SESSION_END);
serio_write(psm->mx_serio, PS2MULT_SESSION_START);
ps2mult_select_port(psm, &psm->ports[PS2MULT_KBD_PORT]);
spin_unlock_irqrestore(&psm->lock, flags);
}
static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
{
struct ps2mult *psm;
int i;
int error;
if (!serio->write)
return -EINVAL;
psm = kzalloc(sizeof(*psm), GFP_KERNEL);
if (!psm)
return -ENOMEM;
spin_lock_init(&psm->lock);
psm->mx_serio = serio;
for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
psm->ports[i].sel = ps2mult_controls[i];
error = ps2mult_create_port(psm, i);
if (error)
goto err_out;
}
psm->in_port = psm->out_port = &psm->ports[PS2MULT_KBD_PORT];
serio_set_drvdata(serio, psm);
error = serio_open(serio, drv);
if (error)
goto err_out;
ps2mult_reset(psm);
for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
struct serio *s = psm->ports[i].serio;
dev_info(&serio->dev, "%s port at %s\n", s->name, serio->phys);
serio_register_port(s);
}
return 0;
err_out:
while (--i >= 0)
kfree(psm->ports[i].serio);
kfree(serio);
return error;
}
static void ps2mult_disconnect(struct serio *serio)
{
struct ps2mult *psm = serio_get_drvdata(serio);
/* Note that serio core already take care of children ports */
serio_write(serio, PS2MULT_SESSION_END);
serio_close(serio);
kfree(psm);
serio_set_drvdata(serio, NULL);
}
static int ps2mult_reconnect(struct serio *serio)
{
struct ps2mult *psm = serio_get_drvdata(serio);
ps2mult_reset(psm);
return 0;
}
static irqreturn_t ps2mult_interrupt(struct serio *serio,
unsigned char data, unsigned int dfl)
{
struct ps2mult *psm = serio_get_drvdata(serio);
struct ps2mult_port *in_port;
unsigned long flags;
dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, dfl);
spin_lock_irqsave(&psm->lock, flags);
if (psm->escape) {
psm->escape = false;
in_port = psm->in_port;
if (in_port->registered)
serio_interrupt(in_port->serio, data, dfl);
goto out;
}
switch (data) {
case PS2MULT_ESCAPE:
dev_dbg(&serio->dev, "ESCAPE\n");
psm->escape = true;
break;
case PS2MULT_BSYNC:
dev_dbg(&serio->dev, "BSYNC\n");
psm->in_port = psm->out_port;
break;
case PS2MULT_SESSION_START:
dev_dbg(&serio->dev, "SS\n");
break;
case PS2MULT_SESSION_END:
dev_dbg(&serio->dev, "SE\n");
break;
case PS2MULT_KB_SELECTOR:
dev_dbg(&serio->dev, "KB\n");
psm->in_port = &psm->ports[PS2MULT_KBD_PORT];
break;
case PS2MULT_MS_SELECTOR:
dev_dbg(&serio->dev, "MS\n");
psm->in_port = &psm->ports[PS2MULT_MOUSE_PORT];
break;
default:
in_port = psm->in_port;
if (in_port->registered)
serio_interrupt(in_port->serio, data, dfl);
break;
}
out:
spin_unlock_irqrestore(&psm->lock, flags);
return IRQ_HANDLED;
}
static struct serio_driver ps2mult_drv = {
.driver = {
.name = "ps2mult",
},
.description = "TQC PS/2 Multiplexer driver",
.id_table = ps2mult_serio_ids,
.interrupt = ps2mult_interrupt,
.connect = ps2mult_connect,
.disconnect = ps2mult_disconnect,
.reconnect = ps2mult_reconnect,
};
static int __init ps2mult_init(void)
{
return serio_register_driver(&ps2mult_drv);
}
static void __exit ps2mult_exit(void)
{
serio_unregister_driver(&ps2mult_drv);
}
module_init(ps2mult_init);
module_exit(ps2mult_exit);
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/freezer.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core"); MODULE_DESCRIPTION("Serio abstraction core");
...@@ -56,7 +55,7 @@ static struct bus_type serio_bus; ...@@ -56,7 +55,7 @@ static struct bus_type serio_bus;
static void serio_add_port(struct serio *serio); static void serio_add_port(struct serio *serio);
static int serio_reconnect_port(struct serio *serio); static int serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio); static void serio_disconnect_port(struct serio *serio);
static void serio_reconnect_chain(struct serio *serio); static void serio_reconnect_subtree(struct serio *serio);
static void serio_attach_driver(struct serio_driver *drv); static void serio_attach_driver(struct serio_driver *drv);
static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
...@@ -152,7 +151,7 @@ static void serio_find_driver(struct serio *serio) ...@@ -152,7 +151,7 @@ static void serio_find_driver(struct serio *serio)
enum serio_event_type { enum serio_event_type {
SERIO_RESCAN_PORT, SERIO_RESCAN_PORT,
SERIO_RECONNECT_PORT, SERIO_RECONNECT_PORT,
SERIO_RECONNECT_CHAIN, SERIO_RECONNECT_SUBTREE,
SERIO_REGISTER_PORT, SERIO_REGISTER_PORT,
SERIO_ATTACH_DRIVER, SERIO_ATTACH_DRIVER,
}; };
...@@ -292,8 +291,8 @@ static void serio_handle_event(void) ...@@ -292,8 +291,8 @@ static void serio_handle_event(void)
serio_find_driver(event->object); serio_find_driver(event->object);
break; break;
case SERIO_RECONNECT_CHAIN: case SERIO_RECONNECT_SUBTREE:
serio_reconnect_chain(event->object); serio_reconnect_subtree(event->object);
break; break;
case SERIO_ATTACH_DRIVER: case SERIO_ATTACH_DRIVER:
...@@ -330,12 +329,10 @@ static void serio_remove_pending_events(void *object) ...@@ -330,12 +329,10 @@ static void serio_remove_pending_events(void *object)
} }
/* /*
* Destroy child serio port (if any) that has not been fully registered yet. * Locate child serio port (if any) that has not been fully registered yet.
* *
* Note that we rely on the fact that port can have only one child and therefore * Children are registered by driver's connect() handler so there can't be a
* only one child registration request can be pending. Additionally, children * grandchild pending registration together with a child.
* are registered by driver's connect() handler so there can't be a grandchild
* pending registration together with a child.
*/ */
static struct serio *serio_get_pending_child(struct serio *parent) static struct serio *serio_get_pending_child(struct serio *parent)
{ {
...@@ -449,7 +446,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * ...@@ -449,7 +446,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
if (!strncmp(buf, "none", count)) { if (!strncmp(buf, "none", count)) {
serio_disconnect_port(serio); serio_disconnect_port(serio);
} else if (!strncmp(buf, "reconnect", count)) { } else if (!strncmp(buf, "reconnect", count)) {
serio_reconnect_chain(serio); serio_reconnect_subtree(serio);
} else if (!strncmp(buf, "rescan", count)) { } else if (!strncmp(buf, "rescan", count)) {
serio_disconnect_port(serio); serio_disconnect_port(serio);
serio_find_driver(serio); serio_find_driver(serio);
...@@ -516,6 +513,8 @@ static void serio_init_port(struct serio *serio) ...@@ -516,6 +513,8 @@ static void serio_init_port(struct serio *serio)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
INIT_LIST_HEAD(&serio->node); INIT_LIST_HEAD(&serio->node);
INIT_LIST_HEAD(&serio->child_node);
INIT_LIST_HEAD(&serio->children);
spin_lock_init(&serio->lock); spin_lock_init(&serio->lock);
mutex_init(&serio->drv_mutex); mutex_init(&serio->drv_mutex);
device_initialize(&serio->dev); device_initialize(&serio->dev);
...@@ -538,12 +537,13 @@ static void serio_init_port(struct serio *serio) ...@@ -538,12 +537,13 @@ static void serio_init_port(struct serio *serio)
*/ */
static void serio_add_port(struct serio *serio) static void serio_add_port(struct serio *serio)
{ {
struct serio *parent = serio->parent;
int error; int error;
if (serio->parent) { if (parent) {
serio_pause_rx(serio->parent); serio_pause_rx(parent);
serio->parent->child = serio; list_add_tail(&serio->child_node, &parent->children);
serio_continue_rx(serio->parent); serio_continue_rx(parent);
} }
list_add_tail(&serio->node, &serio_list); list_add_tail(&serio->node, &serio_list);
...@@ -559,15 +559,14 @@ static void serio_add_port(struct serio *serio) ...@@ -559,15 +559,14 @@ static void serio_add_port(struct serio *serio)
} }
/* /*
* serio_destroy_port() completes deregistration process and removes * serio_destroy_port() completes unregistration process and removes
* port from the system * port from the system
*/ */
static void serio_destroy_port(struct serio *serio) static void serio_destroy_port(struct serio *serio)
{ {
struct serio *child; struct serio *child;
child = serio_get_pending_child(serio); while ((child = serio_get_pending_child(serio)) != NULL) {
if (child) {
serio_remove_pending_events(child); serio_remove_pending_events(child);
put_device(&child->dev); put_device(&child->dev);
} }
...@@ -577,7 +576,7 @@ static void serio_destroy_port(struct serio *serio) ...@@ -577,7 +576,7 @@ static void serio_destroy_port(struct serio *serio)
if (serio->parent) { if (serio->parent) {
serio_pause_rx(serio->parent); serio_pause_rx(serio->parent);
serio->parent->child = NULL; list_del_init(&serio->child_node);
serio_continue_rx(serio->parent); serio_continue_rx(serio->parent);
serio->parent = NULL; serio->parent = NULL;
} }
...@@ -609,46 +608,82 @@ static int serio_reconnect_port(struct serio *serio) ...@@ -609,46 +608,82 @@ static int serio_reconnect_port(struct serio *serio)
} }
/* /*
* Reconnect serio port and all its children (re-initialize attached devices) * Reconnect serio port and all its children (re-initialize attached
* devices).
*/ */
static void serio_reconnect_chain(struct serio *serio) static void serio_reconnect_subtree(struct serio *root)
{ {
struct serio *s = root;
int error;
do { do {
if (serio_reconnect_port(serio)) { error = serio_reconnect_port(s);
/* Ok, old children are now gone, we are done */ if (!error) {
/*
* Reconnect was successful, move on to do the
* first child.
*/
if (!list_empty(&s->children)) {
s = list_first_entry(&s->children,
struct serio, child_node);
continue;
}
}
/*
* Either it was a leaf node or reconnect failed and it
* became a leaf node. Continue reconnecting starting with
* the next sibling of the parent node.
*/
while (s != root) {
struct serio *parent = s->parent;
if (!list_is_last(&s->child_node, &parent->children)) {
s = list_entry(s->child_node.next,
struct serio, child_node);
break; break;
} }
serio = serio->child;
} while (serio); s = parent;
}
} while (s != root);
} }
/* /*
* serio_disconnect_port() unbinds a port from its driver. As a side effect * serio_disconnect_port() unbinds a port from its driver. As a side effect
* all child ports are unbound and destroyed. * all children ports are unbound and destroyed.
*/ */
static void serio_disconnect_port(struct serio *serio) static void serio_disconnect_port(struct serio *serio)
{ {
struct serio *s, *parent; struct serio *s = serio;
if (serio->child) {
/* /*
* Children ports should be disconnected and destroyed * Children ports should be disconnected and destroyed
* first, staring with the leaf one, since we don't want * first; we travel the tree in depth-first order.
* to do recursion
*/ */
for (s = serio; s->child; s = s->child) while (!list_empty(&serio->children)) {
/* empty */;
do { /* Locate a leaf */
parent = s->parent; while (!list_empty(&s->children))
s = list_first_entry(&s->children,
struct serio, child_node);
/*
* Prune this leaf node unless it is the one we
* started with.
*/
if (s != serio) {
struct serio *parent = s->parent;
device_release_driver(&s->dev); device_release_driver(&s->dev);
serio_destroy_port(s); serio_destroy_port(s);
} while ((s = parent) != serio);
s = parent;
}
} }
/* /*
* Ok, no children left, now disconnect this port * OK, no children left, now disconnect this port.
*/ */
device_release_driver(&serio->dev); device_release_driver(&serio->dev);
} }
...@@ -661,7 +696,7 @@ EXPORT_SYMBOL(serio_rescan); ...@@ -661,7 +696,7 @@ EXPORT_SYMBOL(serio_rescan);
void serio_reconnect(struct serio *serio) void serio_reconnect(struct serio *serio)
{ {
serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN); serio_queue_event(serio, NULL, SERIO_RECONNECT_SUBTREE);
} }
EXPORT_SYMBOL(serio_reconnect); EXPORT_SYMBOL(serio_reconnect);
...@@ -689,14 +724,16 @@ void serio_unregister_port(struct serio *serio) ...@@ -689,14 +724,16 @@ void serio_unregister_port(struct serio *serio)
EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_port);
/* /*
* Safely unregisters child port if one is present. * Safely unregisters children ports if they are present.
*/ */
void serio_unregister_child_port(struct serio *serio) void serio_unregister_child_port(struct serio *serio)
{ {
struct serio *s, *next;
mutex_lock(&serio_mutex); mutex_lock(&serio_mutex);
if (serio->child) { list_for_each_entry_safe(s, next, &serio->children, child_node) {
serio_disconnect_port(serio->child); serio_disconnect_port(s);
serio_destroy_port(serio->child); serio_destroy_port(s);
} }
mutex_unlock(&serio_mutex); mutex_unlock(&serio_mutex);
} }
......
...@@ -22,6 +22,37 @@ MODULE_DESCRIPTION("Generic support for sparse keymaps"); ...@@ -22,6 +22,37 @@ MODULE_DESCRIPTION("Generic support for sparse keymaps");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1"); MODULE_VERSION("0.1");
static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
const struct key_entry *k)
{
struct key_entry *key;
unsigned int idx = 0;
for (key = dev->keycode; key->type != KE_END; key++) {
if (key->type == KE_KEY) {
if (key == k)
break;
idx++;
}
}
return idx;
}
static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
unsigned int index)
{
struct key_entry *key;
unsigned int key_cnt = 0;
for (key = dev->keycode; key->type != KE_END; key++)
if (key->type == KE_KEY)
if (key_cnt++ == index)
return key;
return NULL;
}
/** /**
* sparse_keymap_entry_from_scancode - perform sparse keymap lookup * sparse_keymap_entry_from_scancode - perform sparse keymap lookup
* @dev: Input device using sparse keymap * @dev: Input device using sparse keymap
...@@ -64,16 +95,36 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, ...@@ -64,16 +95,36 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
} }
EXPORT_SYMBOL(sparse_keymap_entry_from_keycode); EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
const struct input_keymap_entry *ke)
{
struct key_entry *key;
unsigned int scancode;
if (ke->flags & INPUT_KEYMAP_BY_INDEX)
key = sparse_keymap_entry_by_index(dev, ke->index);
else if (input_scancode_to_scalar(ke, &scancode) == 0)
key = sparse_keymap_entry_from_scancode(dev, scancode);
else
key = NULL;
return key;
}
static int sparse_keymap_getkeycode(struct input_dev *dev, static int sparse_keymap_getkeycode(struct input_dev *dev,
unsigned int scancode, struct input_keymap_entry *ke)
unsigned int *keycode)
{ {
const struct key_entry *key; const struct key_entry *key;
if (dev->keycode) { if (dev->keycode) {
key = sparse_keymap_entry_from_scancode(dev, scancode); key = sparse_keymap_locate(dev, ke);
if (key && key->type == KE_KEY) { if (key && key->type == KE_KEY) {
*keycode = key->keycode; ke->keycode = key->keycode;
if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
ke->index =
sparse_keymap_get_key_index(dev, key);
ke->len = sizeof(key->code);
memcpy(ke->scancode, &key->code, sizeof(key->code));
return 0; return 0;
} }
} }
...@@ -82,20 +133,19 @@ static int sparse_keymap_getkeycode(struct input_dev *dev, ...@@ -82,20 +133,19 @@ static int sparse_keymap_getkeycode(struct input_dev *dev,
} }
static int sparse_keymap_setkeycode(struct input_dev *dev, static int sparse_keymap_setkeycode(struct input_dev *dev,
unsigned int scancode, const struct input_keymap_entry *ke,
unsigned int keycode) unsigned int *old_keycode)
{ {
struct key_entry *key; struct key_entry *key;
int old_keycode;
if (dev->keycode) { if (dev->keycode) {
key = sparse_keymap_entry_from_scancode(dev, scancode); key = sparse_keymap_locate(dev, ke);
if (key && key->type == KE_KEY) { if (key && key->type == KE_KEY) {
old_keycode = key->keycode; *old_keycode = key->keycode;
key->keycode = keycode; key->keycode = ke->keycode;
set_bit(keycode, dev->keybit); set_bit(ke->keycode, dev->keybit);
if (!sparse_keymap_entry_from_keycode(dev, old_keycode)) if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
clear_bit(old_keycode, dev->keybit); clear_bit(*old_keycode, dev->keybit);
return 0; return 0;
} }
} }
...@@ -159,15 +209,14 @@ int sparse_keymap_setup(struct input_dev *dev, ...@@ -159,15 +209,14 @@ int sparse_keymap_setup(struct input_dev *dev,
dev->keycode = map; dev->keycode = map;
dev->keycodemax = map_size; dev->keycodemax = map_size;
dev->getkeycode = sparse_keymap_getkeycode; dev->getkeycode_new = sparse_keymap_getkeycode;
dev->setkeycode = sparse_keymap_setkeycode; dev->setkeycode_new = sparse_keymap_setkeycode;
return 0; return 0;
err_out: err_out:
kfree(map); kfree(map);
return error; return error;
} }
EXPORT_SYMBOL(sparse_keymap_setup); EXPORT_SYMBOL(sparse_keymap_setup);
......
...@@ -49,6 +49,17 @@ config TABLET_USB_GTCO ...@@ -49,6 +49,17 @@ config TABLET_USB_GTCO
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called gtco. module will be called gtco.
config TABLET_USB_HANWANG
tristate "Hanwang Art Master III tablet support (USB)"
depends on USB_ARCH_HAS_HCD
select USB
help
Say Y here if you want to use the USB version of the Hanwang Art
Master III tablet.
To compile this driver as a module, choose M here: the
module will be called hanwang.
config TABLET_USB_KBTAB config TABLET_USB_KBTAB
tristate "KB Gear JamStudio tablet support (USB)" tristate "KB Gear JamStudio tablet support (USB)"
depends on USB_ARCH_HAS_HCD depends on USB_ARCH_HAS_HCD
......
...@@ -8,5 +8,6 @@ wacom-objs := wacom_wac.o wacom_sys.o ...@@ -8,5 +8,6 @@ wacom-objs := wacom_wac.o wacom_sys.o
obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o
obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o
obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o
obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o
This diff is collapsed.
...@@ -118,6 +118,7 @@ struct wacom { ...@@ -118,6 +118,7 @@ struct wacom {
extern const struct usb_device_id wacom_ids[]; extern const struct usb_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
void wacom_setup_device_quirks(struct wacom_features *features);
void wacom_setup_input_capabilities(struct input_dev *input_dev, void wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac); struct wacom_wac *wacom_wac);
#endif #endif
...@@ -120,7 +120,6 @@ static int wacom_open(struct input_dev *dev) ...@@ -120,7 +120,6 @@ static int wacom_open(struct input_dev *dev)
out: out:
mutex_unlock(&wacom->lock); mutex_unlock(&wacom->lock);
if (retval)
usb_autopm_put_interface(wacom->intf); usb_autopm_put_interface(wacom->intf);
return retval; return retval;
} }
...@@ -128,6 +127,9 @@ static int wacom_open(struct input_dev *dev) ...@@ -128,6 +127,9 @@ static int wacom_open(struct input_dev *dev)
static void wacom_close(struct input_dev *dev) static void wacom_close(struct input_dev *dev)
{ {
struct wacom *wacom = input_get_drvdata(dev); struct wacom *wacom = input_get_drvdata(dev);
int autopm_error;
autopm_error = usb_autopm_get_interface(wacom->intf);
mutex_lock(&wacom->lock); mutex_lock(&wacom->lock);
usb_kill_urb(wacom->irq); usb_kill_urb(wacom->irq);
...@@ -135,6 +137,7 @@ static void wacom_close(struct input_dev *dev) ...@@ -135,6 +137,7 @@ static void wacom_close(struct input_dev *dev)
wacom->intf->needs_remote_wakeup = 0; wacom->intf->needs_remote_wakeup = 0;
mutex_unlock(&wacom->lock); mutex_unlock(&wacom->lock);
if (!autopm_error)
usb_autopm_put_interface(wacom->intf); usb_autopm_put_interface(wacom->intf);
} }
...@@ -196,6 +199,16 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi ...@@ -196,6 +199,16 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
features->pktlen = WACOM_PKGLEN_TPC2FG; features->pktlen = WACOM_PKGLEN_TPC2FG;
features->device_type = BTN_TOOL_TRIPLETAP; features->device_type = BTN_TOOL_TRIPLETAP;
} }
if (features->type == BAMBOO_PT) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_BBTOUCH;
features->device_type = BTN_TOOL_TRIPLETAP;
features->x_phy =
get_unaligned_le16(&report[i + 5]);
features->x_max =
get_unaligned_le16(&report[i + 8]);
i += 15;
} else {
features->x_max = features->x_max =
get_unaligned_le16(&report[i + 3]); get_unaligned_le16(&report[i + 3]);
features->x_phy = features->x_phy =
...@@ -203,10 +216,13 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi ...@@ -203,10 +216,13 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
features->unit = report[i + 9]; features->unit = report[i + 9];
features->unitExpo = report[i + 11]; features->unitExpo = report[i + 11];
i += 12; i += 12;
}
} else if (pen) { } else if (pen) {
/* penabled only accepts exact bytes of data */ /* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG) if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE; features->pktlen = WACOM_PKGLEN_GRAPHIRE;
if (features->type == BAMBOO_PT)
features->pktlen = WACOM_PKGLEN_BBFUN;
features->device_type = BTN_TOOL_PEN; features->device_type = BTN_TOOL_PEN;
features->x_max = features->x_max =
get_unaligned_le16(&report[i + 3]); get_unaligned_le16(&report[i + 3]);
...@@ -235,6 +251,15 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi ...@@ -235,6 +251,15 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
features->y_phy = features->y_phy =
get_unaligned_le16(&report[i + 6]); get_unaligned_le16(&report[i + 6]);
i += 7; i += 7;
} else if (features->type == BAMBOO_PT) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_BBTOUCH;
features->device_type = BTN_TOOL_TRIPLETAP;
features->y_phy =
get_unaligned_le16(&report[i + 3]);
features->y_max =
get_unaligned_le16(&report[i + 6]);
i += 12;
} else { } else {
features->y_max = features->y_max =
features->x_max; features->x_max;
...@@ -246,6 +271,8 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi ...@@ -246,6 +271,8 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
/* penabled only accepts exact bytes of data */ /* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG) if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE; features->pktlen = WACOM_PKGLEN_GRAPHIRE;
if (features->type == BAMBOO_PT)
features->pktlen = WACOM_PKGLEN_BBFUN;
features->device_type = BTN_TOOL_PEN; features->device_type = BTN_TOOL_PEN;
features->y_max = features->y_max =
get_unaligned_le16(&report[i + 3]); get_unaligned_le16(&report[i + 3]);
...@@ -296,8 +323,9 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat ...@@ -296,8 +323,9 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
if (!rep_data) if (!rep_data)
return error; return error;
/* ask to report tablet data if it is 2FGT or not a Tablet PC */ /* ask to report tablet data if it is 2FGT Tablet PC or
if (features->device_type == BTN_TOOL_TRIPLETAP) { * not a Tablet PC */
if (features->type == TABLETPC2FG) {
do { do {
rep_data[0] = 3; rep_data[0] = 3;
rep_data[1] = 4; rep_data[1] = 4;
...@@ -309,7 +337,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat ...@@ -309,7 +337,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
WAC_HID_FEATURE_REPORT, report_id, WAC_HID_FEATURE_REPORT, report_id,
rep_data, 3); rep_data, 3);
} while ((error < 0 || rep_data[1] != 4) && limit++ < 5); } while ((error < 0 || rep_data[1] != 4) && limit++ < 5);
} else if (features->type != TABLETPC && features->type != TABLETPC2FG) { } else if (features->type != TABLETPC) {
do { do {
rep_data[0] = 2; rep_data[0] = 2;
rep_data[1] = 2; rep_data[1] = 2;
...@@ -334,11 +362,16 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, ...@@ -334,11 +362,16 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
struct usb_host_interface *interface = intf->cur_altsetting; struct usb_host_interface *interface = intf->cur_altsetting;
struct hid_descriptor *hid_desc; struct hid_descriptor *hid_desc;
/* default device to penabled */ /* default features */
features->device_type = BTN_TOOL_PEN; features->device_type = BTN_TOOL_PEN;
features->x_fuzz = 4;
/* only Tablet PCs need to retrieve the info */ features->y_fuzz = 4;
if ((features->type != TABLETPC) && (features->type != TABLETPC2FG)) features->pressure_fuzz = 0;
features->distance_fuzz = 0;
/* only Tablet PCs and Bamboo P&T need to retrieve the info */
if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
(features->type != BAMBOO_PT))
goto out; goto out;
if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) { if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
...@@ -353,12 +386,6 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, ...@@ -353,12 +386,6 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
if (error) if (error)
goto out; goto out;
/* touch device found but size is not defined. use default */
if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
features->x_max = 1023;
features->y_max = 1023;
}
out: out:
return error; return error;
} }
...@@ -494,9 +521,11 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -494,9 +521,11 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (error) if (error)
goto fail2; goto fail2;
wacom_setup_device_quirks(features);
strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
if (features->type == TABLETPC || features->type == TABLETPC2FG) { if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
/* Append the device type to the name */ /* Append the device type to the name */
strlcat(wacom_wac->name, strlcat(wacom_wac->name,
features->device_type == BTN_TOOL_PEN ? features->device_type == BTN_TOOL_PEN ?
......
This diff is collapsed.
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define WACOM_PKGLEN_INTUOS 10 #define WACOM_PKGLEN_INTUOS 10
#define WACOM_PKGLEN_TPC1FG 5 #define WACOM_PKGLEN_TPC1FG 5
#define WACOM_PKGLEN_TPC2FG 14 #define WACOM_PKGLEN_TPC2FG 14
#define WACOM_PKGLEN_BBTOUCH 20
/* device IDs */ /* device IDs */
#define STYLUS_DEVICE_ID 0x02 #define STYLUS_DEVICE_ID 0x02
...@@ -37,6 +38,13 @@ ...@@ -37,6 +38,13 @@
#define WACOM_REPORT_TPC1FG 6 #define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13 #define WACOM_REPORT_TPC2FG 13
/* device quirks */
#define WACOM_QUIRK_MULTI_INPUT 0x0001
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
/* largest reported tracking id */
#define MAX_TRACKING_ID 0xfff
enum { enum {
PENPARTNER = 0, PENPARTNER = 0,
GRAPHIRE, GRAPHIRE,
...@@ -44,6 +52,7 @@ enum { ...@@ -44,6 +52,7 @@ enum {
PTU, PTU,
PL, PL,
DTU, DTU,
BAMBOO_PT,
INTUOS, INTUOS,
INTUOS3S, INTUOS3S,
INTUOS3, INTUOS3,
...@@ -73,6 +82,11 @@ struct wacom_features { ...@@ -73,6 +82,11 @@ struct wacom_features {
int y_phy; int y_phy;
unsigned char unit; unsigned char unit;
unsigned char unitExpo; unsigned char unitExpo;
int x_fuzz;
int y_fuzz;
int pressure_fuzz;
int distance_fuzz;
unsigned quirks;
}; };
struct wacom_shared { struct wacom_shared {
...@@ -86,6 +100,7 @@ struct wacom_wac { ...@@ -86,6 +100,7 @@ struct wacom_wac {
int id[3]; int id[3];
__u32 serial[2]; __u32 serial[2];
int last_finger; int last_finger;
int trk_id;
struct wacom_features features; struct wacom_features features;
struct wacom_shared *shared; struct wacom_shared *shared;
struct input_dev *input; struct input_dev *input;
......
...@@ -98,6 +98,18 @@ config TOUCHSCREEN_BITSY ...@@ -98,6 +98,18 @@ config TOUCHSCREEN_BITSY
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called h3600_ts_input. module will be called h3600_ts_input.
config TOUCHSCREEN_BU21013
tristate "BU21013 based touch panel controllers"
depends on I2C
help
Say Y here if you have a bu21013 touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called bu21013_ts.
config TOUCHSCREEN_CY8CTMG110 config TOUCHSCREEN_CY8CTMG110
tristate "cy8ctmg110 touchscreen" tristate "cy8ctmg110 touchscreen"
depends on I2C depends on I2C
...@@ -214,6 +226,16 @@ config TOUCHSCREEN_WACOM_W8001 ...@@ -214,6 +226,16 @@ config TOUCHSCREEN_WACOM_W8001
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called wacom_w8001. module will be called wacom_w8001.
config TOUCHSCREEN_LPC32XX
tristate "LPC32XX touchscreen controller"
depends on ARCH_LPC32XX
help
Say Y here if you have a LPC32XX device and want
to support the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called lpc32xx_ts.
config TOUCHSCREEN_MCS5000 config TOUCHSCREEN_MCS5000
tristate "MELFAS MCS-5000 touchscreen" tristate "MELFAS MCS-5000 touchscreen"
depends on I2C depends on I2C
...@@ -250,6 +272,18 @@ config TOUCHSCREEN_INEXIO ...@@ -250,6 +272,18 @@ config TOUCHSCREEN_INEXIO
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called inexio. module will be called inexio.
config TOUCHSCREEN_INTEL_MID
tristate "Intel MID platform resistive touchscreen"
depends on INTEL_SCU_IPC
help
Say Y here if you have a Intel MID based touchscreen in
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called intel_mid_touch.
config TOUCHSCREEN_MK712 config TOUCHSCREEN_MK712
tristate "ICS MicroClock MK712 touchscreen" tristate "ICS MicroClock MK712 touchscreen"
help help
......
...@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o ...@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
...@@ -23,6 +24,8 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o ...@@ -23,6 +24,8 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
......
...@@ -191,13 +191,12 @@ struct ad7877 { ...@@ -191,13 +191,12 @@ struct ad7877 {
struct spi_message msg; struct spi_message msg;
struct mutex mutex; struct mutex mutex;
unsigned disabled:1; /* P: mutex */ bool disabled; /* P: mutex */
unsigned gpio3:1; /* P: mutex */ bool gpio3; /* P: mutex */
unsigned gpio4:1; /* P: mutex */ bool gpio4; /* P: mutex */
spinlock_t lock; spinlock_t lock;
struct timer_list timer; /* P: lock */ struct timer_list timer; /* P: lock */
unsigned pending:1; /* P: lock */
/* /*
* DMA (thus cache coherency maintenance) requires the * DMA (thus cache coherency maintenance) requires the
...@@ -206,8 +205,8 @@ struct ad7877 { ...@@ -206,8 +205,8 @@ struct ad7877 {
u16 conversion_data[AD7877_NR_SENSE] ____cacheline_aligned; u16 conversion_data[AD7877_NR_SENSE] ____cacheline_aligned;
}; };
static int gpio3; static bool gpio3;
module_param(gpio3, int, 0); module_param(gpio3, bool, 0);
MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3"); MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
/* /*
...@@ -230,6 +229,7 @@ static int ad7877_read(struct spi_device *spi, u16 reg) ...@@ -230,6 +229,7 @@ static int ad7877_read(struct spi_device *spi, u16 reg)
AD7877_READADD(reg)); AD7877_READADD(reg));
req->xfer[0].tx_buf = &req->command; req->xfer[0].tx_buf = &req->command;
req->xfer[0].len = 2; req->xfer[0].len = 2;
req->xfer[0].cs_change = 1;
req->xfer[1].rx_buf = &req->sample; req->xfer[1].rx_buf = &req->sample;
req->xfer[1].len = 2; req->xfer[1].len = 2;
...@@ -295,20 +295,25 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command) ...@@ -295,20 +295,25 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
req->xfer[0].tx_buf = &req->reset; req->xfer[0].tx_buf = &req->reset;
req->xfer[0].len = 2; req->xfer[0].len = 2;
req->xfer[0].cs_change = 1;
req->xfer[1].tx_buf = &req->ref_on; req->xfer[1].tx_buf = &req->ref_on;
req->xfer[1].len = 2; req->xfer[1].len = 2;
req->xfer[1].delay_usecs = ts->vref_delay_usecs; req->xfer[1].delay_usecs = ts->vref_delay_usecs;
req->xfer[1].cs_change = 1;
req->xfer[2].tx_buf = &req->command; req->xfer[2].tx_buf = &req->command;
req->xfer[2].len = 2; req->xfer[2].len = 2;
req->xfer[2].delay_usecs = ts->vref_delay_usecs; req->xfer[2].delay_usecs = ts->vref_delay_usecs;
req->xfer[2].cs_change = 1;
req->xfer[3].rx_buf = &req->sample; req->xfer[3].rx_buf = &req->sample;
req->xfer[3].len = 2; req->xfer[3].len = 2;
req->xfer[3].cs_change = 1;
req->xfer[4].tx_buf = &ts->cmd_crtl2; /*REF OFF*/ req->xfer[4].tx_buf = &ts->cmd_crtl2; /*REF OFF*/
req->xfer[4].len = 2; req->xfer[4].len = 2;
req->xfer[4].cs_change = 1;
req->xfer[5].tx_buf = &ts->cmd_crtl1; /*DEFAULT*/ req->xfer[5].tx_buf = &ts->cmd_crtl1; /*DEFAULT*/
req->xfer[5].len = 2; req->xfer[5].len = 2;
...@@ -327,7 +332,7 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command) ...@@ -327,7 +332,7 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
return status ? : sample; return status ? : sample;
} }
static void ad7877_rx(struct ad7877 *ts) static int ad7877_process_data(struct ad7877 *ts)
{ {
struct input_dev *input_dev = ts->input; struct input_dev *input_dev = ts->input;
unsigned Rt; unsigned Rt;
...@@ -354,11 +359,25 @@ static void ad7877_rx(struct ad7877 *ts) ...@@ -354,11 +359,25 @@ static void ad7877_rx(struct ad7877 *ts)
Rt /= z1; Rt /= z1;
Rt = (Rt + 2047) >> 12; Rt = (Rt + 2047) >> 12;
/*
* Sample found inconsistent, pressure is beyond
* the maximum. Don't report it to user space.
*/
if (Rt > ts->pressure_max)
return -EINVAL;
if (!timer_pending(&ts->timer))
input_report_key(input_dev, BTN_TOUCH, 1);
input_report_abs(input_dev, ABS_X, x); input_report_abs(input_dev, ABS_X, x);
input_report_abs(input_dev, ABS_Y, y); input_report_abs(input_dev, ABS_Y, y);
input_report_abs(input_dev, ABS_PRESSURE, Rt); input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev); input_sync(input_dev);
return 0;
} }
return -EINVAL;
} }
static inline void ad7877_ts_event_release(struct ad7877 *ts) static inline void ad7877_ts_event_release(struct ad7877 *ts)
...@@ -366,72 +385,56 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts) ...@@ -366,72 +385,56 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
struct input_dev *input_dev = ts->input; struct input_dev *input_dev = ts->input;
input_report_abs(input_dev, ABS_PRESSURE, 0); input_report_abs(input_dev, ABS_PRESSURE, 0);
input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev); input_sync(input_dev);
} }
static void ad7877_timer(unsigned long handle) static void ad7877_timer(unsigned long handle)
{ {
struct ad7877 *ts = (void *)handle; struct ad7877 *ts = (void *)handle;
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
ad7877_ts_event_release(ts); ad7877_ts_event_release(ts);
spin_unlock_irqrestore(&ts->lock, flags);
} }
static irqreturn_t ad7877_irq(int irq, void *handle) static irqreturn_t ad7877_irq(int irq, void *handle)
{ {
struct ad7877 *ts = handle; struct ad7877 *ts = handle;
unsigned long flags; unsigned long flags;
int status; int error;
/* error = spi_sync(ts->spi, &ts->msg);
* The repeated conversion sequencer controlled by TMR kicked off if (error) {
* too fast. We ignore the last and process the sample sequence dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
* currently in the queue. It can't be older than 9.4ms, and we goto out;
* need to avoid that ts->msg doesn't get issued twice while in work. }
*/
spin_lock_irqsave(&ts->lock, flags); spin_lock_irqsave(&ts->lock, flags);
if (!ts->pending) { error = ad7877_process_data(ts);
ts->pending = 1; if (!error)
mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
status = spi_async(ts->spi, &ts->msg);
if (status)
dev_err(&ts->spi->dev, "spi_sync --> %d\n", status);
}
spin_unlock_irqrestore(&ts->lock, flags); spin_unlock_irqrestore(&ts->lock, flags);
out:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void ad7877_callback(void *_ts)
{
struct ad7877 *ts = _ts;
spin_lock_irq(&ts->lock);
ad7877_rx(ts);
ts->pending = 0;
mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
spin_unlock_irq(&ts->lock);
}
static void ad7877_disable(struct ad7877 *ts) static void ad7877_disable(struct ad7877 *ts)
{ {
mutex_lock(&ts->mutex); mutex_lock(&ts->mutex);
if (!ts->disabled) { if (!ts->disabled) {
ts->disabled = 1; ts->disabled = true;
disable_irq(ts->spi->irq); disable_irq(ts->spi->irq);
/* Wait for spi_async callback */
while (ts->pending)
msleep(1);
if (del_timer_sync(&ts->timer)) if (del_timer_sync(&ts->timer))
ad7877_ts_event_release(ts); ad7877_ts_event_release(ts);
} }
/* we know the chip's in lowpower mode since we always /*
* We know the chip's in lowpower mode since we always
* leave it that way after every request * leave it that way after every request
*/ */
...@@ -443,7 +446,7 @@ static void ad7877_enable(struct ad7877 *ts) ...@@ -443,7 +446,7 @@ static void ad7877_enable(struct ad7877 *ts)
mutex_lock(&ts->mutex); mutex_lock(&ts->mutex);
if (ts->disabled) { if (ts->disabled) {
ts->disabled = 0; ts->disabled = false;
enable_irq(ts->spi->irq); enable_irq(ts->spi->irq);
} }
...@@ -597,15 +600,34 @@ static struct attribute *ad7877_attributes[] = { ...@@ -597,15 +600,34 @@ static struct attribute *ad7877_attributes[] = {
&dev_attr_temp2.attr, &dev_attr_temp2.attr,
&dev_attr_aux1.attr, &dev_attr_aux1.attr,
&dev_attr_aux2.attr, &dev_attr_aux2.attr,
&dev_attr_aux3.attr,
&dev_attr_bat1.attr, &dev_attr_bat1.attr,
&dev_attr_bat2.attr, &dev_attr_bat2.attr,
&dev_attr_disable.attr, &dev_attr_disable.attr,
&dev_attr_dac.attr, &dev_attr_dac.attr,
&dev_attr_gpio3.attr,
&dev_attr_gpio4.attr, &dev_attr_gpio4.attr,
NULL NULL
}; };
static mode_t ad7877_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
mode_t mode = attr->mode;
if (attr == &dev_attr_aux3.attr) {
if (gpio3)
mode = 0;
} else if (attr == &dev_attr_gpio3.attr) {
if (!gpio3)
mode = 0;
}
return mode;
}
static const struct attribute_group ad7877_attr_group = { static const struct attribute_group ad7877_attr_group = {
.is_visible = ad7877_attr_is_visible,
.attrs = ad7877_attributes, .attrs = ad7877_attributes,
}; };
...@@ -635,22 +657,25 @@ static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts) ...@@ -635,22 +657,25 @@ static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
spi_message_init(m); spi_message_init(m);
m->complete = ad7877_callback;
m->context = ts; m->context = ts;
ts->xfer[0].tx_buf = &ts->cmd_crtl1; ts->xfer[0].tx_buf = &ts->cmd_crtl1;
ts->xfer[0].len = 2; ts->xfer[0].len = 2;
ts->xfer[0].cs_change = 1;
spi_message_add_tail(&ts->xfer[0], m); spi_message_add_tail(&ts->xfer[0], m);
ts->xfer[1].tx_buf = &ts->cmd_dummy; /* Send ZERO */ ts->xfer[1].tx_buf = &ts->cmd_dummy; /* Send ZERO */
ts->xfer[1].len = 2; ts->xfer[1].len = 2;
ts->xfer[1].cs_change = 1;
spi_message_add_tail(&ts->xfer[1], m); spi_message_add_tail(&ts->xfer[1], m);
for (i = 0; i < 11; i++) { for (i = 0; i < AD7877_NR_SENSE; i++) {
ts->xfer[i + 2].rx_buf = &ts->conversion_data[AD7877_SEQ_YPOS + i]; ts->xfer[i + 2].rx_buf = &ts->conversion_data[AD7877_SEQ_YPOS + i];
ts->xfer[i + 2].len = 2; ts->xfer[i + 2].len = 2;
if (i < (AD7877_NR_SENSE - 1))
ts->xfer[i + 2].cs_change = 1;
spi_message_add_tail(&ts->xfer[i + 2], m); spi_message_add_tail(&ts->xfer[i + 2], m);
} }
} }
...@@ -718,6 +743,8 @@ static int __devinit ad7877_probe(struct spi_device *spi) ...@@ -718,6 +743,8 @@ static int __devinit ad7877_probe(struct spi_device *spi)
input_dev->phys = ts->phys; input_dev->phys = ts->phys;
input_dev->dev.parent = &spi->dev; input_dev->dev.parent = &spi->dev;
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(EV_ABS, input_dev->evbit); __set_bit(EV_ABS, input_dev->evbit);
__set_bit(ABS_X, input_dev->absbit); __set_bit(ABS_X, input_dev->absbit);
__set_bit(ABS_Y, input_dev->absbit); __set_bit(ABS_Y, input_dev->absbit);
...@@ -752,7 +779,8 @@ static int __devinit ad7877_probe(struct spi_device *spi) ...@@ -752,7 +779,8 @@ static int __devinit ad7877_probe(struct spi_device *spi)
/* Request AD7877 /DAV GPIO interrupt */ /* Request AD7877 /DAV GPIO interrupt */
err = request_irq(spi->irq, ad7877_irq, IRQF_TRIGGER_FALLING, err = request_threaded_irq(spi->irq, NULL, ad7877_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
spi->dev.driver->name, ts); spi->dev.driver->name, ts);
if (err) { if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
...@@ -763,20 +791,12 @@ static int __devinit ad7877_probe(struct spi_device *spi) ...@@ -763,20 +791,12 @@ static int __devinit ad7877_probe(struct spi_device *spi)
if (err) if (err)
goto err_free_irq; goto err_free_irq;
err = device_create_file(&spi->dev,
gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
if (err)
goto err_remove_attr_group;
err = input_register_device(input_dev); err = input_register_device(input_dev);
if (err) if (err)
goto err_remove_attr; goto err_remove_attr_group;
return 0; return 0;
err_remove_attr:
device_remove_file(&spi->dev,
gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
err_remove_attr_group: err_remove_attr_group:
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group); sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
err_free_irq: err_free_irq:
...@@ -793,8 +813,6 @@ static int __devexit ad7877_remove(struct spi_device *spi) ...@@ -793,8 +813,6 @@ static int __devexit ad7877_remove(struct spi_device *spi)
struct ad7877 *ts = dev_get_drvdata(&spi->dev); struct ad7877 *ts = dev_get_drvdata(&spi->dev);
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group); sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
device_remove_file(&spi->dev,
gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
ad7877_disable(ts); ad7877_disable(ts);
free_irq(ts->spi->irq, ts); free_irq(ts->spi->irq, ts);
......
This diff is collapsed.
This diff is collapsed.
...@@ -206,9 +206,9 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client, ...@@ -206,9 +206,9 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client,
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, input_set_abs_params(input_dev, ABS_X,
CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0); CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
input_set_abs_params(input_dev, ABS_Y, input_set_abs_params(input_dev, ABS_Y,
CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0); CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
if (ts->reset_pin) { if (ts->reset_pin) {
err = gpio_request(ts->reset_pin, NULL); err = gpio_request(ts->reset_pin, NULL);
......
...@@ -107,8 +107,7 @@ static int __init hp680_ts_init(void) ...@@ -107,8 +107,7 @@ static int __init hp680_ts_init(void)
return 0; return 0;
fail2: free_irq(HP680_TS_IRQ, NULL); fail2: free_irq(HP680_TS_IRQ, NULL);
cancel_delayed_work(&work); cancel_delayed_work_sync(&work);
flush_scheduled_work();
fail1: input_free_device(hp680_ts_dev); fail1: input_free_device(hp680_ts_dev);
return err; return err;
} }
...@@ -116,8 +115,7 @@ static int __init hp680_ts_init(void) ...@@ -116,8 +115,7 @@ static int __init hp680_ts_init(void)
static void __exit hp680_ts_exit(void) static void __exit hp680_ts_exit(void)
{ {
free_irq(HP680_TS_IRQ, NULL); free_irq(HP680_TS_IRQ, NULL);
cancel_delayed_work(&work); cancel_delayed_work_sync(&work);
flush_scheduled_work();
input_unregister_device(hp680_ts_dev); input_unregister_device(hp680_ts_dev);
} }
......
This diff is collapsed.
...@@ -350,7 +350,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev) ...@@ -350,7 +350,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev)
err_tcirq: err_tcirq:
free_irq(ts.irq_tc, ts.input); free_irq(ts.irq_tc, ts.input);
err_inputdev: err_inputdev:
input_unregister_device(ts.input); input_free_device(ts.input);
err_iomap: err_iomap:
iounmap(ts.io); iounmap(ts.io);
err_clk: err_clk:
......
...@@ -268,7 +268,7 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev) ...@@ -268,7 +268,7 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
struct stmpe_touch *ts; struct stmpe_touch *ts;
struct input_dev *idev; struct input_dev *idev;
struct stmpe_ts_platform_data *ts_pdata = NULL; struct stmpe_ts_platform_data *ts_pdata = NULL;
int ret = 0; int ret;
int ts_irq; int ts_irq;
ts_irq = platform_get_irq_byname(pdev, "FIFO_TH"); ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
...@@ -276,12 +276,16 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev) ...@@ -276,12 +276,16 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
return ts_irq; return ts_irq;
ts = kzalloc(sizeof(*ts), GFP_KERNEL); ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (!ts) if (!ts) {
ret = -ENOMEM;
goto err_out; goto err_out;
}
idev = input_allocate_device(); idev = input_allocate_device();
if (!idev) if (!idev) {
ret = -ENOMEM;
goto err_free_ts; goto err_free_ts;
}
platform_set_drvdata(pdev, ts); platform_set_drvdata(pdev, ts);
ts->stmpe = stmpe; ts->stmpe = stmpe;
...@@ -361,7 +365,6 @@ static int __devexit stmpe_ts_remove(struct platform_device *pdev) ...@@ -361,7 +365,6 @@ static int __devexit stmpe_ts_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
input_unregister_device(ts->idev); input_unregister_device(ts->idev);
input_free_device(ts->idev);
kfree(ts); kfree(ts);
......
...@@ -335,6 +335,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev) ...@@ -335,6 +335,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
dev_err(tsc->dev, "schedule failed"); dev_err(tsc->dev, "schedule failed");
goto err2; goto err2;
} }
platform_set_drvdata(pdev, tps6507x_dev);
return 0; return 0;
...@@ -358,7 +359,7 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev) ...@@ -358,7 +359,7 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&tsc->work); cancel_delayed_work_sync(&tsc->work);
destroy_workqueue(tsc->wq); destroy_workqueue(tsc->wq);
input_free_device(input_dev); input_unregister_device(input_dev);
tps6507x_dev->ts = NULL; tps6507x_dev->ts = NULL;
kfree(tsc); kfree(tsc);
......
...@@ -265,7 +265,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client, ...@@ -265,7 +265,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct tsc2007 *ts; struct tsc2007 *ts;
struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data; struct tsc2007_platform_data *pdata = client->dev.platform_data;
struct input_dev *input_dev; struct input_dev *input_dev;
int err; int err;
......
This diff is collapsed.
...@@ -125,6 +125,8 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) ...@@ -125,6 +125,8 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
{ {
int power_adc = 0, auxval; int power_adc = 0, auxval;
u16 power = 0; u16 power = 0;
int rc = 0;
int timeout = 0;
/* get codec */ /* get codec */
mutex_lock(&wm->codec_mutex); mutex_lock(&wm->codec_mutex);
...@@ -143,7 +145,9 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) ...@@ -143,7 +145,9 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
/* Turn polling mode on to read AUX ADC */ /* Turn polling mode on to read AUX ADC */
wm->pen_probably_down = 1; wm->pen_probably_down = 1;
wm->codec->poll_sample(wm, adcsel, &auxval);
while (rc != RC_VALID && timeout++ < 5)
rc = wm->codec->poll_sample(wm, adcsel, &auxval);
if (power_adc) if (power_adc)
wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000); wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000);
...@@ -152,8 +156,15 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) ...@@ -152,8 +156,15 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
wm->pen_probably_down = 0; wm->pen_probably_down = 0;
if (timeout >= 5) {
dev_err(wm->dev,
"timeout reading auxadc %d, disabling digitiser\n",
adcsel);
wm->codec->dig_enable(wm, false);
}
mutex_unlock(&wm->codec_mutex); mutex_unlock(&wm->codec_mutex);
return auxval & 0xfff; return (rc == RC_VALID ? auxval & 0xfff : -EBUSY);
} }
EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc); EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
...@@ -684,8 +695,7 @@ static int wm97xx_probe(struct device *dev) ...@@ -684,8 +695,7 @@ static int wm97xx_probe(struct device *dev)
touch_reg_err: touch_reg_err:
platform_device_put(wm->touch_dev); platform_device_put(wm->touch_dev);
touch_err: touch_err:
platform_device_unregister(wm->battery_dev); platform_device_del(wm->battery_dev);
wm->battery_dev = NULL;
batt_reg_err: batt_reg_err:
platform_device_put(wm->battery_dev); platform_device_put(wm->battery_dev);
batt_err: batt_err:
......
This diff is collapsed.
This diff is collapsed.
...@@ -141,8 +141,6 @@ source "drivers/staging/adis16255/Kconfig" ...@@ -141,8 +141,6 @@ source "drivers/staging/adis16255/Kconfig"
source "drivers/staging/xgifb/Kconfig" source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/mrst-touchscreen/Kconfig"
source "drivers/staging/msm/Kconfig" source "drivers/staging/msm/Kconfig"
source "drivers/staging/lirc/Kconfig" source "drivers/staging/lirc/Kconfig"
......
...@@ -52,7 +52,6 @@ obj-$(CONFIG_CXT1E1) += cxt1e1/ ...@@ -52,7 +52,6 @@ obj-$(CONFIG_CXT1E1) += cxt1e1/
obj-$(CONFIG_TI_ST) += ti-st/ obj-$(CONFIG_TI_ST) += ti-st/
obj-$(CONFIG_ADIS16255) += adis16255/ obj-$(CONFIG_ADIS16255) += adis16255/
obj-$(CONFIG_FB_XGI) += xgifb/ obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/
obj-$(CONFIG_MSM_STAGING) += msm/ obj-$(CONFIG_MSM_STAGING) += msm/
obj-$(CONFIG_EASYCAP) += easycap/ obj-$(CONFIG_EASYCAP) += easycap/
obj-$(CONFIG_SOLO6X10) += solo6x10/ obj-$(CONFIG_SOLO6X10) += solo6x10/
......
This diff is collapsed.
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) := intel_mid_touch.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment