forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (22 commits) Input: ALPS - add interleaved protocol support (Dell E6x00 series) Input: keyboard - don't override beep with a bell Input: altera_ps2 - fix test of unsigned in altera_ps2_probe() Input: add mc13783 touchscreen driver Input: ep93xx_keypad - update driver to new core support Input: wacom - separate pen from express keys on Graphire Input: wacom - add defines for data packet report IDs Input: wacom - add support for new LCD tablets Input: wacom - add defines for packet lengths of various devices Input: wacom - ensure the device is initialized properly upon resume Input: at32psif - do not sleep in atomic context Input: i8042 - add Gigabyte M1022M to the noloop list Input: i8042 - allow installing platform filters for incoming data Input: i8042 - fix locking in interrupt routine Input: ALPS - do not set REL_X/REL_Y capabilities on the touchpad Input: document use of input_event() function Input: sa1111ps2 - annotate probe() and remove() methods Input: ambakmi - annotate probe() and remove() methods Input: gscps2 - fix probe() and remove() annotations Input: altera_ps2 - add annotations to probe and remove methods ...
This commit is contained in:
commit
238ccbb050
@ -5,9 +5,6 @@
|
||||
#ifndef __ASM_ARCH_EP93XX_KEYPAD_H
|
||||
#define __ASM_ARCH_EP93XX_KEYPAD_H
|
||||
|
||||
#define MAX_MATRIX_KEY_ROWS (8)
|
||||
#define MAX_MATRIX_KEY_COLS (8)
|
||||
|
||||
/* flags for the ep93xx_keypad driver */
|
||||
#define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */
|
||||
#define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */
|
||||
@ -18,8 +15,6 @@
|
||||
|
||||
/**
|
||||
* struct ep93xx_keypad_platform_data - platform specific device structure
|
||||
* @matrix_key_rows: number of rows in the keypad matrix
|
||||
* @matrix_key_cols: number of columns in the keypad matrix
|
||||
* @matrix_key_map: array of keycodes defining the keypad matrix
|
||||
* @matrix_key_map_size: ARRAY_SIZE(matrix_key_map)
|
||||
* @debounce: debounce start count; terminal count is 0xff
|
||||
@ -27,8 +22,6 @@
|
||||
* @flags: see above
|
||||
*/
|
||||
struct ep93xx_keypad_platform_data {
|
||||
unsigned int matrix_key_rows;
|
||||
unsigned int matrix_key_cols;
|
||||
unsigned int *matrix_key_map;
|
||||
int matrix_key_map_size;
|
||||
unsigned int debounce;
|
||||
@ -36,7 +29,7 @@ struct ep93xx_keypad_platform_data {
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* macro for creating the matrix_key_map table */
|
||||
#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val))
|
||||
#define EP93XX_MATRIX_ROWS (8)
|
||||
#define EP93XX_MATRIX_COLS (8)
|
||||
|
||||
#endif /* __ASM_ARCH_EP93XX_KEYPAD_H */
|
||||
|
@ -233,7 +233,8 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
|
||||
}
|
||||
|
||||
/*
|
||||
* Making beeps and bells.
|
||||
* Making beeps and bells. Note that we prefer beeps to bells, but when
|
||||
* shutting the sound off we do both.
|
||||
*/
|
||||
|
||||
static int kd_sound_helper(struct input_handle *handle, void *data)
|
||||
@ -242,9 +243,12 @@ static int kd_sound_helper(struct input_handle *handle, void *data)
|
||||
struct input_dev *dev = handle->dev;
|
||||
|
||||
if (test_bit(EV_SND, dev->evbit)) {
|
||||
if (test_bit(SND_TONE, dev->sndbit))
|
||||
if (test_bit(SND_TONE, dev->sndbit)) {
|
||||
input_inject_event(handle, EV_SND, SND_TONE, *hz);
|
||||
if (test_bit(SND_BELL, handle->dev->sndbit))
|
||||
if (*hz)
|
||||
return 0;
|
||||
}
|
||||
if (test_bit(SND_BELL, dev->sndbit))
|
||||
input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
|
||||
}
|
||||
|
||||
|
@ -296,9 +296,15 @@ static void input_handle_event(struct input_dev *dev,
|
||||
* @value: value of the event
|
||||
*
|
||||
* This function should be used by drivers implementing various input
|
||||
* devices. See also input_inject_event().
|
||||
* devices to report input events. See also input_inject_event().
|
||||
*
|
||||
* NOTE: input_event() may be safely used right after input device was
|
||||
* allocated with input_allocate_device(), even before it is registered
|
||||
* with input_register_device(), but the event will not reach any of the
|
||||
* input handlers. Such early invocation of input_event() may be used
|
||||
* to 'seed' initial state of a switch or initial position of absolute
|
||||
* axis, etc.
|
||||
*/
|
||||
|
||||
void input_event(struct input_dev *dev,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
|
@ -22,11 +22,11 @@
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/ep93xx_keypad.h>
|
||||
|
||||
/*
|
||||
@ -60,38 +60,37 @@
|
||||
#define KEY_REG_KEY1_MASK (0x0000003f)
|
||||
#define KEY_REG_KEY1_SHIFT (0)
|
||||
|
||||
#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off))
|
||||
#define keypad_writel(v, off) __raw_writel((v), keypad->mmio_base + (off))
|
||||
|
||||
#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
|
||||
#define EP93XX_MATRIX_SIZE (EP93XX_MATRIX_ROWS * EP93XX_MATRIX_COLS)
|
||||
|
||||
struct ep93xx_keypad {
|
||||
struct ep93xx_keypad_platform_data *pdata;
|
||||
|
||||
struct clk *clk;
|
||||
struct input_dev *input_dev;
|
||||
struct clk *clk;
|
||||
|
||||
void __iomem *mmio_base;
|
||||
|
||||
int irq;
|
||||
int enabled;
|
||||
unsigned int matrix_keycodes[EP93XX_MATRIX_SIZE];
|
||||
|
||||
int key1;
|
||||
int key2;
|
||||
|
||||
unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM];
|
||||
int irq;
|
||||
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad)
|
||||
{
|
||||
struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
unsigned int *key;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pdata->matrix_key_map_size; i++) {
|
||||
unsigned int key = pdata->matrix_key_map[i];
|
||||
int row = (key >> 28) & 0xf;
|
||||
int col = (key >> 24) & 0xf;
|
||||
int code = key & 0xffffff;
|
||||
key = &pdata->matrix_key_map[0];
|
||||
for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
|
||||
int row = KEY_ROW(*key);
|
||||
int col = KEY_COL(*key);
|
||||
int code = KEY_VAL(*key);
|
||||
|
||||
keypad->matrix_keycodes[(row << 3) + col] = code;
|
||||
__set_bit(code, input_dev->keybit);
|
||||
@ -102,9 +101,11 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct ep93xx_keypad *keypad = dev_id;
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
unsigned int status = keypad_readl(KEY_REG);
|
||||
unsigned int status;
|
||||
int keycode, key1, key2;
|
||||
|
||||
status = __raw_readl(keypad->mmio_base + KEY_REG);
|
||||
|
||||
keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT;
|
||||
key1 = keypad->matrix_keycodes[keycode];
|
||||
|
||||
@ -152,7 +153,10 @@ static void ep93xx_keypad_config(struct ep93xx_keypad *keypad)
|
||||
struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
|
||||
unsigned int val = 0;
|
||||
|
||||
clk_set_rate(keypad->clk, pdata->flags & EP93XX_KEYPAD_KDIV);
|
||||
if (pdata->flags & EP93XX_KEYPAD_KDIV)
|
||||
clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV4);
|
||||
else
|
||||
clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV16);
|
||||
|
||||
if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY)
|
||||
val |= KEY_INIT_DIS3KY;
|
||||
@ -167,7 +171,7 @@ static void ep93xx_keypad_config(struct ep93xx_keypad *keypad)
|
||||
|
||||
val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK);
|
||||
|
||||
keypad_writel(val, KEY_INIT);
|
||||
__raw_writel(val, keypad->mmio_base + KEY_INIT);
|
||||
}
|
||||
|
||||
static int ep93xx_keypad_open(struct input_dev *pdev)
|
||||
@ -177,7 +181,7 @@ static int ep93xx_keypad_open(struct input_dev *pdev)
|
||||
if (!keypad->enabled) {
|
||||
ep93xx_keypad_config(keypad);
|
||||
clk_enable(keypad->clk);
|
||||
keypad->enabled = 1;
|
||||
keypad->enabled = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -189,7 +193,7 @@ static void ep93xx_keypad_close(struct input_dev *pdev)
|
||||
|
||||
if (keypad->enabled) {
|
||||
clk_disable(keypad->clk);
|
||||
keypad->enabled = 0;
|
||||
keypad->enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,7 +215,7 @@ static int ep93xx_keypad_suspend(struct platform_device *pdev,
|
||||
|
||||
if (keypad->enabled) {
|
||||
clk_disable(keypad->clk);
|
||||
keypad->enabled = 0;
|
||||
keypad->enabled = false;
|
||||
}
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
@ -236,7 +240,7 @@ static int ep93xx_keypad_resume(struct platform_device *pdev)
|
||||
if (!keypad->enabled) {
|
||||
ep93xx_keypad_config(keypad);
|
||||
clk_enable(keypad->clk);
|
||||
keypad->enabled = 1;
|
||||
keypad->enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,88 +256,56 @@ static int ep93xx_keypad_resume(struct platform_device *pdev)
|
||||
static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_keypad *keypad;
|
||||
struct ep93xx_keypad_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct input_dev *input_dev;
|
||||
struct resource *res;
|
||||
int irq, err, i, gpio;
|
||||
|
||||
if (!pdata ||
|
||||
!pdata->matrix_key_rows ||
|
||||
pdata->matrix_key_rows > MAX_MATRIX_KEY_ROWS ||
|
||||
!pdata->matrix_key_cols ||
|
||||
pdata->matrix_key_cols > MAX_MATRIX_KEY_COLS) {
|
||||
dev_err(&pdev->dev, "invalid or missing platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
int err;
|
||||
|
||||
keypad = kzalloc(sizeof(struct ep93xx_keypad), GFP_KERNEL);
|
||||
if (!keypad) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
if (!keypad)
|
||||
return -ENOMEM;
|
||||
|
||||
keypad->pdata = pdev->dev.platform_data;
|
||||
if (!keypad->pdata) {
|
||||
err = -EINVAL;
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
keypad->pdata = pdata;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get keypad irq\n");
|
||||
keypad->irq = platform_get_irq(pdev, 0);
|
||||
if (!keypad->irq) {
|
||||
err = -ENXIO;
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "failed to get I/O memory\n");
|
||||
err = -ENXIO;
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
res = request_mem_region(res->start, resource_size(res), pdev->name);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "failed to request I/O memory\n");
|
||||
err = -EBUSY;
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
keypad->mmio_base = ioremap(res->start, resource_size(res));
|
||||
if (keypad->mmio_base == NULL) {
|
||||
dev_err(&pdev->dev, "failed to remap I/O memory\n");
|
||||
err = -ENXIO;
|
||||
goto failed_free_mem;
|
||||
}
|
||||
|
||||
/* Request the needed GPIO's */
|
||||
gpio = EP93XX_GPIO_LINE_ROW0;
|
||||
for (i = 0; i < keypad->pdata->matrix_key_rows; i++, gpio++) {
|
||||
err = gpio_request(gpio, pdev->name);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to request gpio-%d\n",
|
||||
gpio);
|
||||
goto failed_free_rows;
|
||||
}
|
||||
}
|
||||
|
||||
gpio = EP93XX_GPIO_LINE_COL0;
|
||||
for (i = 0; i < keypad->pdata->matrix_key_cols; i++, gpio++) {
|
||||
err = gpio_request(gpio, pdev->name);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to request gpio-%d\n",
|
||||
gpio);
|
||||
goto failed_free_cols;
|
||||
}
|
||||
}
|
||||
|
||||
keypad->clk = clk_get(&pdev->dev, "key_clk");
|
||||
if (IS_ERR(keypad->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get keypad clock\n");
|
||||
err = PTR_ERR(keypad->clk);
|
||||
err = ep93xx_keypad_acquire_gpio(pdev);
|
||||
if (err)
|
||||
goto failed_free_io;
|
||||
|
||||
keypad->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(keypad->clk)) {
|
||||
err = PTR_ERR(keypad->clk);
|
||||
goto failed_free_gpio;
|
||||
}
|
||||
|
||||
/* Create and register the input driver */
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev) {
|
||||
dev_err(&pdev->dev, "failed to allocate input device\n");
|
||||
err = -ENOMEM;
|
||||
goto failed_put_clk;
|
||||
}
|
||||
@ -358,44 +330,29 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
|
||||
ep93xx_keypad_build_keycode(keypad);
|
||||
platform_set_drvdata(pdev, keypad);
|
||||
|
||||
err = request_irq(irq, ep93xx_keypad_irq_handler, IRQF_DISABLED,
|
||||
pdev->name, keypad);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
|
||||
IRQF_DISABLED, pdev->name, keypad);
|
||||
if (err)
|
||||
goto failed_free_dev;
|
||||
}
|
||||
|
||||
keypad->irq = irq;
|
||||
|
||||
/* Register the input device */
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to register input device\n");
|
||||
if (err)
|
||||
goto failed_free_irq;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
failed_free_irq:
|
||||
free_irq(irq, pdev);
|
||||
free_irq(keypad->irq, pdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
failed_free_dev:
|
||||
input_free_device(input_dev);
|
||||
failed_put_clk:
|
||||
clk_put(keypad->clk);
|
||||
failed_free_gpio:
|
||||
ep93xx_keypad_release_gpio(pdev);
|
||||
failed_free_io:
|
||||
i = keypad->pdata->matrix_key_cols - 1;
|
||||
gpio = EP93XX_GPIO_LINE_COL0 + i;
|
||||
failed_free_cols:
|
||||
for ( ; i >= 0; i--, gpio--)
|
||||
gpio_free(gpio);
|
||||
i = keypad->pdata->matrix_key_rows - 1;
|
||||
gpio = EP93XX_GPIO_LINE_ROW0 + i;
|
||||
failed_free_rows:
|
||||
for ( ; i >= 0; i--, gpio--)
|
||||
gpio_free(gpio);
|
||||
iounmap(keypad->mmio_base);
|
||||
failed_free_mem:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
@ -408,7 +365,6 @@ static int __devexit ep93xx_keypad_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
int i, gpio;
|
||||
|
||||
free_irq(keypad->irq, pdev);
|
||||
|
||||
@ -420,15 +376,7 @@ static int __devexit ep93xx_keypad_remove(struct platform_device *pdev)
|
||||
|
||||
input_unregister_device(keypad->input_dev);
|
||||
|
||||
i = keypad->pdata->matrix_key_cols - 1;
|
||||
gpio = EP93XX_GPIO_LINE_COL0 + i;
|
||||
for ( ; i >= 0; i--, gpio--)
|
||||
gpio_free(gpio);
|
||||
|
||||
i = keypad->pdata->matrix_key_rows - 1;
|
||||
gpio = EP93XX_GPIO_LINE_ROW0 + i;
|
||||
for ( ; i >= 0; i--, gpio--)
|
||||
gpio_free(gpio);
|
||||
ep93xx_keypad_release_gpio(pdev);
|
||||
|
||||
iounmap(keypad->mmio_base);
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
|
||||
* Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
|
||||
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
|
||||
* Copyright (c) 2009 Sebastian Kapfer <sebastian_kapfer@gmx.net>
|
||||
*
|
||||
* ALPS detection, tap switching and status querying info is taken from
|
||||
* tpconfig utility (by C. Scott Ananian and Bruce Kall).
|
||||
@ -28,7 +29,6 @@
|
||||
#define dbg(format, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#define ALPS_OLDPROTO 0x01 /* old style input */
|
||||
#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
|
||||
#define ALPS_PASS 0x04 /* device has a pass-through port */
|
||||
@ -37,7 +37,8 @@
|
||||
#define ALPS_FW_BK_1 0x10 /* front & back buttons present */
|
||||
#define ALPS_FW_BK_2 0x20 /* front & back buttons present */
|
||||
#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
|
||||
|
||||
#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
|
||||
6-byte ALPS packet */
|
||||
|
||||
static const struct alps_model_info alps_model_data[] = {
|
||||
{ { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
|
||||
@ -58,7 +59,9 @@ static const struct alps_model_info alps_model_data[] = {
|
||||
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
|
||||
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
|
||||
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
|
||||
{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */
|
||||
/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
|
||||
{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
|
||||
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
|
||||
{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
|
||||
};
|
||||
|
||||
@ -69,20 +72,88 @@ static const struct alps_model_info alps_model_data[] = {
|
||||
*/
|
||||
|
||||
/*
|
||||
* ALPS abolute Mode - new format
|
||||
* PS/2 packet format
|
||||
*
|
||||
* byte 0: 0 0 YSGN XSGN 1 M R L
|
||||
* byte 1: X7 X6 X5 X4 X3 X2 X1 X0
|
||||
* byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
|
||||
*
|
||||
* Note that the device never signals overflow condition.
|
||||
*
|
||||
* ALPS absolute Mode - new format
|
||||
*
|
||||
* byte 0: 1 ? ? ? 1 ? ? ?
|
||||
* byte 1: 0 x6 x5 x4 x3 x2 x1 x0
|
||||
* byte 2: 0 x10 x9 x8 x7 ? fin ges
|
||||
* byte 2: 0 x10 x9 x8 x7 ? fin ges
|
||||
* byte 3: 0 y9 y8 y7 1 M R L
|
||||
* byte 4: 0 y6 y5 y4 y3 y2 y1 y0
|
||||
* byte 5: 0 z6 z5 z4 z3 z2 z1 z0
|
||||
*
|
||||
* Dualpoint device -- interleaved packet format
|
||||
*
|
||||
* byte 0: 1 1 0 0 1 1 1 1
|
||||
* byte 1: 0 x6 x5 x4 x3 x2 x1 x0
|
||||
* byte 2: 0 x10 x9 x8 x7 0 fin ges
|
||||
* byte 3: 0 0 YSGN XSGN 1 1 1 1
|
||||
* byte 4: X7 X6 X5 X4 X3 X2 X1 X0
|
||||
* byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
|
||||
* byte 6: 0 y9 y8 y7 1 m r l
|
||||
* byte 7: 0 y6 y5 y4 y3 y2 y1 y0
|
||||
* byte 8: 0 z6 z5 z4 z3 z2 z1 z0
|
||||
*
|
||||
* CAPITALS = stick, miniscules = touchpad
|
||||
*
|
||||
* ?'s can have different meanings on different models,
|
||||
* such as wheel rotation, extra buttons, stick buttons
|
||||
* on a dualpoint, etc.
|
||||
*/
|
||||
|
||||
static bool alps_is_valid_first_byte(const struct alps_model_info *model,
|
||||
unsigned char data)
|
||||
{
|
||||
return (data & model->mask0) == model->byte0;
|
||||
}
|
||||
|
||||
static void alps_report_buttons(struct psmouse *psmouse,
|
||||
struct input_dev *dev1, struct input_dev *dev2,
|
||||
int left, int right, int middle)
|
||||
{
|
||||
struct alps_data *priv = psmouse->private;
|
||||
const struct alps_model_info *model = priv->i;
|
||||
|
||||
if (model->flags & ALPS_PS2_INTERLEAVED) {
|
||||
struct input_dev *dev;
|
||||
|
||||
/*
|
||||
* If shared button has already been reported on the
|
||||
* other device (dev2) then this event should be also
|
||||
* sent through that device.
|
||||
*/
|
||||
dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1;
|
||||
input_report_key(dev, BTN_LEFT, left);
|
||||
|
||||
dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1;
|
||||
input_report_key(dev, BTN_RIGHT, right);
|
||||
|
||||
dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1;
|
||||
input_report_key(dev, BTN_MIDDLE, middle);
|
||||
|
||||
/*
|
||||
* Sync the _other_ device now, we'll do the first
|
||||
* device later once we report the rest of the events.
|
||||
*/
|
||||
input_sync(dev2);
|
||||
} else {
|
||||
/*
|
||||
* For devices with non-interleaved packets we know what
|
||||
* device buttons belong to so we can simply report them.
|
||||
*/
|
||||
input_report_key(dev1, BTN_LEFT, left);
|
||||
input_report_key(dev1, BTN_RIGHT, right);
|
||||
input_report_key(dev1, BTN_MIDDLE, middle);
|
||||
}
|
||||
}
|
||||
|
||||
static void alps_process_packet(struct psmouse *psmouse)
|
||||
{
|
||||
struct alps_data *priv = psmouse->private;
|
||||
@ -93,18 +164,6 @@ static void alps_process_packet(struct psmouse *psmouse)
|
||||
int x, y, z, ges, fin, left, right, middle;
|
||||
int back = 0, forward = 0;
|
||||
|
||||
if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */
|
||||
input_report_key(dev2, BTN_LEFT, packet[0] & 1);
|
||||
input_report_key(dev2, BTN_RIGHT, packet[0] & 2);
|
||||
input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
|
||||
input_report_rel(dev2, REL_X,
|
||||
packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
|
||||
input_report_rel(dev2, REL_Y,
|
||||
packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
|
||||
input_sync(dev2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (model->flags & ALPS_OLDPROTO) {
|
||||
left = packet[2] & 0x10;
|
||||
right = packet[2] & 0x08;
|
||||
@ -140,18 +199,13 @@ static void alps_process_packet(struct psmouse *psmouse)
|
||||
input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x));
|
||||
input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
|
||||
|
||||
input_report_key(dev2, BTN_LEFT, left);
|
||||
input_report_key(dev2, BTN_RIGHT, right);
|
||||
input_report_key(dev2, BTN_MIDDLE, middle);
|
||||
alps_report_buttons(psmouse, dev2, dev, left, right, middle);
|
||||
|
||||
input_sync(dev);
|
||||
input_sync(dev2);
|
||||
return;
|
||||
}
|
||||
|
||||
input_report_key(dev, BTN_LEFT, left);
|
||||
input_report_key(dev, BTN_RIGHT, right);
|
||||
input_report_key(dev, BTN_MIDDLE, middle);
|
||||
alps_report_buttons(psmouse, dev, dev2, left, right, middle);
|
||||
|
||||
/* Convert hardware tap to a reasonable Z value */
|
||||
if (ges && !fin)
|
||||
@ -202,25 +256,168 @@ static void alps_process_packet(struct psmouse *psmouse)
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
|
||||
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
|
||||
unsigned char packet[],
|
||||
bool report_buttons)
|
||||
{
|
||||
struct alps_data *priv = psmouse->private;
|
||||
struct input_dev *dev2 = priv->dev2;
|
||||
|
||||
if (report_buttons)
|
||||
alps_report_buttons(psmouse, dev2, psmouse->dev,
|
||||
packet[0] & 1, packet[0] & 2, packet[0] & 4);
|
||||
|
||||
input_report_rel(dev2, REL_X,
|
||||
packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
|
||||
input_report_rel(dev2, REL_Y,
|
||||
packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
|
||||
|
||||
input_sync(dev2);
|
||||
}
|
||||
|
||||
static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
|
||||
{
|
||||
struct alps_data *priv = psmouse->private;
|
||||
|
||||
if (psmouse->pktcnt < 6)
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
|
||||
if (psmouse->pktcnt == 6) {
|
||||
/*
|
||||
* Start a timer to flush the packet if it ends up last
|
||||
* 6-byte packet in the stream. Timer needs to fire
|
||||
* psmouse core times out itself. 20 ms should be enough
|
||||
* to decide if we are getting more data or not.
|
||||
*/
|
||||
mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20));
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
}
|
||||
|
||||
del_timer(&priv->timer);
|
||||
|
||||
if (psmouse->packet[6] & 0x80) {
|
||||
|
||||
/*
|
||||
* Highest bit is set - that means we either had
|
||||
* complete ALPS packet and this is start of the
|
||||
* next packet or we got garbage.
|
||||
*/
|
||||
|
||||
if (((psmouse->packet[3] |
|
||||
psmouse->packet[4] |
|
||||
psmouse->packet[5]) & 0x80) ||
|
||||
(!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) {
|
||||
dbg("refusing packet %x %x %x %x "
|
||||
"(suspected interleaved ps/2)\n",
|
||||
psmouse->packet[3], psmouse->packet[4],
|
||||
psmouse->packet[5], psmouse->packet[6]);
|
||||
return PSMOUSE_BAD_DATA;
|
||||
}
|
||||
|
||||
alps_process_packet(psmouse);
|
||||
|
||||
/* Continue with the next packet */
|
||||
psmouse->packet[0] = psmouse->packet[6];
|
||||
psmouse->pktcnt = 1;
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
* High bit is 0 - that means that we indeed got a PS/2
|
||||
* packet in the middle of ALPS packet.
|
||||
*
|
||||
* There is also possibility that we got 6-byte ALPS
|
||||
* packet followed by 3-byte packet from trackpoint. We
|
||||
* can not distinguish between these 2 scenarios but
|
||||
* becase the latter is unlikely to happen in course of
|
||||
* normal operation (user would need to press all
|
||||
* buttons on the pad and start moving trackpoint
|
||||
* without touching the pad surface) we assume former.
|
||||
* Even if we are wrong the wost thing that would happen
|
||||
* the cursor would jump but we should not get protocol
|
||||
* desynchronization.
|
||||
*/
|
||||
|
||||
alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
|
||||
false);
|
||||
|
||||
/*
|
||||
* Continue with the standard ALPS protocol handling,
|
||||
* but make sure we won't process it as an interleaved
|
||||
* packet again, which may happen if all buttons are
|
||||
* pressed. To avoid this let's reset the 4th bit which
|
||||
* is normally 1.
|
||||
*/
|
||||
psmouse->packet[3] = psmouse->packet[6] & 0xf7;
|
||||
psmouse->pktcnt = 4;
|
||||
}
|
||||
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
}
|
||||
|
||||
static void alps_flush_packet(unsigned long data)
|
||||
{
|
||||
struct psmouse *psmouse = (struct psmouse *)data;
|
||||
|
||||
serio_pause_rx(psmouse->ps2dev.serio);
|
||||
|
||||
if (psmouse->pktcnt == 6) {
|
||||
|
||||
/*
|
||||
* We did not any more data in reasonable amount of time.
|
||||
* Validate the last 3 bytes and process as a standard
|
||||
* ALPS packet.
|
||||
*/
|
||||
if ((psmouse->packet[3] |
|
||||
psmouse->packet[4] |
|
||||
psmouse->packet[5]) & 0x80) {
|
||||
dbg("refusing packet %x %x %x "
|
||||
"(suspected interleaved ps/2)\n",
|
||||
psmouse->packet[3], psmouse->packet[4],
|
||||
psmouse->packet[5]);
|
||||
} else {
|
||||
alps_process_packet(psmouse);
|
||||
}
|
||||
psmouse->pktcnt = 0;
|
||||
}
|
||||
|
||||
serio_continue_rx(psmouse->ps2dev.serio);
|
||||
}
|
||||
|
||||
static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
|
||||
{
|
||||
struct alps_data *priv = psmouse->private;
|
||||
const struct alps_model_info *model = priv->i;
|
||||
|
||||
if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
|
||||
if (psmouse->pktcnt == 3) {
|
||||
alps_process_packet(psmouse);
|
||||
alps_report_bare_ps2_packet(psmouse, psmouse->packet,
|
||||
true);
|
||||
return PSMOUSE_FULL_PACKET;
|
||||
}
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
}
|
||||
|
||||
if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0)
|
||||
/* Check for PS/2 packet stuffed in the middle of ALPS packet. */
|
||||
|
||||
if ((model->flags & ALPS_PS2_INTERLEAVED) &&
|
||||
psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) {
|
||||
return alps_handle_interleaved_ps2(psmouse);
|
||||
}
|
||||
|
||||
if (!alps_is_valid_first_byte(model, psmouse->packet[0])) {
|
||||
dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
|
||||
psmouse->packet[0], model->mask0, model->byte0);
|
||||
return PSMOUSE_BAD_DATA;
|
||||
}
|
||||
|
||||
/* Bytes 2 - 6 should have 0 in the highest bit */
|
||||
if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
|
||||
(psmouse->packet[psmouse->pktcnt - 1] & 0x80))
|
||||
(psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
|
||||
dbg("refusing packet[%i] = %x\n",
|
||||
psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]);
|
||||
return PSMOUSE_BAD_DATA;
|
||||
}
|
||||
|
||||
if (psmouse->pktcnt == 6) {
|
||||
alps_process_packet(psmouse);
|
||||
@ -459,6 +656,7 @@ static void alps_disconnect(struct psmouse *psmouse)
|
||||
struct alps_data *priv = psmouse->private;
|
||||
|
||||
psmouse_reset(psmouse);
|
||||
del_timer_sync(&priv->timer);
|
||||
input_unregister_device(priv->dev2);
|
||||
kfree(priv);
|
||||
}
|
||||
@ -476,6 +674,8 @@ int alps_init(struct psmouse *psmouse)
|
||||
goto init_fail;
|
||||
|
||||
priv->dev2 = dev2;
|
||||
setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
|
||||
|
||||
psmouse->private = priv;
|
||||
|
||||
model = alps_get_model(psmouse, &version);
|
||||
@ -487,6 +687,17 @@ int alps_init(struct psmouse *psmouse)
|
||||
if (alps_hw_init(psmouse))
|
||||
goto init_fail;
|
||||
|
||||
/*
|
||||
* Undo part of setup done for us by psmouse core since touchpad
|
||||
* is not a relative device.
|
||||
*/
|
||||
__clear_bit(EV_REL, dev1->evbit);
|
||||
__clear_bit(REL_X, dev1->relbit);
|
||||
__clear_bit(REL_Y, dev1->relbit);
|
||||
|
||||
/*
|
||||
* Now set up our capabilities.
|
||||
*/
|
||||
dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY);
|
||||
dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
|
||||
dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER);
|
||||
|
@ -23,6 +23,7 @@ struct alps_data {
|
||||
char phys[32]; /* Phys */
|
||||
const struct alps_model_info *i;/* Info */
|
||||
int prev_fin; /* Finger bit from previous packet */
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_ALPS
|
||||
|
@ -79,11 +79,11 @@ static void altera_ps2_close(struct serio *io)
|
||||
/*
|
||||
* Add one device to this driver.
|
||||
*/
|
||||
static int altera_ps2_probe(struct platform_device *pdev)
|
||||
static int __devinit altera_ps2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ps2if *ps2if;
|
||||
struct serio *serio;
|
||||
int error;
|
||||
int error, irq;
|
||||
|
||||
ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL);
|
||||
serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
|
||||
@ -108,11 +108,13 @@ static int altera_ps2_probe(struct platform_device *pdev)
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
ps2if->irq = platform_get_irq(pdev, 0);
|
||||
if (ps2if->irq < 0) {
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
error = -ENXIO;
|
||||
goto err_free_mem;
|
||||
}
|
||||
ps2if->irq = irq;
|
||||
|
||||
if (!request_mem_region(ps2if->iomem_res->start,
|
||||
resource_size(ps2if->iomem_res), pdev->name)) {
|
||||
@ -155,7 +157,7 @@ static int altera_ps2_probe(struct platform_device *pdev)
|
||||
/*
|
||||
* Remove one device from this driver.
|
||||
*/
|
||||
static int altera_ps2_remove(struct platform_device *pdev)
|
||||
static int __devexit altera_ps2_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ps2if *ps2if = platform_get_drvdata(pdev);
|
||||
|
||||
@ -175,9 +177,10 @@ static int altera_ps2_remove(struct platform_device *pdev)
|
||||
*/
|
||||
static struct platform_driver altera_ps2_driver = {
|
||||
.probe = altera_ps2_probe,
|
||||
.remove = altera_ps2_remove,
|
||||
.remove = __devexit_p(altera_ps2_remove),
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -107,7 +107,7 @@ static void amba_kmi_close(struct serio *io)
|
||||
clk_disable(kmi->clk);
|
||||
}
|
||||
|
||||
static int amba_kmi_probe(struct amba_device *dev, struct amba_id *id)
|
||||
static int __devinit amba_kmi_probe(struct amba_device *dev, struct amba_id *id)
|
||||
{
|
||||
struct amba_kmi_port *kmi;
|
||||
struct serio *io;
|
||||
@ -134,7 +134,7 @@ static int amba_kmi_probe(struct amba_device *dev, struct amba_id *id)
|
||||
io->port_data = kmi;
|
||||
io->dev.parent = &dev->dev;
|
||||
|
||||
kmi->io = io;
|
||||
kmi->io = io;
|
||||
kmi->base = ioremap(dev->res.start, resource_size(&dev->res));
|
||||
if (!kmi->base) {
|
||||
ret = -ENOMEM;
|
||||
@ -162,7 +162,7 @@ static int amba_kmi_probe(struct amba_device *dev, struct amba_id *id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amba_kmi_remove(struct amba_device *dev)
|
||||
static int __devexit amba_kmi_remove(struct amba_device *dev)
|
||||
{
|
||||
struct amba_kmi_port *kmi = amba_get_drvdata(dev);
|
||||
|
||||
@ -197,10 +197,11 @@ static struct amba_id amba_kmi_idtable[] = {
|
||||
static struct amba_driver ambakmi_driver = {
|
||||
.drv = {
|
||||
.name = "kmi-pl050",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.id_table = amba_kmi_idtable,
|
||||
.probe = amba_kmi_probe,
|
||||
.remove = amba_kmi_remove,
|
||||
.remove = __devexit_p(amba_kmi_remove),
|
||||
.resume = amba_kmi_resume,
|
||||
};
|
||||
|
||||
|
@ -137,7 +137,7 @@ static int psif_write(struct serio *io, unsigned char val)
|
||||
spin_lock_irqsave(&psif->lock, flags);
|
||||
|
||||
while (!(psif_readl(psif, SR) & PSIF_BIT(TXEMPTY)) && timeout--)
|
||||
msleep(10);
|
||||
udelay(50);
|
||||
|
||||
if (timeout >= 0) {
|
||||
psif_writel(psif, THR, val);
|
||||
@ -352,6 +352,7 @@ static struct platform_driver psif_driver = {
|
||||
.remove = __exit_p(psif_remove),
|
||||
.driver = {
|
||||
.name = "atmel_psif",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.suspend = psif_suspend,
|
||||
.resume = psif_resume,
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org>
|
||||
*
|
||||
* Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
|
||||
* Copyright (c) 1999 Alex deVries <alex@onefishtwo.ca>
|
||||
* Copyright (c) 1999 Alex deVries <alex@onefishtwo.ca>
|
||||
* Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
|
||||
* Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
|
||||
* Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
|
||||
@ -326,7 +326,7 @@ static void gscps2_close(struct serio *port)
|
||||
* @return: success/error report
|
||||
*/
|
||||
|
||||
static int __init gscps2_probe(struct parisc_device *dev)
|
||||
static int __devinit gscps2_probe(struct parisc_device *dev)
|
||||
{
|
||||
struct gscps2port *ps2port;
|
||||
struct serio *serio;
|
||||
@ -443,7 +443,7 @@ static struct parisc_driver parisc_ps2_driver = {
|
||||
.name = "gsc_ps2",
|
||||
.id_table = gscps2_device_tbl,
|
||||
.probe = gscps2_probe,
|
||||
.remove = gscps2_remove,
|
||||
.remove = __devexit_p(gscps2_remove),
|
||||
};
|
||||
|
||||
static int __init gscps2_init(void)
|
||||
|
@ -993,10 +993,8 @@ int hil_mlc_unregister(hil_mlc *mlc)
|
||||
|
||||
static int __init hil_mlc_init(void)
|
||||
{
|
||||
init_timer(&hil_mlcs_kicker);
|
||||
hil_mlcs_kicker.expires = jiffies + HZ;
|
||||
hil_mlcs_kicker.function = &hil_mlcs_timer;
|
||||
add_timer(&hil_mlcs_kicker);
|
||||
setup_timer(&hil_mlcs_kicker, &hil_mlcs_timer, 0);
|
||||
mod_timer(&hil_mlcs_kicker, jiffies + HZ);
|
||||
|
||||
tasklet_enable(&hil_mlcs_tasklet);
|
||||
|
||||
@ -1005,7 +1003,7 @@ static int __init hil_mlc_init(void)
|
||||
|
||||
static void __exit hil_mlc_exit(void)
|
||||
{
|
||||
del_timer(&hil_mlcs_kicker);
|
||||
del_timer_sync(&hil_mlcs_kicker);
|
||||
|
||||
tasklet_disable(&hil_mlcs_tasklet);
|
||||
tasklet_kill(&hil_mlcs_tasklet);
|
||||
|
@ -157,6 +157,14 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "01"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Gigabyte M1022M netbook */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co.,Ltd."),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "M1022E"),
|
||||
DMI_MATCH(DMI_BOARD_VERSION, "1.02"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
|
@ -126,6 +126,8 @@ static unsigned char i8042_suppress_kbd_ack;
|
||||
static struct platform_device *i8042_platform_device;
|
||||
|
||||
static irqreturn_t i8042_interrupt(int irq, void *dev_id);
|
||||
static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio);
|
||||
|
||||
void i8042_lock_chip(void)
|
||||
{
|
||||
@ -139,6 +141,48 @@ void i8042_unlock_chip(void)
|
||||
}
|
||||
EXPORT_SYMBOL(i8042_unlock_chip);
|
||||
|
||||
int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio))
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&i8042_lock, flags);
|
||||
|
||||
if (i8042_platform_filter) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
i8042_platform_filter = filter;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&i8042_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(i8042_install_filter);
|
||||
|
||||
int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *port))
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&i8042_lock, flags);
|
||||
|
||||
if (i8042_platform_filter != filter) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
i8042_platform_filter = NULL;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&i8042_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(i8042_remove_filter);
|
||||
|
||||
/*
|
||||
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
|
||||
* be ready for reading values from it / writing values to it.
|
||||
@ -368,6 +412,31 @@ static void i8042_stop(struct serio *serio)
|
||||
port->serio = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* i8042_filter() filters out unwanted bytes from the input data stream.
|
||||
* It is called from i8042_interrupt and thus is running with interrupts
|
||||
* off and i8042_lock held.
|
||||
*/
|
||||
static bool i8042_filter(unsigned char data, unsigned char str,
|
||||
struct serio *serio)
|
||||
{
|
||||
if (unlikely(i8042_suppress_kbd_ack)) {
|
||||
if ((~str & I8042_STR_AUXDATA) &&
|
||||
(data == 0xfa || data == 0xfe)) {
|
||||
i8042_suppress_kbd_ack--;
|
||||
dbg("Extra keyboard ACK - filtered out\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
|
||||
dbg("Filtered out by platfrom filter\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* i8042_interrupt() is the most important function in this driver -
|
||||
* it handles the interrupts from the i8042, and sends incoming bytes
|
||||
@ -377,13 +446,16 @@ static void i8042_stop(struct serio *serio)
|
||||
static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct i8042_port *port;
|
||||
struct serio *serio;
|
||||
unsigned long flags;
|
||||
unsigned char str, data;
|
||||
unsigned int dfl;
|
||||
unsigned int port_no;
|
||||
bool filtered;
|
||||
int ret = 1;
|
||||
|
||||
spin_lock_irqsave(&i8042_lock, flags);
|
||||
|
||||
str = i8042_read_status();
|
||||
if (unlikely(~str & I8042_STR_OBF)) {
|
||||
spin_unlock_irqrestore(&i8042_lock, flags);
|
||||
@ -391,8 +463,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = i8042_read_data();
|
||||
spin_unlock_irqrestore(&i8042_lock, flags);
|
||||
|
||||
if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
|
||||
static unsigned long last_transmit;
|
||||
@ -441,21 +513,19 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
port = &i8042_ports[port_no];
|
||||
serio = port->exists ? port->serio : NULL;
|
||||
|
||||
dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
|
||||
data, port_no, irq,
|
||||
dfl & SERIO_PARITY ? ", bad parity" : "",
|
||||
dfl & SERIO_TIMEOUT ? ", timeout" : "");
|
||||
|
||||
if (unlikely(i8042_suppress_kbd_ack))
|
||||
if (port_no == I8042_KBD_PORT_NO &&
|
||||
(data == 0xfa || data == 0xfe)) {
|
||||
i8042_suppress_kbd_ack--;
|
||||
goto out;
|
||||
}
|
||||
filtered = i8042_filter(data, str, serio);
|
||||
|
||||
if (likely(port->exists))
|
||||
serio_interrupt(port->serio, data, dfl);
|
||||
spin_unlock_irqrestore(&i8042_lock, flags);
|
||||
|
||||
if (likely(port->exists && !filtered))
|
||||
serio_interrupt(serio, data, dfl);
|
||||
|
||||
out:
|
||||
return IRQ_RETVAL(ret);
|
||||
|
@ -180,8 +180,8 @@ static void __devinit ps2_clear_input(struct ps2if *ps2if)
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
ps2_test_one(struct ps2if *ps2if, unsigned int mask)
|
||||
static unsigned int __devinit ps2_test_one(struct ps2if *ps2if,
|
||||
unsigned int mask)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
@ -197,7 +197,7 @@ ps2_test_one(struct ps2if *ps2if, unsigned int mask)
|
||||
* Test the keyboard interface. We basically check to make sure that
|
||||
* we can drive each line to the keyboard independently of each other.
|
||||
*/
|
||||
static int __init ps2_test(struct ps2if *ps2if)
|
||||
static int __devinit ps2_test(struct ps2if *ps2if)
|
||||
{
|
||||
unsigned int stat;
|
||||
int ret = 0;
|
||||
@ -312,7 +312,7 @@ static int __devinit ps2_probe(struct sa1111_dev *dev)
|
||||
/*
|
||||
* Remove one device from this driver.
|
||||
*/
|
||||
static int ps2_remove(struct sa1111_dev *dev)
|
||||
static int __devexit ps2_remove(struct sa1111_dev *dev)
|
||||
{
|
||||
struct ps2if *ps2if = sa1111_get_drvdata(dev);
|
||||
|
||||
@ -335,7 +335,7 @@ static struct sa1111_driver ps2_driver = {
|
||||
},
|
||||
.devid = SA1111_DEVID_PS2,
|
||||
.probe = ps2_probe,
|
||||
.remove = ps2_remove,
|
||||
.remove = __devexit_p(ps2_remove),
|
||||
};
|
||||
|
||||
static int __init ps2_init(void)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* drivers/input/tablet/wacom.h
|
||||
*
|
||||
* USB Wacom Graphire and Wacom Intuos tablet support
|
||||
* USB Wacom tablet support
|
||||
*
|
||||
* Copyright (c) 2000-2004 Vojtech Pavlik <vojtech@ucw.cz>
|
||||
* Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
|
||||
@ -69,6 +69,9 @@
|
||||
* v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A)
|
||||
* v1.50 (pc) - Fixed a TabletPC touch bug in 2.6.28
|
||||
* v1.51 (pc) - Added support for Intuos4
|
||||
* v1.52 (pc) - Query Wacom data upon system resume
|
||||
* - add defines for features->type
|
||||
* - add new devices (0x9F, 0xE2, and 0XE3)
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -89,9 +92,9 @@
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v1.51"
|
||||
#define DRIVER_VERSION "v1.52"
|
||||
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
|
||||
#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
|
||||
#define DRIVER_DESC "USB Wacom tablet driver"
|
||||
#define DRIVER_LICENSE "GPL"
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
@ -133,6 +136,8 @@ extern void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_w
|
||||
extern void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
|
||||
extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
|
||||
extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
|
||||
extern void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
|
||||
extern void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
|
||||
extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
|
||||
extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
|
||||
extern __u16 wacom_le16_to_cpu(unsigned char *data);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* drivers/input/tablet/wacom_sys.c
|
||||
*
|
||||
* USB Wacom Graphire and Wacom Intuos tablet support - system specific code
|
||||
* USB Wacom tablet support - system specific code
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -209,6 +209,7 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_LEFT) |
|
||||
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
|
||||
BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) |
|
||||
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2);
|
||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
|
||||
}
|
||||
@ -256,6 +257,7 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE) |
|
||||
BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
|
||||
BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) |
|
||||
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) |
|
||||
BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) |
|
||||
BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2);
|
||||
@ -269,7 +271,8 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
|
||||
void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
{
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_STYLUS2);
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) |
|
||||
BIT_MASK(BTN_STYLUS) | BIT_MASK(BTN_STYLUS2);
|
||||
}
|
||||
|
||||
void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
@ -277,12 +280,32 @@ void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER);
|
||||
}
|
||||
|
||||
void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
{
|
||||
if (wacom_wac->features->device_type == BTN_TOOL_DOUBLETAP ||
|
||||
wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
|
||||
input_set_abs_params(input_dev, ABS_RX, 0, wacom_wac->features->x_phy, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_RY, 0, wacom_wac->features->y_phy, 0, 0);
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP);
|
||||
}
|
||||
}
|
||||
|
||||
void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
{
|
||||
if (wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP);
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_MSC);
|
||||
input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
|
||||
}
|
||||
}
|
||||
|
||||
static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
|
||||
struct wacom_wac *wacom_wac)
|
||||
struct wacom_features *features)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct wacom_features *features = wacom_wac->features;
|
||||
char limit = 0, result = 0;
|
||||
char limit = 0;
|
||||
/* result has to be defined as int for some devices */
|
||||
int result = 0;
|
||||
int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0;
|
||||
unsigned char *report;
|
||||
|
||||
@ -328,13 +351,24 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
|
||||
case HID_USAGE_X:
|
||||
if (usage == WCM_DESKTOP) {
|
||||
if (finger) {
|
||||
features->touch_x_max =
|
||||
features->touch_y_max =
|
||||
wacom_le16_to_cpu(&report[i + 3]);
|
||||
features->device_type = BTN_TOOL_DOUBLETAP;
|
||||
if (features->type == TABLETPC2FG) {
|
||||
/* need to reset back */
|
||||
features->pktlen = WACOM_PKGLEN_TPC2FG;
|
||||
features->device_type = BTN_TOOL_TRIPLETAP;
|
||||
}
|
||||
features->x_max =
|
||||
wacom_le16_to_cpu(&report[i + 3]);
|
||||
features->x_phy =
|
||||
wacom_le16_to_cpu(&report[i + 6]);
|
||||
i += 7;
|
||||
features->unit = report[i + 9];
|
||||
features->unitExpo = report[i + 11];
|
||||
i += 12;
|
||||
} else if (pen) {
|
||||
/* penabled only accepts exact bytes of data */
|
||||
if (features->type == TABLETPC2FG)
|
||||
features->pktlen = WACOM_PKGLEN_PENABLED;
|
||||
features->device_type = BTN_TOOL_PEN;
|
||||
features->x_max =
|
||||
wacom_le16_to_cpu(&report[i + 3]);
|
||||
i += 4;
|
||||
@ -350,10 +384,35 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
|
||||
break;
|
||||
|
||||
case HID_USAGE_Y:
|
||||
if (usage == WCM_DESKTOP)
|
||||
features->y_max =
|
||||
wacom_le16_to_cpu(&report[i + 3]);
|
||||
i += 4;
|
||||
if (usage == WCM_DESKTOP) {
|
||||
if (finger) {
|
||||
features->device_type = BTN_TOOL_DOUBLETAP;
|
||||
if (features->type == TABLETPC2FG) {
|
||||
/* need to reset back */
|
||||
features->pktlen = WACOM_PKGLEN_TPC2FG;
|
||||
features->device_type = BTN_TOOL_TRIPLETAP;
|
||||
features->y_max =
|
||||
wacom_le16_to_cpu(&report[i + 3]);
|
||||
features->y_phy =
|
||||
wacom_le16_to_cpu(&report[i + 6]);
|
||||
i += 7;
|
||||
} else {
|
||||
features->y_max =
|
||||
features->x_max;
|
||||
features->y_phy =
|
||||
wacom_le16_to_cpu(&report[i + 3]);
|
||||
i += 4;
|
||||
}
|
||||
} else if (pen) {
|
||||
/* penabled only accepts exact bytes of data */
|
||||
if (features->type == TABLETPC2FG)
|
||||
features->pktlen = WACOM_PKGLEN_PENABLED;
|
||||
features->device_type = BTN_TOOL_PEN;
|
||||
features->y_max =
|
||||
wacom_le16_to_cpu(&report[i + 3]);
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_USAGE_FINGER:
|
||||
@ -376,7 +435,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
|
||||
break;
|
||||
|
||||
case HID_COLLECTION:
|
||||
/* reset UsagePage ans Finger */
|
||||
/* reset UsagePage and Finger */
|
||||
finger = usage = 0;
|
||||
break;
|
||||
}
|
||||
@ -388,43 +447,92 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
|
||||
return result;
|
||||
}
|
||||
|
||||
static int wacom_query_tablet_data(struct usb_interface *intf)
|
||||
static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features)
|
||||
{
|
||||
unsigned char *rep_data;
|
||||
int limit = 0;
|
||||
int error;
|
||||
int limit = 0, report_id = 2;
|
||||
int error = -ENOMEM;
|
||||
|
||||
rep_data = kmalloc(2, GFP_KERNEL);
|
||||
if (!rep_data)
|
||||
return -ENOMEM;
|
||||
return error;
|
||||
|
||||
do {
|
||||
rep_data[0] = 2;
|
||||
rep_data[1] = 2;
|
||||
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
2, rep_data, 2);
|
||||
if (error >= 0)
|
||||
error = usb_get_report(intf,
|
||||
WAC_HID_FEATURE_REPORT, 2,
|
||||
rep_data, 2);
|
||||
} while ((error < 0 || rep_data[1] != 2) && limit++ < 5);
|
||||
/* ask to report tablet data if it is 2FGT or not a Tablet PC */
|
||||
if (features->device_type == BTN_TOOL_TRIPLETAP) {
|
||||
do {
|
||||
rep_data[0] = 3;
|
||||
rep_data[1] = 4;
|
||||
report_id = 3;
|
||||
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 2);
|
||||
if (error >= 0)
|
||||
error = usb_get_report(intf,
|
||||
WAC_HID_FEATURE_REPORT, report_id,
|
||||
rep_data, 3);
|
||||
} while ((error < 0 || rep_data[1] != 4) && limit++ < 5);
|
||||
} else if (features->type != TABLETPC && features->type != TABLETPC2FG) {
|
||||
do {
|
||||
rep_data[0] = 2;
|
||||
rep_data[1] = 2;
|
||||
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 2);
|
||||
if (error >= 0)
|
||||
error = usb_get_report(intf,
|
||||
WAC_HID_FEATURE_REPORT, report_id,
|
||||
rep_data, 2);
|
||||
} while ((error < 0 || rep_data[1] != 2) && limit++ < 5);
|
||||
}
|
||||
|
||||
kfree(rep_data);
|
||||
|
||||
return error < 0 ? error : 0;
|
||||
}
|
||||
|
||||
static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
|
||||
struct wacom_features *features)
|
||||
{
|
||||
int error = 0;
|
||||
struct usb_host_interface *interface = intf->cur_altsetting;
|
||||
struct hid_descriptor *hid_desc;
|
||||
|
||||
/* default device to penabled */
|
||||
features->device_type = BTN_TOOL_PEN;
|
||||
|
||||
/* only Tablet PCs need to retrieve the info */
|
||||
if ((features->type != TABLETPC) && (features->type != TABLETPC2FG))
|
||||
goto out;
|
||||
|
||||
if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
|
||||
if (usb_get_extra_descriptor(&interface->endpoint[0],
|
||||
HID_DEVICET_REPORT, &hid_desc)) {
|
||||
printk("wacom: can not retrieve extra class descriptor\n");
|
||||
error = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
error = wacom_parse_hid(intf, hid_desc, features);
|
||||
if (error)
|
||||
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:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct usb_host_interface *interface = intf->cur_altsetting;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct wacom *wacom;
|
||||
struct wacom_wac *wacom_wac;
|
||||
struct wacom_features *features;
|
||||
struct input_dev *input_dev;
|
||||
int error = -ENOMEM;
|
||||
struct hid_descriptor *hid_desc;
|
||||
|
||||
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
|
||||
wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
|
||||
@ -432,7 +540,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
if (!wacom || !input_dev || !wacom_wac)
|
||||
goto fail1;
|
||||
|
||||
wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
|
||||
wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX, GFP_KERNEL, &wacom->data_dma);
|
||||
if (!wacom_wac->data)
|
||||
goto fail1;
|
||||
|
||||
@ -448,7 +556,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
|
||||
|
||||
wacom_wac->features = features = get_wacom_feature(id);
|
||||
BUG_ON(features->pktlen > 10);
|
||||
BUG_ON(features->pktlen > WACOM_PKGLEN_MAX);
|
||||
|
||||
input_dev->name = wacom_wac->features->name;
|
||||
wacom->wacom_wac = wacom_wac;
|
||||
@ -463,47 +571,24 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
|
||||
endpoint = &intf->cur_altsetting->endpoint[0].desc;
|
||||
|
||||
/* Initialize touch_x_max and touch_y_max in case it is not defined */
|
||||
if (wacom_wac->features->type == TABLETPC) {
|
||||
features->touch_x_max = 1023;
|
||||
features->touch_y_max = 1023;
|
||||
} else {
|
||||
features->touch_x_max = 0;
|
||||
features->touch_y_max = 0;
|
||||
}
|
||||
|
||||
/* TabletPC need to retrieve the physical and logical maximum from report descriptor */
|
||||
if (wacom_wac->features->type == TABLETPC) {
|
||||
if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
|
||||
if (usb_get_extra_descriptor(&interface->endpoint[0],
|
||||
HID_DEVICET_REPORT, &hid_desc)) {
|
||||
printk("wacom: can not retrive extra class descriptor\n");
|
||||
goto fail2;
|
||||
}
|
||||
}
|
||||
error = wacom_parse_hid(intf, hid_desc, wacom_wac);
|
||||
if (error)
|
||||
goto fail2;
|
||||
}
|
||||
/* Retrieve the physical and logical size for OEM devices */
|
||||
error = wacom_retrieve_hid_descriptor(intf, features);
|
||||
if (error)
|
||||
goto fail2;
|
||||
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) |
|
||||
BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS);
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_X, 0, features->x_max, 4, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, 4, 0);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 0);
|
||||
if (features->type == TABLETPC) {
|
||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP);
|
||||
input_set_abs_params(input_dev, ABS_RX, 0, features->touch_x_max, 4, 0);
|
||||
input_set_abs_params(input_dev, ABS_RY, 0, features->touch_y_max, 4, 0);
|
||||
}
|
||||
input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
|
||||
|
||||
wacom_init_input_dev(input_dev, wacom_wac);
|
||||
|
||||
usb_fill_int_urb(wacom->irq, dev,
|
||||
usb_rcvintpipe(dev, endpoint->bEndpointAddress),
|
||||
wacom_wac->data, wacom_wac->features->pktlen,
|
||||
wacom_wac->data, features->pktlen,
|
||||
wacom_sys_irq, wacom, endpoint->bInterval);
|
||||
wacom->irq->transfer_dma = wacom->data_dma;
|
||||
wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
@ -512,18 +597,14 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
if (error)
|
||||
goto fail3;
|
||||
|
||||
/*
|
||||
* Ask the tablet to report tablet data if it is not a Tablet PC.
|
||||
* Note that if query fails it is not a hard failure.
|
||||
*/
|
||||
if (wacom_wac->features->type != TABLETPC)
|
||||
wacom_query_tablet_data(intf);
|
||||
/* Note that if query fails it is not a hard failure */
|
||||
wacom_query_tablet_data(intf, features);
|
||||
|
||||
usb_set_intfdata(intf, wacom);
|
||||
return 0;
|
||||
|
||||
fail3: usb_free_urb(wacom->irq);
|
||||
fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
|
||||
fail2: usb_buffer_free(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
|
||||
fail1: input_free_device(input_dev);
|
||||
kfree(wacom);
|
||||
kfree(wacom_wac);
|
||||
@ -539,7 +620,7 @@ static void wacom_disconnect(struct usb_interface *intf)
|
||||
usb_kill_urb(wacom->irq);
|
||||
input_unregister_device(wacom->dev);
|
||||
usb_free_urb(wacom->irq);
|
||||
usb_buffer_free(interface_to_usbdev(intf), 10,
|
||||
usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
|
||||
wacom->wacom_wac->data, wacom->data_dma);
|
||||
kfree(wacom->wacom_wac);
|
||||
kfree(wacom);
|
||||
@ -559,12 +640,16 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
static int wacom_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct wacom *wacom = usb_get_intfdata(intf);
|
||||
struct wacom_features *features = wacom->wacom_wac->features;
|
||||
int rv;
|
||||
|
||||
mutex_lock(&wacom->lock);
|
||||
if (wacom->open)
|
||||
if (wacom->open) {
|
||||
rv = usb_submit_urb(wacom->irq, GFP_NOIO);
|
||||
else
|
||||
/* switch to wacom mode if needed */
|
||||
if (!wacom_retrieve_hid_descriptor(intf, features))
|
||||
wacom_query_tablet_data(intf, features);
|
||||
} else
|
||||
rv = 0;
|
||||
mutex_unlock(&wacom->lock);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* drivers/input/tablet/wacom_wac.c
|
||||
*
|
||||
* USB Wacom Graphire and Wacom Intuos tablet support - Wacom specific code
|
||||
* USB Wacom tablet support - Wacom specific code
|
||||
*
|
||||
*/
|
||||
|
||||
@ -58,16 +58,15 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
unsigned char *data = wacom->data;
|
||||
int prox, pressure;
|
||||
|
||||
if (data[0] != 2) {
|
||||
if (data[0] != WACOM_REPORT_PENABLED) {
|
||||
dbg("wacom_pl_irq: received unknown report #%d", data[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
prox = data[1] & 0x40;
|
||||
|
||||
wacom->id[0] = ERASER_DEVICE_ID;
|
||||
if (prox) {
|
||||
|
||||
wacom->id[0] = ERASER_DEVICE_ID;
|
||||
pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
|
||||
if (wacom->features->pressure_max > 255)
|
||||
pressure = (pressure << 1) | ((data[4] >> 6) & 1);
|
||||
@ -128,7 +127,7 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
{
|
||||
unsigned char *data = wacom->data;
|
||||
|
||||
if (data[0] != 2) {
|
||||
if (data[0] != WACOM_REPORT_PENABLED) {
|
||||
printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
|
||||
return 0;
|
||||
}
|
||||
@ -155,14 +154,16 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
{
|
||||
unsigned char *data = wacom->data;
|
||||
int x, y, rw;
|
||||
static int penData = 0;
|
||||
|
||||
if (data[0] != 2) {
|
||||
if (data[0] != WACOM_REPORT_PENABLED) {
|
||||
dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[1] & 0x80) {
|
||||
/* in prox and not a pad data */
|
||||
penData = 1;
|
||||
|
||||
switch ((data[1] >> 5) & 3) {
|
||||
|
||||
@ -232,7 +233,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
switch (wacom->features->type) {
|
||||
case WACOM_G4:
|
||||
if (data[7] & 0xf8) {
|
||||
wacom_input_sync(wcombo); /* sync last event */
|
||||
if (penData) {
|
||||
wacom_input_sync(wcombo); /* sync last event */
|
||||
if (!wacom->id[0])
|
||||
penData = 0;
|
||||
}
|
||||
wacom->id[1] = PAD_DEVICE_ID;
|
||||
wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
|
||||
wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
|
||||
@ -242,10 +247,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]);
|
||||
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
|
||||
} else if (wacom->id[1]) {
|
||||
wacom_input_sync(wcombo); /* sync last event */
|
||||
if (penData) {
|
||||
wacom_input_sync(wcombo); /* sync last event */
|
||||
if (!wacom->id[0])
|
||||
penData = 0;
|
||||
}
|
||||
wacom->id[1] = 0;
|
||||
wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
|
||||
wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
|
||||
wacom_report_rel(wcombo, REL_WHEEL, 0);
|
||||
wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
|
||||
wacom_report_abs(wcombo, ABS_MISC, 0);
|
||||
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
|
||||
@ -253,7 +263,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
break;
|
||||
case WACOM_MO:
|
||||
if ((data[7] & 0xf8) || (data[8] & 0xff)) {
|
||||
wacom_input_sync(wcombo); /* sync last event */
|
||||
if (penData) {
|
||||
wacom_input_sync(wcombo); /* sync last event */
|
||||
if (!wacom->id[0])
|
||||
penData = 0;
|
||||
}
|
||||
wacom->id[1] = PAD_DEVICE_ID;
|
||||
wacom_report_key(wcombo, BTN_0, (data[7] & 0x08));
|
||||
wacom_report_key(wcombo, BTN_1, (data[7] & 0x20));
|
||||
@ -264,7 +278,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]);
|
||||
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
|
||||
} else if (wacom->id[1]) {
|
||||
wacom_input_sync(wcombo); /* sync last event */
|
||||
if (penData) {
|
||||
wacom_input_sync(wcombo); /* sync last event */
|
||||
if (!wacom->id[0])
|
||||
penData = 0;
|
||||
}
|
||||
wacom->id[1] = 0;
|
||||
wacom_report_key(wcombo, BTN_0, (data[7] & 0x08));
|
||||
wacom_report_key(wcombo, BTN_1, (data[7] & 0x20));
|
||||
@ -432,7 +450,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
unsigned int t;
|
||||
int idx = 0, result;
|
||||
|
||||
if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
|
||||
if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_INTUOSREAD
|
||||
&& data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD) {
|
||||
dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
|
||||
return 0;
|
||||
}
|
||||
@ -442,7 +461,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
idx = data[1] & 0x01;
|
||||
|
||||
/* pad packets. Works as a second tool and is always in prox */
|
||||
if (data[0] == 12) {
|
||||
if (data[0] == WACOM_REPORT_INTUOSPAD) {
|
||||
/* initiate the pad as a device */
|
||||
if (wacom->tool[1] != BTN_TOOL_FINGER)
|
||||
wacom->tool[1] = BTN_TOOL_FINGER;
|
||||
@ -608,95 +627,163 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void wacom_tpc_finger_in(struct wacom_wac *wacom, void *wcombo, char *data, int idx)
|
||||
{
|
||||
wacom_report_abs(wcombo, ABS_X,
|
||||
(data[2 + idx * 2] & 0xff) | ((data[3 + idx * 2] & 0x7f) << 8));
|
||||
wacom_report_abs(wcombo, ABS_Y,
|
||||
(data[6 + idx * 2] & 0xff) | ((data[7 + idx * 2] & 0x7f) << 8));
|
||||
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
|
||||
wacom_report_key(wcombo, wacom->tool[idx], 1);
|
||||
if (idx)
|
||||
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
|
||||
else
|
||||
wacom_report_key(wcombo, BTN_TOUCH, 1);
|
||||
}
|
||||
|
||||
static void wacom_tpc_touch_out(struct wacom_wac *wacom, void *wcombo, int idx)
|
||||
{
|
||||
wacom_report_abs(wcombo, ABS_X, 0);
|
||||
wacom_report_abs(wcombo, ABS_Y, 0);
|
||||
wacom_report_abs(wcombo, ABS_MISC, 0);
|
||||
wacom_report_key(wcombo, wacom->tool[idx], 0);
|
||||
if (idx)
|
||||
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
|
||||
else
|
||||
wacom_report_key(wcombo, BTN_TOUCH, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
static void wacom_tpc_touch_in(struct wacom_wac *wacom, void *wcombo)
|
||||
{
|
||||
char *data = wacom->data;
|
||||
struct urb *urb = ((struct wacom_combo *)wcombo)->urb;
|
||||
static int firstFinger = 0;
|
||||
static int secondFinger = 0;
|
||||
|
||||
wacom->tool[0] = BTN_TOOL_DOUBLETAP;
|
||||
wacom->id[0] = TOUCH_DEVICE_ID;
|
||||
wacom->tool[1] = BTN_TOOL_TRIPLETAP;
|
||||
|
||||
if (urb->actual_length != WACOM_PKGLEN_TPC1FG) {
|
||||
switch (data[0]) {
|
||||
case WACOM_REPORT_TPC1FG:
|
||||
wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
|
||||
wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
|
||||
wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
|
||||
wacom_report_key(wcombo, BTN_TOUCH, wacom_le16_to_cpu(&data[6]));
|
||||
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
|
||||
wacom_report_key(wcombo, wacom->tool[0], 1);
|
||||
break;
|
||||
case WACOM_REPORT_TPC2FG:
|
||||
/* keep this byte to send proper out-prox event */
|
||||
wacom->id[1] = data[1] & 0x03;
|
||||
|
||||
if (data[1] & 0x01) {
|
||||
wacom_tpc_finger_in(wacom, wcombo, data, 0);
|
||||
firstFinger = 1;
|
||||
} else if (firstFinger) {
|
||||
wacom_tpc_touch_out(wacom, wcombo, 0);
|
||||
}
|
||||
|
||||
if (data[1] & 0x02) {
|
||||
/* sync first finger data */
|
||||
if (firstFinger)
|
||||
wacom_input_sync(wcombo);
|
||||
|
||||
wacom_tpc_finger_in(wacom, wcombo, data, 1);
|
||||
secondFinger = 1;
|
||||
} else if (secondFinger) {
|
||||
/* sync first finger data */
|
||||
if (firstFinger)
|
||||
wacom_input_sync(wcombo);
|
||||
|
||||
wacom_tpc_touch_out(wacom, wcombo, 1);
|
||||
secondFinger = 0;
|
||||
}
|
||||
if (!(data[1] & 0x01))
|
||||
firstFinger = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
|
||||
wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
|
||||
wacom_report_key(wcombo, BTN_TOUCH, 1);
|
||||
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
|
||||
wacom_report_key(wcombo, wacom->tool[0], 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
{
|
||||
char *data = wacom->data;
|
||||
int prox = 0, pressure;
|
||||
int prox = 0, pressure, idx = -1;
|
||||
static int stylusInProx, touchInProx = 1, touchOut;
|
||||
struct urb *urb = ((struct wacom_combo *)wcombo)->urb;
|
||||
|
||||
dbg("wacom_tpc_irq: received report #%d", data[0]);
|
||||
|
||||
if (urb->actual_length == 5 || data[0] == 6) { /* Touch data */
|
||||
if (urb->actual_length == 5) { /* with touch */
|
||||
prox = data[0] & 0x03;
|
||||
if (urb->actual_length == WACOM_PKGLEN_TPC1FG || /* single touch */
|
||||
data[0] == WACOM_REPORT_TPC1FG || /* single touch */
|
||||
data[0] == WACOM_REPORT_TPC2FG) { /* 2FG touch */
|
||||
if (urb->actual_length == WACOM_PKGLEN_TPC1FG) { /* with touch */
|
||||
prox = data[0] & 0x01;
|
||||
} else { /* with capacity */
|
||||
prox = data[1] & 0x03;
|
||||
if (data[0] == WACOM_REPORT_TPC1FG)
|
||||
/* single touch */
|
||||
prox = data[1] & 0x01;
|
||||
else
|
||||
/* 2FG touch data */
|
||||
prox = data[1] & 0x03;
|
||||
}
|
||||
|
||||
if (!stylusInProx) { /* stylus not in prox */
|
||||
if (prox) {
|
||||
if (touchInProx) {
|
||||
wacom->tool[1] = BTN_TOOL_DOUBLETAP;
|
||||
wacom->id[0] = TOUCH_DEVICE_ID;
|
||||
if (urb->actual_length != 5) {
|
||||
wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
|
||||
wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
|
||||
wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
|
||||
wacom_report_key(wcombo, BTN_TOUCH, wacom_le16_to_cpu(&data[6]));
|
||||
} else {
|
||||
wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
|
||||
wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
|
||||
wacom_report_key(wcombo, BTN_TOUCH, 1);
|
||||
}
|
||||
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
|
||||
wacom_report_key(wcombo, wacom->tool[1], prox & 0x01);
|
||||
wacom_tpc_touch_in(wacom, wcombo);
|
||||
touchOut = 1;
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
|
||||
wacom_report_key(wcombo, wacom->tool[1], prox & 0x01);
|
||||
wacom_report_key(wcombo, BTN_TOUCH, 0);
|
||||
/* 2FGT out-prox */
|
||||
if (data[0] == WACOM_REPORT_TPC2FG) {
|
||||
idx = (wacom->id[1] & 0x01) - 1;
|
||||
if (idx == 0) {
|
||||
wacom_tpc_touch_out(wacom, wcombo, idx);
|
||||
/* sync first finger event */
|
||||
if (wacom->id[1] & 0x02)
|
||||
wacom_input_sync(wcombo);
|
||||
}
|
||||
idx = (wacom->id[1] & 0x02) - 1;
|
||||
if (idx == 1)
|
||||
wacom_tpc_touch_out(wacom, wcombo, idx);
|
||||
} else /* one finger touch */
|
||||
wacom_tpc_touch_out(wacom, wcombo, 0);
|
||||
touchOut = 0;
|
||||
touchInProx = 1;
|
||||
return 1;
|
||||
}
|
||||
} else if (touchOut || !prox) { /* force touch out-prox */
|
||||
wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID);
|
||||
wacom_report_key(wcombo, wacom->tool[1], 0);
|
||||
wacom_report_key(wcombo, BTN_TOUCH, 0);
|
||||
wacom_tpc_touch_out(wacom, wcombo, 0);
|
||||
touchOut = 0;
|
||||
touchInProx = 1;
|
||||
return 1;
|
||||
}
|
||||
} else if (data[0] == 2) { /* Penabled */
|
||||
} else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */
|
||||
prox = data[1] & 0x20;
|
||||
|
||||
touchInProx = 0;
|
||||
|
||||
wacom->id[0] = ERASER_DEVICE_ID;
|
||||
|
||||
/*
|
||||
* if going from out of proximity into proximity select between the eraser
|
||||
* and the pen based on the state of the stylus2 button, choose eraser if
|
||||
* pressed else choose pen. if not a proximity change from out to in, send
|
||||
* an out of proximity for previous tool then a in for new tool.
|
||||
*/
|
||||
if (prox) { /* in prox */
|
||||
if (!wacom->tool[0]) {
|
||||
if (!wacom->id[0]) {
|
||||
/* Going into proximity select tool */
|
||||
wacom->tool[1] = (data[1] & 0x08) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
|
||||
if (wacom->tool[1] == BTN_TOOL_PEN)
|
||||
wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
|
||||
if (wacom->tool[0] == BTN_TOOL_PEN)
|
||||
wacom->id[0] = STYLUS_DEVICE_ID;
|
||||
} else if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[1] & 0x08)) {
|
||||
/*
|
||||
* was entered with stylus2 pressed
|
||||
* report out proximity for previous tool
|
||||
*/
|
||||
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
|
||||
wacom_report_key(wcombo, wacom->tool[1], 0);
|
||||
wacom_input_sync(wcombo);
|
||||
|
||||
/* set new tool */
|
||||
wacom->tool[1] = BTN_TOOL_PEN;
|
||||
wacom->id[0] = STYLUS_DEVICE_ID;
|
||||
return 0;
|
||||
}
|
||||
if (wacom->tool[1] != BTN_TOOL_RUBBER) {
|
||||
/* Unknown tool selected default to pen tool */
|
||||
wacom->tool[1] = BTN_TOOL_PEN;
|
||||
wacom->id[0] = STYLUS_DEVICE_ID;
|
||||
else
|
||||
wacom->id[0] = ERASER_DEVICE_ID;
|
||||
}
|
||||
wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
|
||||
wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
|
||||
@ -706,17 +793,21 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
if (pressure < 0)
|
||||
pressure = wacom->features->pressure_max + pressure + 1;
|
||||
wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
|
||||
wacom_report_key(wcombo, BTN_TOUCH, pressure);
|
||||
wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
|
||||
} else {
|
||||
wacom_report_abs(wcombo, ABS_X, 0);
|
||||
wacom_report_abs(wcombo, ABS_Y, 0);
|
||||
wacom_report_abs(wcombo, ABS_PRESSURE, 0);
|
||||
wacom_report_key(wcombo, BTN_STYLUS, 0);
|
||||
wacom_report_key(wcombo, BTN_STYLUS2, 0);
|
||||
wacom_report_key(wcombo, BTN_TOUCH, 0);
|
||||
wacom->id[0] = 0;
|
||||
/* pen is out so touch can be enabled now */
|
||||
touchInProx = 1;
|
||||
}
|
||||
wacom_report_key(wcombo, wacom->tool[1], prox);
|
||||
wacom_report_key(wcombo, wacom->tool[0], prox);
|
||||
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
|
||||
stylusInProx = prox;
|
||||
wacom->tool[0] = prox;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -751,6 +842,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
|
||||
return wacom_intuos_irq(wacom_wac, wcombo);
|
||||
|
||||
case TABLETPC:
|
||||
case TABLETPC2FG:
|
||||
return wacom_tpc_irq(wacom_wac, wcombo);
|
||||
|
||||
default:
|
||||
@ -791,9 +883,17 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
|
||||
input_dev_i4s(input_dev, wacom_wac);
|
||||
input_dev_i(input_dev, wacom_wac);
|
||||
break;
|
||||
case TABLETPC2FG:
|
||||
input_dev_tpc2fg(input_dev, wacom_wac);
|
||||
/* fall through */
|
||||
case TABLETPC:
|
||||
input_dev_tpc(input_dev, wacom_wac);
|
||||
if (wacom_wac->features->device_type != BTN_TOOL_PEN)
|
||||
break; /* no need to process stylus stuff */
|
||||
|
||||
/* fall through */
|
||||
case PL:
|
||||
case PTU:
|
||||
case TABLETPC:
|
||||
input_dev_pl(input_dev, wacom_wac);
|
||||
/* fall through */
|
||||
case PENPARTNER:
|
||||
@ -804,66 +904,69 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
|
||||
}
|
||||
|
||||
static struct wacom_features wacom_features[] = {
|
||||
{ "Wacom Penpartner", 7, 5040, 3780, 255, 0, PENPARTNER },
|
||||
{ "Wacom Graphire", 8, 10206, 7422, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire3", 8, 10208, 7424, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 },
|
||||
{ "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 },
|
||||
{ "Wacom BambooFun 4x5", 9, 14760, 9225, 511, 63, WACOM_MO },
|
||||
{ "Wacom BambooFun 6x8", 9, 21648, 13530, 511, 63, WACOM_MO },
|
||||
{ "Wacom Bamboo1 Medium",8, 16704, 12064, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Volito", 8, 5104, 3712, 511, 63, GRAPHIRE },
|
||||
{ "Wacom PenStation2", 8, 3250, 2320, 255, 63, GRAPHIRE },
|
||||
{ "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE },
|
||||
{ "Wacom PenPartner2", 8, 3250, 2320, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Bamboo", 9, 14760, 9225, 511, 63, WACOM_MO },
|
||||
{ "Wacom Bamboo1", 8, 5104, 3712, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 31, INTUOS },
|
||||
{ "Wacom PL400", 8, 5408, 4056, 255, 0, PL },
|
||||
{ "Wacom PL500", 8, 6144, 4608, 255, 0, PL },
|
||||
{ "Wacom PL600", 8, 6126, 4604, 255, 0, PL },
|
||||
{ "Wacom PL600SX", 8, 6260, 5016, 255, 0, PL },
|
||||
{ "Wacom PL550", 8, 6144, 4608, 511, 0, PL },
|
||||
{ "Wacom PL800", 8, 7220, 5780, 511, 0, PL },
|
||||
{ "Wacom PL700", 8, 6758, 5406, 511, 0, PL },
|
||||
{ "Wacom PL510", 8, 6282, 4762, 511, 0, PL },
|
||||
{ "Wacom DTU710", 8, 34080, 27660, 511, 0, PL },
|
||||
{ "Wacom DTF521", 8, 6282, 4762, 511, 0, PL },
|
||||
{ "Wacom DTF720", 8, 6858, 5506, 511, 0, PL },
|
||||
{ "Wacom DTF720a", 8, 6858, 5506, 511, 0, PL },
|
||||
{ "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU },
|
||||
{ "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S },
|
||||
{ "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 },
|
||||
{ "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 },
|
||||
{ "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L },
|
||||
{ "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
|
||||
{ "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 },
|
||||
{ "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S },
|
||||
{ "Wacom Intuos4 4x6", 10, 31496, 19685, 2047, 63, INTUOS4S },
|
||||
{ "Wacom Intuos4 6x9", 10, 44704, 27940, 2047, 63, INTUOS4 },
|
||||
{ "Wacom Intuos4 8x13", 10, 65024, 40640, 2047, 63, INTUOS4L },
|
||||
{ "Wacom Intuos4 12x19", 10, 97536, 60960, 2047, 63, INTUOS4L },
|
||||
{ "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ },
|
||||
{ "Wacom Cintiq 20WSX", 10, 86680, 54180, 1023, 63, WACOM_BEE },
|
||||
{ "Wacom Cintiq 12WX", 10, 53020, 33440, 1023, 63, WACOM_BEE },
|
||||
{ "Wacom DTU1931", 8, 37832, 30305, 511, 0, PL },
|
||||
{ "Wacom ISDv4 90", 8, 26202, 16325, 255, 0, TABLETPC },
|
||||
{ "Wacom ISDv4 93", 8, 26202, 16325, 255, 0, TABLETPC },
|
||||
{ "Wacom ISDv4 9A", 8, 26202, 16325, 255, 0, TABLETPC },
|
||||
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
|
||||
{ "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER },
|
||||
{ "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 },
|
||||
{ "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 },
|
||||
{ "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO },
|
||||
{ "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO },
|
||||
{ "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE },
|
||||
{ "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE },
|
||||
{ "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE },
|
||||
{ "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO },
|
||||
{ "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS },
|
||||
{ "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL },
|
||||
{ "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL },
|
||||
{ "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL },
|
||||
{ "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL },
|
||||
{ "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL },
|
||||
{ "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL },
|
||||
{ "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL },
|
||||
{ "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL },
|
||||
{ "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL },
|
||||
{ "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL },
|
||||
{ "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL },
|
||||
{ "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL },
|
||||
{ "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU },
|
||||
{ "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS },
|
||||
{ "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S },
|
||||
{ "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 },
|
||||
{ "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 },
|
||||
{ "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L },
|
||||
{ "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L },
|
||||
{ "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 },
|
||||
{ "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S },
|
||||
{ "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S },
|
||||
{ "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 },
|
||||
{ "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L },
|
||||
{ "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L },
|
||||
{ "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ },
|
||||
{ "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE },
|
||||
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE },
|
||||
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL },
|
||||
{ "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
|
||||
{ "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
|
||||
{ "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
|
||||
{ "Wacom ISDv4 9F", WACOM_PKGLEN_PENABLED, 26202, 16325, 255, 0, TABLETPC },
|
||||
{ "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG },
|
||||
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG },
|
||||
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -927,6 +1030,9 @@ static struct usb_device_id wacom_ids[] = {
|
||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9F) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE2) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE3) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
|
||||
{ }
|
||||
};
|
||||
|
@ -9,12 +9,33 @@
|
||||
#ifndef WACOM_WAC_H
|
||||
#define WACOM_WAC_H
|
||||
|
||||
/* maximum packet length for USB devices */
|
||||
#define WACOM_PKGLEN_MAX 32
|
||||
|
||||
/* packet length for individual models */
|
||||
#define WACOM_PKGLEN_PENPRTN 7
|
||||
#define WACOM_PKGLEN_GRAPHIRE 8
|
||||
#define WACOM_PKGLEN_BBFUN 9
|
||||
#define WACOM_PKGLEN_INTUOS 10
|
||||
#define WACOM_PKGLEN_PENABLED 8
|
||||
#define WACOM_PKGLEN_TPC1FG 5
|
||||
#define WACOM_PKGLEN_TPC2FG 14
|
||||
|
||||
/* device IDs */
|
||||
#define STYLUS_DEVICE_ID 0x02
|
||||
#define TOUCH_DEVICE_ID 0x03
|
||||
#define CURSOR_DEVICE_ID 0x06
|
||||
#define ERASER_DEVICE_ID 0x0A
|
||||
#define PAD_DEVICE_ID 0x0F
|
||||
|
||||
/* wacom data packet report IDs */
|
||||
#define WACOM_REPORT_PENABLED 2
|
||||
#define WACOM_REPORT_INTUOSREAD 5
|
||||
#define WACOM_REPORT_INTUOSWRITE 6
|
||||
#define WACOM_REPORT_INTUOSPAD 12
|
||||
#define WACOM_REPORT_TPC1FG 6
|
||||
#define WACOM_REPORT_TPC2FG 13
|
||||
|
||||
enum {
|
||||
PENPARTNER = 0,
|
||||
GRAPHIRE,
|
||||
@ -32,6 +53,7 @@ enum {
|
||||
WACOM_BEE,
|
||||
WACOM_MO,
|
||||
TABLETPC,
|
||||
TABLETPC2FG,
|
||||
MAX_TYPE
|
||||
};
|
||||
|
||||
@ -43,8 +65,11 @@ struct wacom_features {
|
||||
int pressure_max;
|
||||
int distance_max;
|
||||
int type;
|
||||
int touch_x_max;
|
||||
int touch_y_max;
|
||||
int device_type;
|
||||
int x_phy;
|
||||
int y_phy;
|
||||
unsigned char unit;
|
||||
unsigned char unitExpo;
|
||||
};
|
||||
|
||||
struct wacom_wac {
|
||||
|
@ -450,6 +450,18 @@ config TOUCHSCREEN_USB_COMPOSITE
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called usbtouchscreen.
|
||||
|
||||
config TOUCHSCREEN_MC13783
|
||||
tristate "Freescale MC13783 touchscreen input driver"
|
||||
depends on MFD_MC13783
|
||||
help
|
||||
Say Y here if you have an Freescale MC13783 PMIC on your
|
||||
board and want to use its touchscreen
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mc13783_ts.
|
||||
|
||||
config TOUCHSCREEN_USB_EGALAX
|
||||
default y
|
||||
bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
|
||||
|
@ -18,6 +18,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
|
||||
|
258
drivers/input/touchscreen/mc13783_ts.c
Normal file
258
drivers/input/touchscreen/mc13783_ts.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Driver for the Freescale Semiconductor MC13783 touchscreen.
|
||||
*
|
||||
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2009 Sascha Hauer, Pengutronix
|
||||
*
|
||||
* Initial development of this code was funded by
|
||||
* Phytec Messtechnik GmbH, http://www.phytec.de/
|
||||
*
|
||||
* 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/platform_device.h>
|
||||
#include <linux/mfd/mc13783.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define MC13783_TS_NAME "mc13783-ts"
|
||||
|
||||
#define DEFAULT_SAMPLE_TOLERANCE 300
|
||||
|
||||
static unsigned int sample_tolerance = DEFAULT_SAMPLE_TOLERANCE;
|
||||
module_param(sample_tolerance, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(sample_tolerance,
|
||||
"If the minimal and maximal value read out for one axis (out "
|
||||
"of three) differ by this value (default: "
|
||||
__stringify(DEFAULT_SAMPLE_TOLERANCE) ") or more, the reading "
|
||||
"is supposed to be wrong and is discarded. Set to 0 to "
|
||||
"disable this check.");
|
||||
|
||||
struct mc13783_ts_priv {
|
||||
struct input_dev *idev;
|
||||
struct mc13783 *mc13783;
|
||||
struct delayed_work work;
|
||||
struct workqueue_struct *workq;
|
||||
unsigned int sample[4];
|
||||
};
|
||||
|
||||
static irqreturn_t mc13783_ts_handler(int irq, void *data)
|
||||
{
|
||||
struct mc13783_ts_priv *priv = data;
|
||||
|
||||
mc13783_ackirq(priv->mc13783, irq);
|
||||
|
||||
/*
|
||||
* Kick off reading coordinates. Note that if work happens already
|
||||
* be queued for future execution (it rearms itself) it will not
|
||||
* be rescheduled for immediate execution here. However the rearm
|
||||
* delay is HZ / 50 which is acceptable.
|
||||
*/
|
||||
queue_delayed_work(priv->workq, &priv->work, 0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define sort3(a0, a1, a2) ({ \
|
||||
if (a0 > a1) \
|
||||
swap(a0, a1); \
|
||||
if (a1 > a2) \
|
||||
swap(a1, a2); \
|
||||
if (a0 > a1) \
|
||||
swap(a0, a1); \
|
||||
})
|
||||
|
||||
static void mc13783_ts_report_sample(struct mc13783_ts_priv *priv)
|
||||
{
|
||||
struct input_dev *idev = priv->idev;
|
||||
int x0, x1, x2, y0, y1, y2;
|
||||
int cr0, cr1;
|
||||
|
||||
/*
|
||||
* the values are 10-bit wide only, but the two least significant
|
||||
* bits are for future 12 bit use and reading yields 0
|
||||
*/
|
||||
x0 = priv->sample[0] & 0xfff;
|
||||
x1 = priv->sample[1] & 0xfff;
|
||||
x2 = priv->sample[2] & 0xfff;
|
||||
y0 = priv->sample[3] & 0xfff;
|
||||
y1 = (priv->sample[0] >> 12) & 0xfff;
|
||||
y2 = (priv->sample[1] >> 12) & 0xfff;
|
||||
cr0 = (priv->sample[2] >> 12) & 0xfff;
|
||||
cr1 = (priv->sample[3] >> 12) & 0xfff;
|
||||
|
||||
dev_dbg(&idev->dev,
|
||||
"x: (% 4d,% 4d,% 4d) y: (% 4d, % 4d,% 4d) cr: (% 4d, % 4d)\n",
|
||||
x0, x1, x2, y0, y1, y2, cr0, cr1);
|
||||
|
||||
sort3(x0, x1, x2);
|
||||
sort3(y0, y1, y2);
|
||||
|
||||
cr0 = (cr0 + cr1) / 2;
|
||||
|
||||
if (!cr0 || !sample_tolerance ||
|
||||
(x2 - x0 < sample_tolerance &&
|
||||
y2 - y0 < sample_tolerance)) {
|
||||
/* report the median coordinate and average pressure */
|
||||
if (cr0) {
|
||||
input_report_abs(idev, ABS_X, x1);
|
||||
input_report_abs(idev, ABS_Y, y1);
|
||||
|
||||
dev_dbg(&idev->dev, "report (%d, %d, %d)\n",
|
||||
x1, y1, 0x1000 - cr0);
|
||||
queue_delayed_work(priv->workq, &priv->work, HZ / 50);
|
||||
} else
|
||||
dev_dbg(&idev->dev, "report release\n");
|
||||
|
||||
input_report_abs(idev, ABS_PRESSURE,
|
||||
cr0 ? 0x1000 - cr0 : cr0);
|
||||
input_report_key(idev, BTN_TOUCH, cr0);
|
||||
input_sync(idev);
|
||||
} else
|
||||
dev_dbg(&idev->dev, "discard event\n");
|
||||
}
|
||||
|
||||
static void mc13783_ts_work(struct work_struct *work)
|
||||
{
|
||||
struct mc13783_ts_priv *priv =
|
||||
container_of(work, struct mc13783_ts_priv, work.work);
|
||||
unsigned int mode = MC13783_ADC_MODE_TS;
|
||||
unsigned int channel = 12;
|
||||
|
||||
if (mc13783_adc_do_conversion(priv->mc13783,
|
||||
mode, channel, priv->sample) == 0)
|
||||
mc13783_ts_report_sample(priv);
|
||||
}
|
||||
|
||||
static int mc13783_ts_open(struct input_dev *dev)
|
||||
{
|
||||
struct mc13783_ts_priv *priv = input_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
mc13783_lock(priv->mc13783);
|
||||
|
||||
mc13783_ackirq(priv->mc13783, MC13783_IRQ_TS);
|
||||
|
||||
ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_TS,
|
||||
mc13783_ts_handler, MC13783_TS_NAME, priv);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = mc13783_reg_rmw(priv->mc13783, MC13783_ADC0,
|
||||
MC13783_ADC0_TSMOD_MASK, MC13783_ADC0_TSMOD0);
|
||||
if (ret)
|
||||
mc13783_irq_free(priv->mc13783, MC13783_IRQ_TS, priv);
|
||||
out:
|
||||
mc13783_unlock(priv->mc13783);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mc13783_ts_close(struct input_dev *dev)
|
||||
{
|
||||
struct mc13783_ts_priv *priv = input_get_drvdata(dev);
|
||||
|
||||
mc13783_lock(priv->mc13783);
|
||||
mc13783_reg_rmw(priv->mc13783, MC13783_ADC0,
|
||||
MC13783_ADC0_TSMOD_MASK, 0);
|
||||
mc13783_irq_free(priv->mc13783, MC13783_IRQ_TS, priv);
|
||||
mc13783_unlock(priv->mc13783);
|
||||
|
||||
cancel_delayed_work_sync(&priv->work);
|
||||
}
|
||||
|
||||
static int __init mc13783_ts_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13783_ts_priv *priv;
|
||||
struct input_dev *idev;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
idev = input_allocate_device();
|
||||
if (!priv || !idev)
|
||||
goto err_free_mem;
|
||||
|
||||
INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
|
||||
priv->mc13783 = dev_get_drvdata(pdev->dev.parent);
|
||||
priv->idev = idev;
|
||||
|
||||
/*
|
||||
* We need separate workqueue because mc13783_adc_do_conversion
|
||||
* uses keventd and thus would deadlock.
|
||||
*/
|
||||
priv->workq = create_singlethread_workqueue("mc13783_ts");
|
||||
if (!priv->workq)
|
||||
goto err_free_mem;
|
||||
|
||||
idev->name = MC13783_TS_NAME;
|
||||
idev->dev.parent = &pdev->dev;
|
||||
|
||||
idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
input_set_abs_params(idev, ABS_X, 0, 0xfff, 0, 0);
|
||||
input_set_abs_params(idev, ABS_Y, 0, 0xfff, 0, 0);
|
||||
input_set_abs_params(idev, ABS_PRESSURE, 0, 0xfff, 0, 0);
|
||||
|
||||
idev->open = mc13783_ts_open;
|
||||
idev->close = mc13783_ts_close;
|
||||
|
||||
input_set_drvdata(idev, priv);
|
||||
|
||||
ret = input_register_device(priv->idev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"register input device failed with %d\n", ret);
|
||||
goto err_destroy_wq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
return 0;
|
||||
|
||||
err_destroy_wq:
|
||||
destroy_workqueue(priv->workq);
|
||||
err_free_mem:
|
||||
input_free_device(idev);
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit mc13783_ts_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13783_ts_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
destroy_workqueue(priv->workq);
|
||||
input_unregister_device(priv->idev);
|
||||
kfree(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mc13783_ts_driver = {
|
||||
.remove = __devexit_p(mc13783_ts_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = MC13783_TS_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mc13783_ts_init(void)
|
||||
{
|
||||
return platform_driver_probe(&mc13783_ts_driver, &mc13783_ts_probe);
|
||||
}
|
||||
module_init(mc13783_ts_init);
|
||||
|
||||
static void __exit mc13783_ts_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mc13783_ts_driver);
|
||||
}
|
||||
module_exit(mc13783_ts_exit);
|
||||
|
||||
MODULE_DESCRIPTION("MC13783 input touchscreen driver");
|
||||
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" MC13783_TS_NAME);
|
@ -39,6 +39,10 @@ void i8042_lock_chip(void);
|
||||
void i8042_unlock_chip(void);
|
||||
int i8042_command(unsigned char *param, int command);
|
||||
bool i8042_check_port_owner(const struct serio *);
|
||||
int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio));
|
||||
int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio));
|
||||
|
||||
#else
|
||||
|
||||
@ -52,7 +56,7 @@ void i8042_unlock_chip(void)
|
||||
|
||||
int i8042_command(unsigned char *param, int command)
|
||||
{
|
||||
return -ENOSYS;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bool i8042_check_port_owner(const struct serio *serio)
|
||||
@ -60,6 +64,18 @@ bool i8042_check_port_owner(const struct serio *serio)
|
||||
return false;
|
||||
}
|
||||
|
||||
int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio))
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio))
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user