Merge branch 'next' into for-linus

Prepare first round of input updates for 3.17.
This commit is contained in:
Dmitry Torokhov 2014-08-06 23:36:12 -07:00
commit 5e2aa2ed08
9844 changed files with 502512 additions and 252808 deletions

View file

@ -665,4 +665,14 @@ config KEYBOARD_CROS_EC
To compile this driver as a module, choose M here: the
module will be called cros_ec_keyb.
config KEYBOARD_CAP1106
tristate "Microchip CAP1106 touch sensor"
depends on OF && I2C
select REGMAP_I2C
help
Say Y here to enable the CAP1106 touch sensor driver.
To compile this driver as a module, choose M here: the
module will be called cap1106.
endif

View file

@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_CAP1106) += cap1106.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o

View file

@ -0,0 +1,335 @@
/*
* Input driver for Microchip CAP1106, 6 channel capacitive touch sensor
*
* http://www.microchip.com/wwwproducts/Devices.aspx?product=CAP1106
*
* (c) 2014 Daniel Mack <linux@zonque.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/of_irq.h>
#include <linux/regmap.h>
#include <linux/i2c.h>
#include <linux/gpio/consumer.h>
#define CAP1106_REG_MAIN_CONTROL 0x00
#define CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT (6)
#define CAP1106_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
#define CAP1106_REG_MAIN_CONTROL_DLSEEP BIT(4)
#define CAP1106_REG_GENERAL_STATUS 0x02
#define CAP1106_REG_SENSOR_INPUT 0x03
#define CAP1106_REG_NOISE_FLAG_STATUS 0x0a
#define CAP1106_REG_SENOR_DELTA(X) (0x10 + (X))
#define CAP1106_REG_SENSITIVITY_CONTROL 0x1f
#define CAP1106_REG_CONFIG 0x20
#define CAP1106_REG_SENSOR_ENABLE 0x21
#define CAP1106_REG_SENSOR_CONFIG 0x22
#define CAP1106_REG_SENSOR_CONFIG2 0x23
#define CAP1106_REG_SAMPLING_CONFIG 0x24
#define CAP1106_REG_CALIBRATION 0x25
#define CAP1106_REG_INT_ENABLE 0x26
#define CAP1106_REG_REPEAT_RATE 0x28
#define CAP1106_REG_MT_CONFIG 0x2a
#define CAP1106_REG_MT_PATTERN_CONFIG 0x2b
#define CAP1106_REG_MT_PATTERN 0x2d
#define CAP1106_REG_RECALIB_CONFIG 0x2f
#define CAP1106_REG_SENSOR_THRESH(X) (0x30 + (X))
#define CAP1106_REG_SENSOR_NOISE_THRESH 0x38
#define CAP1106_REG_STANDBY_CHANNEL 0x40
#define CAP1106_REG_STANDBY_CONFIG 0x41
#define CAP1106_REG_STANDBY_SENSITIVITY 0x42
#define CAP1106_REG_STANDBY_THRESH 0x43
#define CAP1106_REG_CONFIG2 0x44
#define CAP1106_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
#define CAP1106_REG_SENSOR_CALIB (0xb1 + (X))
#define CAP1106_REG_SENSOR_CALIB_LSB1 0xb9
#define CAP1106_REG_SENSOR_CALIB_LSB2 0xba
#define CAP1106_REG_PRODUCT_ID 0xfd
#define CAP1106_REG_MANUFACTURER_ID 0xfe
#define CAP1106_REG_REVISION 0xff
#define CAP1106_NUM_CHN 6
#define CAP1106_PRODUCT_ID 0x55
#define CAP1106_MANUFACTURER_ID 0x5d
struct cap1106_priv {
struct regmap *regmap;
struct input_dev *idev;
/* config */
unsigned int keycodes[CAP1106_NUM_CHN];
};
static const struct reg_default cap1106_reg_defaults[] = {
{ CAP1106_REG_MAIN_CONTROL, 0x00 },
{ CAP1106_REG_GENERAL_STATUS, 0x00 },
{ CAP1106_REG_SENSOR_INPUT, 0x00 },
{ CAP1106_REG_NOISE_FLAG_STATUS, 0x00 },
{ CAP1106_REG_SENSITIVITY_CONTROL, 0x2f },
{ CAP1106_REG_CONFIG, 0x20 },
{ CAP1106_REG_SENSOR_ENABLE, 0x3f },
{ CAP1106_REG_SENSOR_CONFIG, 0xa4 },
{ CAP1106_REG_SENSOR_CONFIG2, 0x07 },
{ CAP1106_REG_SAMPLING_CONFIG, 0x39 },
{ CAP1106_REG_CALIBRATION, 0x00 },
{ CAP1106_REG_INT_ENABLE, 0x3f },
{ CAP1106_REG_REPEAT_RATE, 0x3f },
{ CAP1106_REG_MT_CONFIG, 0x80 },
{ CAP1106_REG_MT_PATTERN_CONFIG, 0x00 },
{ CAP1106_REG_MT_PATTERN, 0x3f },
{ CAP1106_REG_RECALIB_CONFIG, 0x8a },
{ CAP1106_REG_SENSOR_THRESH(0), 0x40 },
{ CAP1106_REG_SENSOR_THRESH(1), 0x40 },
{ CAP1106_REG_SENSOR_THRESH(2), 0x40 },
{ CAP1106_REG_SENSOR_THRESH(3), 0x40 },
{ CAP1106_REG_SENSOR_THRESH(4), 0x40 },
{ CAP1106_REG_SENSOR_THRESH(5), 0x40 },
{ CAP1106_REG_SENSOR_NOISE_THRESH, 0x01 },
{ CAP1106_REG_STANDBY_CHANNEL, 0x00 },
{ CAP1106_REG_STANDBY_CONFIG, 0x39 },
{ CAP1106_REG_STANDBY_SENSITIVITY, 0x02 },
{ CAP1106_REG_STANDBY_THRESH, 0x40 },
{ CAP1106_REG_CONFIG2, 0x40 },
{ CAP1106_REG_SENSOR_CALIB_LSB1, 0x00 },
{ CAP1106_REG_SENSOR_CALIB_LSB2, 0x00 },
};
static bool cap1106_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case CAP1106_REG_MAIN_CONTROL:
case CAP1106_REG_SENSOR_INPUT:
case CAP1106_REG_SENOR_DELTA(0):
case CAP1106_REG_SENOR_DELTA(1):
case CAP1106_REG_SENOR_DELTA(2):
case CAP1106_REG_SENOR_DELTA(3):
case CAP1106_REG_SENOR_DELTA(4):
case CAP1106_REG_SENOR_DELTA(5):
case CAP1106_REG_PRODUCT_ID:
case CAP1106_REG_MANUFACTURER_ID:
case CAP1106_REG_REVISION:
return true;
}
return false;
}
static const struct regmap_config cap1106_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = CAP1106_REG_REVISION,
.reg_defaults = cap1106_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(cap1106_reg_defaults),
.cache_type = REGCACHE_RBTREE,
.volatile_reg = cap1106_volatile_reg,
};
static irqreturn_t cap1106_thread_func(int irq_num, void *data)
{
struct cap1106_priv *priv = data;
unsigned int status;
int ret, i;
/*
* Deassert interrupt. This needs to be done before reading the status
* registers, which will not carry valid values otherwise.
*/
ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, 1, 0);
if (ret < 0)
goto out;
ret = regmap_read(priv->regmap, CAP1106_REG_SENSOR_INPUT, &status);
if (ret < 0)
goto out;
for (i = 0; i < CAP1106_NUM_CHN; i++)
input_report_key(priv->idev, priv->keycodes[i],
status & (1 << i));
input_sync(priv->idev);
out:
return IRQ_HANDLED;
}
static int cap1106_set_sleep(struct cap1106_priv *priv, bool sleep)
{
return regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
CAP1106_REG_MAIN_CONTROL_DLSEEP,
sleep ? CAP1106_REG_MAIN_CONTROL_DLSEEP : 0);
}
static int cap1106_input_open(struct input_dev *idev)
{
struct cap1106_priv *priv = input_get_drvdata(idev);
return cap1106_set_sleep(priv, false);
}
static void cap1106_input_close(struct input_dev *idev)
{
struct cap1106_priv *priv = input_get_drvdata(idev);
cap1106_set_sleep(priv, true);
}
static int cap1106_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct device *dev = &i2c_client->dev;
struct cap1106_priv *priv;
struct device_node *node;
int i, error, irq, gain = 0;
unsigned int val, rev;
u32 gain32, keycodes[CAP1106_NUM_CHN];
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->regmap = devm_regmap_init_i2c(i2c_client, &cap1106_regmap_config);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
error = regmap_read(priv->regmap, CAP1106_REG_PRODUCT_ID, &val);
if (error)
return error;
if (val != CAP1106_PRODUCT_ID) {
dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n",
val, CAP1106_PRODUCT_ID);
return -ENODEV;
}
error = regmap_read(priv->regmap, CAP1106_REG_MANUFACTURER_ID, &val);
if (error)
return error;
if (val != CAP1106_MANUFACTURER_ID) {
dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n",
val, CAP1106_MANUFACTURER_ID);
return -ENODEV;
}
error = regmap_read(priv->regmap, CAP1106_REG_REVISION, &rev);
if (error < 0)
return error;
dev_info(dev, "CAP1106 detected, revision 0x%02x\n", rev);
i2c_set_clientdata(i2c_client, priv);
node = dev->of_node;
if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) {
if (is_power_of_2(gain32) && gain32 <= 8)
gain = ilog2(gain32);
else
dev_err(dev, "Invalid sensor-gain value %d\n", gain32);
}
BUILD_BUG_ON(ARRAY_SIZE(keycodes) != ARRAY_SIZE(priv->keycodes));
/* Provide some useful defaults */
for (i = 0; i < ARRAY_SIZE(keycodes); i++)
keycodes[i] = KEY_A + i;
of_property_read_u32_array(node, "linux,keycodes",
keycodes, ARRAY_SIZE(keycodes));
for (i = 0; i < ARRAY_SIZE(keycodes); i++)
priv->keycodes[i] = keycodes[i];
error = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
CAP1106_REG_MAIN_CONTROL_GAIN_MASK,
gain << CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT);
if (error)
return error;
/* Disable autorepeat. The Linux input system has its own handling. */
error = regmap_write(priv->regmap, CAP1106_REG_REPEAT_RATE, 0);
if (error)
return error;
priv->idev = devm_input_allocate_device(dev);
if (!priv->idev)
return -ENOMEM;
priv->idev->name = "CAP1106 capacitive touch sensor";
priv->idev->id.bustype = BUS_I2C;
priv->idev->evbit[0] = BIT_MASK(EV_KEY);
if (of_property_read_bool(node, "autorepeat"))
__set_bit(EV_REP, priv->idev->evbit);
for (i = 0; i < CAP1106_NUM_CHN; i++)
__set_bit(priv->keycodes[i], priv->idev->keybit);
priv->idev->id.vendor = CAP1106_MANUFACTURER_ID;
priv->idev->id.product = CAP1106_PRODUCT_ID;
priv->idev->id.version = rev;
priv->idev->open = cap1106_input_open;
priv->idev->close = cap1106_input_close;
input_set_drvdata(priv->idev, priv);
/*
* Put the device in deep sleep mode for now.
* ->open() will bring it back once the it is actually needed.
*/
cap1106_set_sleep(priv, true);
error = input_register_device(priv->idev);
if (error)
return error;
irq = irq_of_parse_and_map(node, 0);
if (!irq) {
dev_err(dev, "Unable to parse or map IRQ\n");
return -ENXIO;
}
error = devm_request_threaded_irq(dev, irq, NULL, cap1106_thread_func,
IRQF_ONESHOT, dev_name(dev), priv);
if (error)
return error;
return 0;
}
static const struct of_device_id cap1106_dt_ids[] = {
{ .compatible = "microchip,cap1106", },
{}
};
MODULE_DEVICE_TABLE(of, cap1106_dt_ids);
static const struct i2c_device_id cap1106_i2c_ids[] = {
{ "cap1106", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, cap1106_i2c_ids);
static struct i2c_driver cap1106_i2c_driver = {
.driver = {
.name = "cap1106",
.owner = THIS_MODULE,
.of_match_table = cap1106_dt_ids,
},
.id_table = cap1106_i2c_ids,
.probe = cap1106_i2c_probe,
};
module_i2c_driver(cap1106_i2c_driver);
MODULE_ALIAS("platform:cap1106");
MODULE_DESCRIPTION("Microchip CAP1106 driver");
MODULE_AUTHOR("Daniel Mack <linux@zonque.org>");
MODULE_LICENSE("GPL v2");

View file

@ -531,8 +531,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int imx_kbd_suspend(struct device *dev)
static int __maybe_unused imx_kbd_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
@ -552,7 +551,7 @@ static int imx_kbd_suspend(struct device *dev)
return 0;
}
static int imx_kbd_resume(struct device *dev)
static int __maybe_unused imx_kbd_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
@ -575,7 +574,6 @@ err_clk:
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);

View file

@ -203,12 +203,17 @@ static int max7359_probe(struct i2c_client *client,
dev_dbg(&client->dev, "keys FIFO is 0x%02x\n", ret);
keypad = kzalloc(sizeof(struct max7359_keypad), GFP_KERNEL);
input_dev = input_allocate_device();
if (!keypad || !input_dev) {
keypad = devm_kzalloc(&client->dev, sizeof(struct max7359_keypad),
GFP_KERNEL);
if (!keypad) {
dev_err(&client->dev, "failed to allocate memory\n");
error = -ENOMEM;
goto failed_free_mem;
return -ENOMEM;
}
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "failed to allocate input device\n");
return -ENOMEM;
}
keypad->client = client;
@ -230,19 +235,20 @@ static int max7359_probe(struct i2c_client *client,
max7359_build_keycode(keypad, keymap_data);
error = request_threaded_irq(client->irq, NULL, max7359_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
client->name, keypad);
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
max7359_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
client->name, keypad);
if (error) {
dev_err(&client->dev, "failed to register interrupt\n");
goto failed_free_mem;
return error;
}
/* Register the input device */
error = input_register_device(input_dev);
if (error) {
dev_err(&client->dev, "failed to register input device\n");
goto failed_free_irq;
return error;
}
/* Initialize MAX7359 */
@ -251,24 +257,6 @@ static int max7359_probe(struct i2c_client *client,
i2c_set_clientdata(client, keypad);
device_init_wakeup(&client->dev, 1);
return 0;
failed_free_irq:
free_irq(client->irq, keypad);
failed_free_mem:
input_free_device(input_dev);
kfree(keypad);
return error;
}
static int max7359_remove(struct i2c_client *client)
{
struct max7359_keypad *keypad = i2c_get_clientdata(client);
free_irq(client->irq, keypad);
input_unregister_device(keypad->input_dev);
kfree(keypad);
return 0;
}
@ -313,7 +301,6 @@ static struct i2c_driver max7359_i2c_driver = {
.pm = &max7359_pm,
},
.probe = max7359_probe,
.remove = max7359_remove,
.id_table = max7359_ids,
};

View file

@ -392,7 +392,6 @@ static void keyspan_irq_recv(struct urb *urb)
default:
goto resubmit;
break;
}
if (debug)

View file

@ -83,6 +83,9 @@ soc_button_device_create(struct pnp_dev *pdev,
sizeof(*gpio_keys_pdata) +
sizeof(*gpio_keys) * MAX_NBUTTONS,
GFP_KERNEL);
if (!gpio_keys_pdata)
return ERR_PTR(-ENOMEM);
gpio_keys = (void *)(gpio_keys_pdata + 1);
for (info = button_info; info->name; info++) {

View file

@ -311,7 +311,14 @@ static int uinput_open(struct inode *inode, struct file *file)
static int uinput_validate_absbits(struct input_dev *dev)
{
unsigned int cnt;
int retval = 0;
int nslot;
if (!test_bit(EV_ABS, dev->evbit))
return 0;
/*
* Check if absmin/absmax/absfuzz/absflat are sane.
*/
for (cnt = 0; cnt < ABS_CNT; cnt++) {
int min, max;
@ -327,8 +334,7 @@ static int uinput_validate_absbits(struct input_dev *dev)
UINPUT_NAME, cnt,
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
retval = -EINVAL;
break;
return -EINVAL;
}
if (input_abs_get_flat(dev, cnt) >
@ -340,11 +346,18 @@ static int uinput_validate_absbits(struct input_dev *dev)
input_abs_get_flat(dev, cnt),
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
retval = -EINVAL;
break;
return -EINVAL;
}
}
return retval;
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
input_mt_init_slots(dev, nslot, 0);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
}
return 0;
}
static int uinput_allocate_device(struct uinput_device *udev)
@ -410,19 +423,9 @@ static int uinput_setup_device(struct uinput_device *udev,
input_abs_set_flat(dev, i, user_dev->absflat[i]);
}
/* check if absmin/absmax/absfuzz/absflat are filled as
* told in Documentation/input/input-programming.txt */
if (test_bit(EV_ABS, dev->evbit)) {
retval = uinput_validate_absbits(dev);
if (retval < 0)
goto exit;
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
input_mt_init_slots(dev, nslot, 0);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
}
}
retval = uinput_validate_absbits(dev);
if (retval < 0)
goto exit;
udev->state = UIST_SETUP_COMPLETE;
retval = count;
@ -720,6 +723,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
}
switch (cmd) {
case UI_GET_VERSION:
if (put_user(UINPUT_VERSION,
(unsigned int __user *)p))
retval = -EFAULT;
goto out;
case UI_DEV_CREATE:
retval = uinput_create_device(udev);
goto out;

View file

@ -99,6 +99,8 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
#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 */
#define ALPS_IS_RUSHMORE 0x100 /* device is a rushmore */
#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
static const struct alps_model_info alps_model_data[] = {
{ { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
@ -281,11 +283,10 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
*
* The bitmaps don't have enough data to track fingers, so this function
* only generates points representing a bounding box of at most two contacts.
* These two points are returned in x1, y1, x2, and y2.
* These two points are returned in fields->mt.
*/
static void alps_process_bitmap_dolphin(struct alps_data *priv,
struct alps_fields *fields,
int *x1, int *y1, int *x2, int *y2)
struct alps_fields *fields)
{
int box_middle_x, box_middle_y;
unsigned int x_map, y_map;
@ -308,8 +309,6 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
if (x_msb > priv->x_bits || y_msb > priv->y_bits)
return;
*x1 = *y1 = *x2 = *y2 = 0;
if (fields->fingers > 1) {
start_bit = priv->x_bits - x_msb;
end_bit = priv->x_bits - x_lsb;
@ -320,10 +319,35 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
end_bit = y_msb - 1;
box_middle_y = (priv->y_max * (start_bit + end_bit)) /
(2 * (priv->y_bits - 1));
*x1 = fields->x;
*y1 = fields->y;
*x2 = 2 * box_middle_x - *x1;
*y2 = 2 * box_middle_y - *y1;
fields->mt[0] = fields->st;
fields->mt[1].x = 2 * box_middle_x - fields->mt[0].x;
fields->mt[1].y = 2 * box_middle_y - fields->mt[0].y;
}
}
static void alps_get_bitmap_points(unsigned int map,
struct alps_bitmap_point *low,
struct alps_bitmap_point *high,
int *fingers)
{
struct alps_bitmap_point *point;
int i, bit, prev_bit = 0;
point = low;
for (i = 0; map != 0; i++, map >>= 1) {
bit = map & 1;
if (bit) {
if (!prev_bit) {
point->start_bit = i;
point->num_bits = 0;
(*fingers)++;
}
point->num_bits++;
} else {
if (prev_bit)
point = high;
}
prev_bit = bit;
}
}
@ -334,71 +358,21 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
*
* The bitmaps don't have enough data to track fingers, so this function
* only generates points representing a bounding box of all contacts.
* These points are returned in x1, y1, x2, and y2 when the return value
* These points are returned in fields->mt when the return value
* is greater than 0.
*/
static int alps_process_bitmap(struct alps_data *priv,
unsigned int x_map, unsigned int y_map,
int *x1, int *y1, int *x2, int *y2)
struct alps_fields *fields)
{
struct alps_bitmap_point {
int start_bit;
int num_bits;
};
int fingers_x = 0, fingers_y = 0, fingers;
int i, bit, prev_bit;
int i, fingers_x = 0, fingers_y = 0, fingers;
struct alps_bitmap_point x_low = {0,}, x_high = {0,};
struct alps_bitmap_point y_low = {0,}, y_high = {0,};
struct alps_bitmap_point *point;
if (!x_map || !y_map)
if (!fields->x_map || !fields->y_map)
return 0;
*x1 = *y1 = *x2 = *y2 = 0;
prev_bit = 0;
point = &x_low;
for (i = 0; x_map != 0; i++, x_map >>= 1) {
bit = x_map & 1;
if (bit) {
if (!prev_bit) {
point->start_bit = i;
fingers_x++;
}
point->num_bits++;
} else {
if (prev_bit)
point = &x_high;
else
point->num_bits = 0;
}
prev_bit = bit;
}
/*
* y bitmap is reversed for what we need (lower positions are in
* higher bits), so we process from the top end.
*/
y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits);
prev_bit = 0;
point = &y_low;
for (i = 0; y_map != 0; i++, y_map <<= 1) {
bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1));
if (bit) {
if (!prev_bit) {
point->start_bit = i;
fingers_y++;
}
point->num_bits++;
} else {
if (prev_bit)
point = &y_high;
else
point->num_bits = 0;
}
prev_bit = bit;
}
alps_get_bitmap_points(fields->x_map, &x_low, &x_high, &fingers_x);
alps_get_bitmap_points(fields->y_map, &y_low, &y_high, &fingers_y);
/*
* Fingers can overlap, so we use the maximum count of fingers
@ -407,58 +381,91 @@ static int alps_process_bitmap(struct alps_data *priv,
fingers = max(fingers_x, fingers_y);
/*
* If total fingers is > 1 but either axis reports only a single
* contact, we have overlapping or adjacent fingers. For the
* purposes of creating a bounding box, divide the single contact
* (roughly) equally between the two points.
* If an axis reports only a single contact, we have overlapping or
* adjacent fingers. Divide the single contact between the two points.
*/
if (fingers > 1) {
if (fingers_x == 1) {
i = x_low.num_bits / 2;
x_low.num_bits = x_low.num_bits - i;
x_high.start_bit = x_low.start_bit + i;
x_high.num_bits = max(i, 1);
} else if (fingers_y == 1) {
i = y_low.num_bits / 2;
y_low.num_bits = y_low.num_bits - i;
y_high.start_bit = y_low.start_bit + i;
y_high.num_bits = max(i, 1);
}
if (fingers_x == 1) {
i = (x_low.num_bits - 1) / 2;
x_low.num_bits = x_low.num_bits - i;
x_high.start_bit = x_low.start_bit + i;
x_high.num_bits = max(i, 1);
}
if (fingers_y == 1) {
i = (y_low.num_bits - 1) / 2;
y_low.num_bits = y_low.num_bits - i;
y_high.start_bit = y_low.start_bit + i;
y_high.num_bits = max(i, 1);
}
*x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
(2 * (priv->x_bits - 1));
*y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
(2 * (priv->y_bits - 1));
fields->mt[0].x =
(priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
(2 * (priv->x_bits - 1));
fields->mt[0].y =
(priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
(2 * (priv->y_bits - 1));
if (fingers > 1) {
*x2 = (priv->x_max *
(2 * x_high.start_bit + x_high.num_bits - 1)) /
(2 * (priv->x_bits - 1));
*y2 = (priv->y_max *
(2 * y_high.start_bit + y_high.num_bits - 1)) /
(2 * (priv->y_bits - 1));
fields->mt[1].x =
(priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
(2 * (priv->x_bits - 1));
fields->mt[1].y =
(priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
(2 * (priv->y_bits - 1));
/* y-bitmap order is reversed, except on rushmore */
if (!(priv->flags & ALPS_IS_RUSHMORE)) {
fields->mt[0].y = priv->y_max - fields->mt[0].y;
fields->mt[1].y = priv->y_max - fields->mt[1].y;
}
return fingers;
}
static void alps_set_slot(struct input_dev *dev, int slot, bool active,
int x, int y)
static void alps_set_slot(struct input_dev *dev, int slot, int x, int y)
{
input_mt_slot(dev, slot);
input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
if (active) {
input_report_abs(dev, ABS_MT_POSITION_X, x);
input_report_abs(dev, ABS_MT_POSITION_Y, y);
}
input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
input_report_abs(dev, ABS_MT_POSITION_X, x);
input_report_abs(dev, ABS_MT_POSITION_Y, y);
}
static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
int x1, int y1, int x2, int y2)
static void alps_report_mt_data(struct psmouse *psmouse, int n)
{
alps_set_slot(dev, 0, num_fingers != 0, x1, y1);
alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
struct alps_data *priv = psmouse->private;
struct input_dev *dev = psmouse->dev;
struct alps_fields *f = &priv->f;
int i, slot[MAX_TOUCHES];
input_mt_assign_slots(dev, slot, f->mt, n);
for (i = 0; i < n; i++)
alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y);
input_mt_sync_frame(dev);
}
static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
{
struct alps_data *priv = psmouse->private;
struct input_dev *dev = psmouse->dev;
struct alps_fields *f = &priv->f;
/* Use st data when we don't have mt data */
if (fingers < 2) {
f->mt[0].x = f->st.x;
f->mt[0].y = f->st.y;
fingers = f->pressure > 0 ? 1 : 0;
}
alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2);
input_mt_report_finger_count(dev, fingers);
input_report_key(dev, BTN_LEFT, f->left);
input_report_key(dev, BTN_RIGHT, f->right);
input_report_key(dev, BTN_MIDDLE, f->middle);
input_report_abs(dev, ABS_PRESSURE, f->pressure);
input_sync(dev);
}
static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
@ -532,7 +539,7 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
f->ts_middle = !!(p[3] & 0x40);
}
static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse)
{
f->first_mp = !!(p[4] & 0x40);
@ -546,24 +553,31 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
((p[2] & 0x7f) << 1) |
(p[4] & 0x01);
f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
((p[0] & 0x30) >> 4);
f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
f->z = p[5] & 0x7f;
f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
f->pressure = p[5] & 0x7f;
alps_decode_buttons_v3(f, p);
return 0;
}
static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse)
{
alps_decode_pinnacle(f, p, psmouse);
/* Rushmore's packet decode has a bit difference with Pinnacle's */
f->is_mp = !!(p[5] & 0x40);
f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
f->x_map |= (p[5] & 0x10) << 11;
f->y_map |= (p[5] & 0x20) << 6;
return 0;
}
static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse)
{
u64 palm_data = 0;
@ -573,9 +587,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
f->is_mp = !!(p[0] & 0x20);
if (!f->is_mp) {
f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
f->st.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
f->st.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
f->pressure = (p[0] & 4) ? 0 : p[5] & 0x7f;
alps_decode_buttons_v3(f, p);
} else {
f->fingers = ((p[0] & 0x6) >> 1 |
@ -596,19 +610,21 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
f->x_map = (palm_data >> priv->y_bits) &
(BIT(priv->x_bits) - 1);
}
return 0;
}
static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
struct input_dev *dev2 = priv->dev2;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
int fingers = 0, bmap_fn;
struct alps_fields f = {0};
struct alps_fields *f = &priv->f;
int fingers = 0;
priv->decode_fields(&f, packet, psmouse);
memset(f, 0, sizeof(*f));
priv->decode_fields(f, packet, psmouse);
/*
* There's no single feature of touchpad position and bitmap packets
@ -623,22 +639,14 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
* packet. Check for this, and when it happens process the
* position packet as usual.
*/
if (f.is_mp) {
fingers = f.fingers;
if (f->is_mp) {
fingers = f->fingers;
if (priv->proto_version == ALPS_PROTO_V3) {
bmap_fn = alps_process_bitmap(priv, f.x_map,
f.y_map, &x1, &y1,
&x2, &y2);
/*
* We shouldn't report more than one finger if
* we don't have two coordinates.
*/
if (fingers > 1 && bmap_fn < 2)
fingers = bmap_fn;
if (alps_process_bitmap(priv, f) == 0)
fingers = 0; /* Use st data */
/* Now process position packet */
priv->decode_fields(&f, priv->multi_data,
priv->decode_fields(f, priv->multi_data,
psmouse);
} else {
/*
@ -647,15 +655,14 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
* calculate Pt2, so we need to do position
* packet decode first.
*/
priv->decode_fields(&f, priv->multi_data,
priv->decode_fields(f, priv->multi_data,
psmouse);
/*
* Since Dolphin's finger number is reliable,
* there is no need to compare with bmap_fn.
*/
alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
&x2, &y2);
alps_process_bitmap_dolphin(priv, f);
}
} else {
priv->multi_packet = 0;
@ -670,10 +677,10 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
* out misidentified bitmap packets, we reject anything with this
* bit set.
*/
if (f.is_mp)
if (f->is_mp)
return;
if (!priv->multi_packet && f.first_mp) {
if (!priv->multi_packet && f->first_mp) {
priv->multi_packet = 1;
memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
return;
@ -687,44 +694,15 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
* with x, y, and z all zero, so these seem to be flukes.
* Ignore them.
*/
if (f.x && f.y && !f.z)
if (f->st.x && f->st.y && !f->pressure)
return;
/*
* If we don't have MT data or the bitmaps were empty, we have
* to rely on ST data.
*/
if (!fingers) {
x1 = f.x;
y1 = f.y;
fingers = f.z > 0 ? 1 : 0;
}
if (f.z >= 64)
input_report_key(dev, BTN_TOUCH, 1);
else
input_report_key(dev, BTN_TOUCH, 0);
alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
input_mt_report_finger_count(dev, fingers);
input_report_key(dev, BTN_LEFT, f.left);
input_report_key(dev, BTN_RIGHT, f.right);
input_report_key(dev, BTN_MIDDLE, f.middle);
if (f.z > 0) {
input_report_abs(dev, ABS_X, f.x);
input_report_abs(dev, ABS_Y, f.y);
}
input_report_abs(dev, ABS_PRESSURE, f.z);
input_sync(dev);
alps_report_semi_mt_data(psmouse, fingers);
if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
input_report_key(dev2, BTN_LEFT, f.ts_left);
input_report_key(dev2, BTN_RIGHT, f.ts_right);
input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
input_report_key(dev2, BTN_LEFT, f->ts_left);
input_report_key(dev2, BTN_RIGHT, f->ts_right);
input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
input_sync(dev2);
}
}
@ -823,13 +801,8 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
struct alps_fields *f = &priv->f;
int offset;
int x, y, z;
int left, right;
int x1, y1, x2, y2;
int fingers = 0;
unsigned int x_bitmap, y_bitmap;
/*
* v4 has a 6-byte encoding for bitmap data, but this data is
@ -851,71 +824,207 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
if (++priv->multi_packet > 2) {
priv->multi_packet = 0;
x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) |
f->x_map = ((priv->multi_data[2] & 0x1f) << 10) |
((priv->multi_data[3] & 0x60) << 3) |
((priv->multi_data[0] & 0x3f) << 2) |
((priv->multi_data[1] & 0x60) >> 5);
y_bitmap = ((priv->multi_data[5] & 0x01) << 10) |
f->y_map = ((priv->multi_data[5] & 0x01) << 10) |
((priv->multi_data[3] & 0x1f) << 5) |
(priv->multi_data[1] & 0x1f);
fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap,
&x1, &y1, &x2, &y2);
/* Store MT data.*/
priv->fingers = fingers;
priv->x1 = x1;
priv->x2 = x2;
priv->y1 = y1;
priv->y2 = y2;
f->fingers = alps_process_bitmap(priv, f);
}
left = packet[4] & 0x01;
right = packet[4] & 0x02;
f->left = packet[4] & 0x01;
f->right = packet[4] & 0x02;
x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
((packet[0] & 0x30) >> 4);
y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
z = packet[5] & 0x7f;
f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
((packet[0] & 0x30) >> 4);
f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
f->pressure = packet[5] & 0x7f;
alps_report_semi_mt_data(psmouse, f->fingers);
}
static bool alps_is_valid_package_v7(struct psmouse *psmouse)
{
switch (psmouse->pktcnt) {
case 3:
return (psmouse->packet[2] & 0x40) == 0x40;
case 4:
return (psmouse->packet[3] & 0x48) == 0x48;
case 6:
return (psmouse->packet[5] & 0x40) == 0x00;
}
return true;
}
static unsigned char alps_get_packet_id_v7(char *byte)
{
unsigned char packet_id;
if (byte[4] & 0x40)
packet_id = V7_PACKET_ID_TWO;
else if (byte[4] & 0x01)
packet_id = V7_PACKET_ID_MULTI;
else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
packet_id = V7_PACKET_ID_NEW;
else if (byte[1] == 0x00 && byte[4] == 0x00)
packet_id = V7_PACKET_ID_IDLE;
else
packet_id = V7_PACKET_ID_UNKNOWN;
return packet_id;
}
static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
unsigned char *pkt,
unsigned char pkt_id)
{
mt[0].x = ((pkt[2] & 0x80) << 4);
mt[0].x |= ((pkt[2] & 0x3F) << 5);
mt[0].x |= ((pkt[3] & 0x30) >> 1);
mt[0].x |= (pkt[3] & 0x07);
mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
mt[1].x = ((pkt[3] & 0x80) << 4);
mt[1].x |= ((pkt[4] & 0x80) << 3);
mt[1].x |= ((pkt[4] & 0x3F) << 4);
mt[1].y = ((pkt[5] & 0x80) << 3);
mt[1].y |= ((pkt[5] & 0x3F) << 4);
switch (pkt_id) {
case V7_PACKET_ID_TWO:
mt[1].x &= ~0x000F;
mt[1].y |= 0x000F;
break;
case V7_PACKET_ID_MULTI:
mt[1].x &= ~0x003F;
mt[1].y &= ~0x0020;
mt[1].y |= ((pkt[4] & 0x02) << 4);
mt[1].y |= 0x001F;
break;
case V7_PACKET_ID_NEW:
mt[1].x &= ~0x003F;
mt[1].x |= (pkt[0] & 0x20);
mt[1].y |= 0x000F;
break;
}
mt[0].y = 0x7FF - mt[0].y;
mt[1].y = 0x7FF - mt[1].y;
}
static int alps_get_mt_count(struct input_mt_pos *mt)
{
int i;
for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++)
/* empty */;
return i;
}
static int alps_decode_packet_v7(struct alps_fields *f,
unsigned char *p,
struct psmouse *psmouse)
{
unsigned char pkt_id;
pkt_id = alps_get_packet_id_v7(p);
if (pkt_id == V7_PACKET_ID_IDLE)
return 0;
if (pkt_id == V7_PACKET_ID_UNKNOWN)
return -1;
alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) {
f->left = (p[0] & 0x80) >> 7;
f->right = (p[0] & 0x20) >> 5;
f->middle = (p[0] & 0x10) >> 4;
}
if (pkt_id == V7_PACKET_ID_TWO)
f->fingers = alps_get_mt_count(f->mt);
else if (pkt_id == V7_PACKET_ID_MULTI)
f->fingers = 3 + (p[5] & 0x03);
return 0;
}
static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev2 = priv->dev2;
int x, y, z, left, right, middle;
/*
* If there were no contacts in the bitmap, use ST
* points in MT reports.
* If there were two contacts or more, report MT data.
* b7 b6 b5 b4 b3 b2 b1 b0
* Byte0 0 1 0 0 1 0 0 0
* Byte1 1 1 * * 1 M R L
* Byte2 X7 1 X5 X4 X3 X2 X1 X0
* Byte3 Z6 1 Y6 X6 1 Y2 Y1 Y0
* Byte4 Y7 0 Y5 Y4 Y3 1 1 0
* Byte5 T&P 0 Z5 Z4 Z3 Z2 Z1 Z0
* M / R / L: Middle / Right / Left button
*/
if (priv->fingers < 2) {
x1 = x;
y1 = y;
fingers = z > 0 ? 1 : 0;
} else {
fingers = priv->fingers;
x1 = priv->x1;
x2 = priv->x2;
y1 = priv->y1;
y2 = priv->y2;
}
if (z >= 64)
input_report_key(dev, BTN_TOUCH, 1);
else
input_report_key(dev, BTN_TOUCH, 0);
x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
((packet[3] & 0x20) << 1);
z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
left = (packet[1] & 0x01);
right = (packet[1] & 0x02) >> 1;
middle = (packet[1] & 0x04) >> 2;
input_mt_report_finger_count(dev, fingers);
/* Divide 2 since trackpoint's speed is too fast */
input_report_rel(dev2, REL_X, (char)x / 2);
input_report_rel(dev2, REL_Y, -((char)y / 2));
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
input_report_key(dev2, BTN_LEFT, left);
input_report_key(dev2, BTN_RIGHT, right);
input_report_key(dev2, BTN_MIDDLE, middle);
if (z > 0) {
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
}
input_report_abs(dev, ABS_PRESSURE, z);
input_sync(dev2);
}
static void alps_process_touchpad_packet_v7(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
struct input_dev *dev = psmouse->dev;
struct alps_fields *f = &priv->f;
memset(f, 0, sizeof(*f));
if (priv->decode_fields(f, psmouse->packet, psmouse))
return;
alps_report_mt_data(psmouse, alps_get_mt_count(f->mt));
input_mt_report_finger_count(dev, f->fingers);
input_report_key(dev, BTN_LEFT, f->left);
input_report_key(dev, BTN_RIGHT, f->right);
input_report_key(dev, BTN_MIDDLE, f->middle);
input_sync(dev);
}
static void alps_process_packet_v7(struct psmouse *psmouse)
{
unsigned char *packet = psmouse->packet;
if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06)
alps_process_trackstick_packet_v7(psmouse);
else
alps_process_touchpad_packet_v7(psmouse);
}
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
unsigned char packet[],
bool report_buttons)
@ -1080,6 +1189,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
return PSMOUSE_BAD_DATA;
}
if (priv->proto_version == ALPS_PROTO_V7 &&
!alps_is_valid_package_v7(psmouse)) {
psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
psmouse->pktcnt - 1,
psmouse->packet[psmouse->pktcnt - 1]);
return PSMOUSE_BAD_DATA;
}
if (psmouse->pktcnt == psmouse->pktsize) {
priv->process_packet(psmouse);
return PSMOUSE_FULL_PACKET;
@ -1192,6 +1309,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
return 0;
}
static bool alps_check_valid_firmware_id(unsigned char id[])
{
if (id[0] == 0x73)
return true;
if (id[0] == 0x88 &&
(id[1] == 0x07 ||
id[1] == 0x08 ||
(id[1] & 0xf0) == 0xb0 ||
(id[1] & 0xf0) == 0xc0)) {
return true;
}
return false;
}
static int alps_enter_command_mode(struct psmouse *psmouse)
{
unsigned char param[4];
@ -1201,8 +1334,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
return -1;
}
if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
param[0] != 0x73) {
if (!alps_check_valid_firmware_id(param)) {
psmouse_dbg(psmouse,
"unknown response while entering command mode\n");
return -1;
@ -1660,6 +1792,45 @@ error:
return -1;
}
static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch)
{
int reg, x_pitch, y_pitch, x_electrode, y_electrode, x_phys, y_phys;
struct alps_data *priv = psmouse->private;
reg = alps_command_mode_read_reg(psmouse, reg_pitch);
if (reg < 0)
return reg;
x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */
y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */
y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */
reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1);
if (reg < 0)
return reg;
x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
x_electrode = 17 + x_electrode;
y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */
y_electrode = 13 + y_electrode;
x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */
y_phys = y_pitch * (y_electrode - 1); /* In 0.1 mm units */
priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */
priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */
psmouse_dbg(psmouse,
"pitch %dx%d num-electrodes %dx%d physical size %dx%d mm res %dx%d\n",
x_pitch, y_pitch, x_electrode, y_electrode,
x_phys / 10, y_phys / 10, priv->x_res, priv->y_res);
return 0;
}
static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
@ -1680,6 +1851,9 @@ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
goto error;
if (alps_get_v3_v7_resolution(psmouse, 0xc2da))
goto error;
reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
if (reg_val == -1)
goto error;
@ -1856,6 +2030,35 @@ static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
return 0;
}
static int alps_hw_init_v7(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
int reg_val, ret = -1;
if (alps_enter_command_mode(psmouse) ||
alps_command_mode_read_reg(psmouse, 0xc2d9) == -1)
goto error;
if (alps_get_v3_v7_resolution(psmouse, 0xc397))
goto error;
if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
goto error;
reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
if (reg_val == -1)
goto error;
if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
goto error;
alps_exit_command_mode(psmouse);
return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
error:
alps_exit_command_mode(psmouse);
return ret;
}
static void alps_set_defaults(struct alps_data *priv)
{
priv->byte0 = 0x8f;
@ -1914,6 +2117,21 @@ static void alps_set_defaults(struct alps_data *priv)
priv->x_max = 2047;
priv->y_max = 1535;
break;
case ALPS_PROTO_V7:
priv->hw_init = alps_hw_init_v7;
priv->process_packet = alps_process_packet_v7;
priv->decode_fields = alps_decode_packet_v7;
priv->set_abs_params = alps_set_abs_params_mt;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
priv->x_max = 0xfff;
priv->y_max = 0x7ff;
priv->byte0 = 0x48;
priv->mask0 = 0x48;
if (priv->fw_ver[1] != 0xba)
priv->flags |= ALPS_BUTTONPAD;
break;
}
}
@ -1972,6 +2190,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
alps_exit_command_mode(psmouse))
return -EIO;
/* Save the Firmware version */
memcpy(priv->fw_ver, ec, 3);
if (alps_match_table(psmouse, priv, e7, ec) == 0) {
return 0;
} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
@ -1982,6 +2203,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
return -EIO;
else
return 0;
} else if (ec[0] == 0x88 &&
((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
priv->proto_version = ALPS_PROTO_V7;
alps_set_defaults(priv);
return 0;
} else if (ec[0] == 0x88 && ec[1] == 0x08) {
priv->proto_version = ALPS_PROTO_V3;
alps_set_defaults(priv);
@ -1990,6 +2217,7 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
priv->decode_fields = alps_decode_rushmore;
priv->x_bits = 16;
priv->y_bits = 12;
priv->flags |= ALPS_IS_RUSHMORE;
/* hack to make addr_command, nibble_command available */
psmouse->private = priv;
@ -2044,17 +2272,21 @@ static void alps_set_abs_params_st(struct alps_data *priv,
static void alps_set_abs_params_mt(struct alps_data *priv,
struct input_dev *dev1)
{
set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
input_mt_init_slots(dev1, 2, 0);
input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
input_abs_set_res(dev1, ABS_MT_POSITION_X, priv->x_res);
input_abs_set_res(dev1, ABS_MT_POSITION_Y, priv->y_res);
input_mt_init_slots(dev1, MAX_TOUCHES, INPUT_MT_POINTER |
INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
/* V7 is real multi-touch */
if (priv->proto_version == ALPS_PROTO_V7)
clear_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
}
int alps_init(struct psmouse *psmouse)
@ -2100,7 +2332,9 @@ int alps_init(struct psmouse *psmouse)
dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
priv->set_abs_params(priv, dev1);
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
/* No pressure on V7 */
if (priv->proto_version != ALPS_PROTO_V7)
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
if (priv->flags & ALPS_WHEEL) {
dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
@ -2117,6 +2351,9 @@ int alps_init(struct psmouse *psmouse)
dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
} else if (priv->flags & ALPS_BUTTONPAD) {
set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit);
clear_bit(BTN_RIGHT, dev1->keybit);
} else {
dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
}

View file

@ -12,17 +12,39 @@
#ifndef _ALPS_H
#define _ALPS_H
#include <linux/input/mt.h>
#define ALPS_PROTO_V1 1
#define ALPS_PROTO_V2 2
#define ALPS_PROTO_V3 3
#define ALPS_PROTO_V4 4
#define ALPS_PROTO_V5 5
#define ALPS_PROTO_V6 6
#define ALPS_PROTO_V7 7 /* t3btl t4s */
#define MAX_TOUCHES 2
#define DOLPHIN_COUNT_PER_ELECTRODE 64
#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
/*
* enum V7_PACKET_ID - defines the packet type for V7
* V7_PACKET_ID_IDLE: There's no finger and no button activity.
* V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
* or there's button activities.
* V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
* V7_PACKET_ID_NEW: The finger position in slot is not continues from
* previous packet.
*/
enum V7_PACKET_ID {
V7_PACKET_ID_IDLE,
V7_PACKET_ID_TWO,
V7_PACKET_ID_MULTI,
V7_PACKET_ID_NEW,
V7_PACKET_ID_UNKNOWN,
};
/**
* struct alps_model_info - touchpad ID table
* @signature: E7 response string to match.
@ -46,7 +68,7 @@ struct alps_model_info {
unsigned char command_mode_resp;
unsigned char proto_version;
unsigned char byte0, mask0;
unsigned char flags;
int flags;
};
/**
@ -65,14 +87,19 @@ struct alps_nibble_commands {
unsigned char data;
};
struct alps_bitmap_point {
int start_bit;
int num_bits;
};
/**
* struct alps_fields - decoded version of the report packet
* @x_map: Bitmap of active X positions for MT.
* @y_map: Bitmap of active Y positions for MT.
* @fingers: Number of fingers for MT.
* @x: X position for ST.
* @y: Y position for ST.
* @z: Z position for ST.
* @pressure: Pressure.
* @st: position for ST.
* @mt: position for MT.
* @first_mp: Packet is the first of a multi-packet report.
* @is_mp: Packet is part of a multi-packet report.
* @left: Left touchpad button is active.
@ -86,9 +113,11 @@ struct alps_fields {
unsigned int x_map;
unsigned int y_map;
unsigned int fingers;
unsigned int x;
unsigned int y;
unsigned int z;
int pressure;
struct input_mt_pos st;
struct input_mt_pos mt[MAX_TOUCHES];
unsigned int first_mp:1;
unsigned int is_mp:1;
@ -113,6 +142,7 @@ struct alps_fields {
* known format for this model. The first byte of the report, ANDed with
* mask0, should match byte0.
* @mask0: The mask used to check the first byte of the report.
* @fw_ver: cached copy of firmware version (EC report)
* @flags: Additional device capabilities (passthrough port, trackstick, etc.).
* @x_max: Largest possible X position value.
* @y_max: Largest possible Y position value.
@ -125,11 +155,7 @@ struct alps_fields {
* @prev_fin: Finger bit from previous packet.
* @multi_packet: Multi-packet data in progress.
* @multi_data: Saved multi-packet data.
* @x1: First X coordinate from last MT report.
* @x2: Second X coordinate from last MT report.
* @y1: First Y coordinate from last MT report.
* @y2: Second Y coordinate from last MT report.
* @fingers: Number of fingers from last MT report.
* @f: Decoded packet data fields.
* @quirks: Bitmap of ALPS_QUIRK_*.
* @timer: Timer for flushing out the final report packet in the stream.
*/
@ -142,23 +168,25 @@ struct alps_data {
int addr_command;
unsigned char proto_version;
unsigned char byte0, mask0;
unsigned char flags;
unsigned char fw_ver[3];
int flags;
int x_max;
int y_max;
int x_bits;
int y_bits;
unsigned int x_res;
unsigned int y_res;
int (*hw_init)(struct psmouse *psmouse);
void (*process_packet)(struct psmouse *psmouse);
void (*decode_fields)(struct alps_fields *f, unsigned char *p,
int (*decode_fields)(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse);
void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
int prev_fin;
int multi_packet;
unsigned char multi_data[6];
int x1, x2, y1, y2;
int fingers;
struct alps_fields f;
u8 quirks;
struct timer_list timer;
};

View file

@ -170,6 +170,15 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev,
serio_interrupt(kbd_dev->hv_serio, scan_code, 0);
}
spin_unlock_irqrestore(&kbd_dev->lock, flags);
/*
* Only trigger a wakeup on key down, otherwise
* "echo freeze > /sys/power/state" can't really enter the
* state because the Enter-UP can trigger a wakeup at once.
*/
if (!(info & IS_BREAK))
pm_wakeup_event(&hv_dev->device, 0);
break;
default:
@ -376,6 +385,9 @@ static int hv_kbd_probe(struct hv_device *hv_dev,
goto err_close_vmbus;
serio_register_port(kbd_dev->hv_serio);
device_init_wakeup(&hv_dev->device, true);
return 0;
err_close_vmbus:
@ -390,6 +402,7 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
{
struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev);
device_init_wakeup(&hv_dev->device, false);
serio_unregister_port(kbd_dev->hv_serio);
vmbus_close(hv_dev->channel);
kfree(kbd_dev);

View file

@ -73,20 +73,14 @@ config TABLET_USB_KBTAB
To compile this driver as a module, choose M here: the
module will be called kbtab.
config TABLET_USB_WACOM
tristate "Wacom Intuos/Graphire tablet support (USB)"
depends on USB_ARCH_HAS_HCD
select POWER_SUPPLY
select USB
select NEW_LEDS
select LEDS_CLASS
config TABLET_SERIAL_WACOM4
tristate "Wacom protocol 4 serial tablet support"
select SERIO
help
Say Y here if you want to use the USB version of the Wacom Intuos
or Graphire tablet. Make sure to say Y to "Mouse support"
(CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
(CONFIG_INPUT_EVDEV) as well.
Say Y here if you want to use Wacom protocol 4 serial tablets.
E.g. serial versions of the Cintiq, Graphire or Penpartner.
To compile this driver as a module, choose M here: the
module will be called wacom.
module will be called wacom_serial4.
endif

View file

@ -2,12 +2,10 @@
# Makefile for the tablet drivers
#
# Multipart objects.
wacom-objs := wacom_wac.o wacom_sys.o
obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o
obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o
obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o
obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o
obj-$(CONFIG_TABLET_SERIAL_WACOM4) += wacom_serial4.o

View file

@ -1,139 +0,0 @@
/*
* drivers/input/tablet/wacom.h
*
* USB Wacom tablet support
*
* Copyright (c) 2000-2004 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
* Copyright (c) 2000 Clifford Wolf <clifford@clifford.at>
* Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org>
* Copyright (c) 2000 James E. Blair <corvus@gnu.org>
* Copyright (c) 2000 Daniel Egger <egger@suse.de>
* Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
* Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
* Copyright (c) 2002-2011 Ping Cheng <pingc@wacom.com>
*
* ChangeLog:
* v0.1 (vp) - Initial release
* v0.2 (aba) - Support for all buttons / combinations
* v0.3 (vp) - Support for Intuos added
* v0.4 (sm) - Support for more Intuos models, menustrip
* relative mode, proximity.
* v0.5 (vp) - Big cleanup, nifty features removed,
* they belong in userspace
* v1.8 (vp) - Submit URB only when operating, moved to CVS,
* use input_report_key instead of report_btn and
* other cleanups
* v1.11 (vp) - Add URB ->dev setting for new kernels
* v1.11 (jb) - Add support for the 4D Mouse & Lens
* v1.12 (de) - Add support for two more inking pen IDs
* v1.14 (vp) - Use new USB device id probing scheme.
* Fix Wacom Graphire mouse wheel
* v1.18 (vp) - Fix mouse wheel direction
* Make mouse relative
* v1.20 (fl) - Report tool id for Intuos devices
* - Multi tools support
* - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
* - Add PL models support
* - Fix Wacom Graphire mouse wheel again
* v1.21 (vp) - Removed protocol descriptions
* - Added MISC_SERIAL for tool serial numbers
* (gb) - Identify version on module load.
* v1.21.1 (fl) - added Graphire2 support
* v1.21.2 (fl) - added Intuos2 support
* - added all the PL ids
* v1.21.3 (fl) - added another eraser id from Neil Okamoto
* - added smooth filter for Graphire from Peri Hankey
* - added PenPartner support from Olaf van Es
* - new tool ids from Ole Martin Bjoerndalen
* v1.29 (pc) - Add support for more tablets
* - Fix pressure reporting
* v1.30 (vp) - Merge 2.4 and 2.5 drivers
* - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
* - Cleanups here and there
* v1.30.1 (pi) - Added Graphire3 support
* v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
* v1.43 (pc) - Added support for Cintiq 21UX
* - Fixed a Graphire bug
* - Merged wacom_intuos3_irq into wacom_intuos_irq
* v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
* - Report Device IDs
* v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
* - Minor data report fix
* v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
* - where wacom_sys.c deals with system specific code,
* - and wacom_wac.c deals with Wacom specific code
* - Support Intuos3 4x6
* v1.47 (pc) - Added support for Bamboo
* v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX
* 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)
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef WACOM_H
#define WACOM_H
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/usb/input.h>
#include <linux/power_supply.h>
#include <asm/unaligned.h>
/*
* Version Information
*/
#define DRIVER_VERSION "v1.53"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB Wacom tablet driver"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_VENDOR_ID_LENOVO 0x17ef
struct wacom {
dma_addr_t data_dma;
struct usb_device *usbdev;
struct usb_interface *intf;
struct urb *irq;
struct wacom_wac wacom_wac;
struct mutex lock;
struct work_struct work;
bool open;
char phys[32];
struct wacom_led {
u8 select[2]; /* status led selector (0..3) */
u8 llv; /* status led brightness no button (1..127) */
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
} led;
struct power_supply battery;
};
static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
schedule_work(&wacom->work);
}
extern const struct usb_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
void wacom_setup_device_quirks(struct wacom_features *features);
int wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac);
#endif

View file

@ -0,0 +1,620 @@
/*
* Wacom protocol 4 serial tablet driver
*
* Copyright 2014 Hans de Goede <hdegoede@redhat.com>
* Copyright 2011-2012 Julian Squires <julian@cipht.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version of 2 of the License, or (at your
* option) any later version. See the file COPYING in the main directory of
* this archive for more details.
*
* Many thanks to Bill Seremetis, without whom PenPartner support
* would not have been possible. Thanks to Patrick Mahoney.
*
* This driver was developed with reference to much code written by others,
* particularly:
* - elo, gunze drivers by Vojtech Pavlik <vojtech@ucw.cz>;
* - wacom_w8001 driver by Jaya Kumar <jayakumar.lkml@gmail.com>;
* - the USB wacom input driver, credited to many people
* (see drivers/input/tablet/wacom.h);
* - new and old versions of linuxwacom / xf86-input-wacom credited to
* Frederic Lepied, France. <Lepied@XFree86.org> and
* Ping Cheng, Wacom. <pingc@wacom.com>;
* - and xf86wacom.c (a presumably ancient version of the linuxwacom code),
* by Frederic Lepied and Raph Levien <raph@gtk.org>.
*
* To do:
* - support pad buttons; (requires access to a model with pad buttons)
* - support (protocol 4-style) tilt (requires access to a > 1.4 rom model)
*/
/*
* Wacom serial protocol 4 documentation taken from linuxwacom-0.9.9 code,
* protocol 4 uses 7 or 9 byte of data in the following format:
*
* Byte 1
* bit 7 Sync bit always 1
* bit 6 Pointing device detected
* bit 5 Cursor = 0 / Stylus = 1
* bit 4 Reserved
* bit 3 1 if a button on the pointing device has been pressed
* bit 2 P0 (optional)
* bit 1 X15
* bit 0 X14
*
* Byte 2
* bit 7 Always 0
* bits 6-0 = X13 - X7
*
* Byte 3
* bit 7 Always 0
* bits 6-0 = X6 - X0
*
* Byte 4
* bit 7 Always 0
* bit 6 B3
* bit 5 B2
* bit 4 B1
* bit 3 B0
* bit 2 P1 (optional)
* bit 1 Y15
* bit 0 Y14
*
* Byte 5
* bit 7 Always 0
* bits 6-0 = Y13 - Y7
*
* Byte 6
* bit 7 Always 0
* bits 6-0 = Y6 - Y0
*
* Byte 7
* bit 7 Always 0
* bit 6 Sign of pressure data; or wheel-rel for cursor tool
* bit 5 P7; or REL1 for cursor tool
* bit 4 P6; or REL0 for cursor tool
* bit 3 P5
* bit 2 P4
* bit 1 P3
* bit 0 P2
*
* byte 8 and 9 are optional and present only
* in tilt mode.
*
* Byte 8
* bit 7 Always 0
* bit 6 Sign of tilt X
* bit 5 Xt6
* bit 4 Xt5
* bit 3 Xt4
* bit 2 Xt3
* bit 1 Xt2
* bit 0 Xt1
*
* Byte 9
* bit 7 Always 0
* bit 6 Sign of tilt Y
* bit 5 Yt6
* bit 4 Yt5
* bit 3 Yt4
* bit 2 Yt3
* bit 1 Yt2
* bit 0 Yt1
*/
#include <linux/completion.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/slab.h>
#include <linux/string.h>
MODULE_AUTHOR("Julian Squires <julian@cipht.net>, Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("Wacom protocol 4 serial tablet driver");
MODULE_LICENSE("GPL");
#define REQUEST_MODEL_AND_ROM_VERSION "~#"
#define REQUEST_MAX_COORDINATES "~C\r"
#define REQUEST_CONFIGURATION_STRING "~R\r"
#define REQUEST_RESET_TO_PROTOCOL_IV "\r#"
/*
* Note: sending "\r$\r" causes at least the Digitizer II to send
* packets in ASCII instead of binary. "\r#" seems to undo that.
*/
#define COMMAND_START_SENDING_PACKETS "ST\r"
#define COMMAND_STOP_SENDING_PACKETS "SP\r"
#define COMMAND_MULTI_MODE_INPUT "MU1\r"
#define COMMAND_ORIGIN_IN_UPPER_LEFT "OC1\r"
#define COMMAND_ENABLE_ALL_MACRO_BUTTONS "~M0\r"
#define COMMAND_DISABLE_GROUP_1_MACRO_BUTTONS "~M1\r"
#define COMMAND_TRANSMIT_AT_MAX_RATE "IT0\r"
#define COMMAND_DISABLE_INCREMENTAL_MODE "IN0\r"
#define COMMAND_ENABLE_CONTINUOUS_MODE "SR\r"
#define COMMAND_ENABLE_PRESSURE_MODE "PH1\r"
#define COMMAND_Z_FILTER "ZF1\r"
/* Note that this is a protocol 4 packet without tilt information. */
#define PACKET_LENGTH 7
#define DATA_SIZE 32
/* flags */
#define F_COVERS_SCREEN 0x01
#define F_HAS_STYLUS2 0x02
#define F_HAS_SCROLLWHEEL 0x04
/* device IDs */
#define STYLUS_DEVICE_ID 0x02
#define CURSOR_DEVICE_ID 0x06
#define ERASER_DEVICE_ID 0x0A
enum { STYLUS = 1, ERASER, CURSOR };
static const struct {
int device_id;
int input_id;
} tools[] = {
{ 0, 0 },
{ STYLUS_DEVICE_ID, BTN_TOOL_PEN },
{ ERASER_DEVICE_ID, BTN_TOOL_RUBBER },
{ CURSOR_DEVICE_ID, BTN_TOOL_MOUSE },
};
struct wacom {
struct input_dev *dev;
struct completion cmd_done;
int result;
u8 expect;
u8 eraser_mask;
unsigned int extra_z_bits;
unsigned int flags;
unsigned int res_x, res_y;
unsigned int max_x, max_y;
unsigned int tool;
unsigned int idx;
u8 data[DATA_SIZE];
char phys[32];
};
enum {
MODEL_CINTIQ = 0x504C, /* PL */
MODEL_CINTIQ2 = 0x4454, /* DT */
MODEL_DIGITIZER_II = 0x5544, /* UD */
MODEL_GRAPHIRE = 0x4554, /* ET */
MODEL_PENPARTNER = 0x4354, /* CT */
};
static void wacom_handle_model_response(struct wacom *wacom)
{
int major_v, minor_v, r = 0;
char *p;
p = strrchr(wacom->data, 'V');
if (p)
r = sscanf(p + 1, "%u.%u", &major_v, &minor_v);
if (r != 2)
major_v = minor_v = 0;
switch (wacom->data[2] << 8 | wacom->data[3]) {
case MODEL_CINTIQ: /* UNTESTED */
case MODEL_CINTIQ2:
if ((wacom->data[2] << 8 | wacom->data[3]) == MODEL_CINTIQ) {
wacom->dev->name = "Wacom Cintiq";
wacom->dev->id.version = MODEL_CINTIQ;
} else {
wacom->dev->name = "Wacom Cintiq II";
wacom->dev->id.version = MODEL_CINTIQ2;
}
wacom->res_x = 508;
wacom->res_y = 508;
switch (wacom->data[5] << 8 | wacom->data[6]) {
case 0x3731: /* PL-710 */
wacom->res_x = 2540;
wacom->res_y = 2540;
/* fall through */
case 0x3535: /* PL-550 */
case 0x3830: /* PL-800 */
wacom->extra_z_bits = 2;
}
wacom->flags = F_COVERS_SCREEN;
break;
case MODEL_PENPARTNER:
wacom->dev->name = "Wacom Penpartner";
wacom->dev->id.version = MODEL_PENPARTNER;
wacom->res_x = 1000;
wacom->res_y = 1000;
break;
case MODEL_GRAPHIRE:
wacom->dev->name = "Wacom Graphire";
wacom->dev->id.version = MODEL_GRAPHIRE;
wacom->res_x = 1016;
wacom->res_y = 1016;
wacom->max_x = 5103;
wacom->max_y = 3711;
wacom->extra_z_bits = 2;
wacom->eraser_mask = 0x08;
wacom->flags = F_HAS_STYLUS2 | F_HAS_SCROLLWHEEL;
break;
case MODEL_DIGITIZER_II:
wacom->dev->name = "Wacom Digitizer II";
wacom->dev->id.version = MODEL_DIGITIZER_II;
if (major_v == 1 && minor_v <= 2)
wacom->extra_z_bits = 0; /* UNTESTED */
break;
default:
dev_err(&wacom->dev->dev, "Unsupported Wacom model %s\n",
wacom->data);
wacom->result = -ENODEV;
return;
}
dev_info(&wacom->dev->dev, "%s tablet, version %u.%u\n",
wacom->dev->name, major_v, minor_v);
}
static void wacom_handle_configuration_response(struct wacom *wacom)
{
int r, skip;
dev_dbg(&wacom->dev->dev, "Configuration string: %s\n", wacom->data);
r = sscanf(wacom->data, "~R%x,%u,%u,%u,%u", &skip, &skip, &skip,
&wacom->res_x, &wacom->res_y);
if (r != 5)
dev_warn(&wacom->dev->dev, "could not get resolution\n");
}
static void wacom_handle_coordinates_response(struct wacom *wacom)
{
int r;
dev_dbg(&wacom->dev->dev, "Coordinates string: %s\n", wacom->data);
r = sscanf(wacom->data, "~C%u,%u", &wacom->max_x, &wacom->max_y);
if (r != 2)
dev_warn(&wacom->dev->dev, "could not get max coordinates\n");
}
static void wacom_handle_response(struct wacom *wacom)
{
if (wacom->data[0] != '~' || wacom->data[1] != wacom->expect) {
dev_err(&wacom->dev->dev,
"Wacom got an unexpected response: %s\n", wacom->data);
wacom->result = -EIO;
} else {
wacom->result = 0;
switch (wacom->data[1]) {
case '#':
wacom_handle_model_response(wacom);
break;
case 'R':
wacom_handle_configuration_response(wacom);
break;
case 'C':
wacom_handle_coordinates_response(wacom);
break;
}
}
complete(&wacom->cmd_done);
}
static void wacom_handle_packet(struct wacom *wacom)
{
u8 in_proximity_p, stylus_p, button;
unsigned int tool;
int x, y, z;
in_proximity_p = wacom->data[0] & 0x40;
stylus_p = wacom->data[0] & 0x20;
button = (wacom->data[3] & 0x78) >> 3;
x = (wacom->data[0] & 3) << 14 | wacom->data[1]<<7 | wacom->data[2];
y = (wacom->data[3] & 3) << 14 | wacom->data[4]<<7 | wacom->data[5];
if (in_proximity_p && stylus_p) {
z = wacom->data[6] & 0x7f;
if (wacom->extra_z_bits >= 1)
z = z << 1 | (wacom->data[3] & 0x4) >> 2;
if (wacom->extra_z_bits > 1)
z = z << 1 | (wacom->data[0] & 0x4) >> 2;
z = z ^ (0x40 << wacom->extra_z_bits);
} else {
z = -1;
}
if (stylus_p)
tool = (button & wacom->eraser_mask) ? ERASER : STYLUS;
else
tool = CURSOR;
if (tool != wacom->tool && wacom->tool != 0) {
input_report_key(wacom->dev, tools[wacom->tool].input_id, 0);
input_sync(wacom->dev);
}
wacom->tool = tool;
input_report_key(wacom->dev, tools[tool].input_id, in_proximity_p);
input_report_abs(wacom->dev, ABS_MISC,
in_proximity_p ? tools[tool].device_id : 0);
input_report_abs(wacom->dev, ABS_X, x);
input_report_abs(wacom->dev, ABS_Y, y);
input_report_abs(wacom->dev, ABS_PRESSURE, z);
if (stylus_p) {
input_report_key(wacom->dev, BTN_TOUCH, button & 1);
input_report_key(wacom->dev, BTN_STYLUS, button & 2);
input_report_key(wacom->dev, BTN_STYLUS2, button & 4);
} else {
input_report_key(wacom->dev, BTN_LEFT, button & 1);
input_report_key(wacom->dev, BTN_RIGHT, button & 2);
input_report_key(wacom->dev, BTN_MIDDLE, button & 4);
/* handle relative wheel for non-stylus device */
z = (wacom->data[6] & 0x30) >> 4;
if (wacom->data[6] & 0x40)
z = -z;
input_report_rel(wacom->dev, REL_WHEEL, z);
}
input_sync(wacom->dev);
}
static void wacom_clear_data_buf(struct wacom *wacom)
{
memset(wacom->data, 0, DATA_SIZE);
wacom->idx = 0;
}
static irqreturn_t wacom_interrupt(struct serio *serio, unsigned char data,
unsigned int flags)
{
struct wacom *wacom = serio_get_drvdata(serio);
if (data & 0x80)
wacom->idx = 0;
/*
* We're either expecting a carriage return-terminated ASCII
* response string, or a seven-byte packet with the MSB set on
* the first byte.
*
* Note however that some tablets (the PenPartner, for
* example) don't send a carriage return at the end of a
* command. We handle these by waiting for timeout.
*/
if (data == '\r' && !(wacom->data[0] & 0x80)) {
wacom_handle_response(wacom);
wacom_clear_data_buf(wacom);
return IRQ_HANDLED;
}
/* Leave place for 0 termination */
if (wacom->idx > (DATA_SIZE - 2)) {
dev_dbg(&wacom->dev->dev,
"throwing away %d bytes of garbage\n", wacom->idx);
wacom_clear_data_buf(wacom);
}
wacom->data[wacom->idx++] = data;
if (wacom->idx == PACKET_LENGTH && (wacom->data[0] & 0x80)) {
wacom_handle_packet(wacom);
wacom_clear_data_buf(wacom);
}
return IRQ_HANDLED;
}
static void wacom_disconnect(struct serio *serio)
{
struct wacom *wacom = serio_get_drvdata(serio);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_unregister_device(wacom->dev);
kfree(wacom);
}
static int wacom_send(struct serio *serio, const u8 *command)
{
int err = 0;
for (; !err && *command; command++)
err = serio_write(serio, *command);
return err;
}
static int wacom_send_setup_string(struct wacom *wacom, struct serio *serio)
{
const u8 *cmd;
switch (wacom->dev->id.version) {
case MODEL_CINTIQ: /* UNTESTED */
cmd = COMMAND_ORIGIN_IN_UPPER_LEFT
COMMAND_TRANSMIT_AT_MAX_RATE
COMMAND_ENABLE_CONTINUOUS_MODE
COMMAND_START_SENDING_PACKETS;
break;
case MODEL_PENPARTNER:
cmd = COMMAND_ENABLE_PRESSURE_MODE
COMMAND_START_SENDING_PACKETS;
break;
default:
cmd = COMMAND_MULTI_MODE_INPUT
COMMAND_ORIGIN_IN_UPPER_LEFT
COMMAND_ENABLE_ALL_MACRO_BUTTONS
COMMAND_DISABLE_GROUP_1_MACRO_BUTTONS
COMMAND_TRANSMIT_AT_MAX_RATE
COMMAND_DISABLE_INCREMENTAL_MODE
COMMAND_ENABLE_CONTINUOUS_MODE
COMMAND_Z_FILTER
COMMAND_START_SENDING_PACKETS;
break;
}
return wacom_send(serio, cmd);
}
static int wacom_send_and_wait(struct wacom *wacom, struct serio *serio,
const u8 *cmd, const char *desc)
{
int err;
unsigned long u;
wacom->expect = cmd[1];
init_completion(&wacom->cmd_done);
err = wacom_send(serio, cmd);
if (err)
return err;
u = wait_for_completion_timeout(&wacom->cmd_done, HZ);
if (u == 0) {
/* Timeout, process what we've received. */
wacom_handle_response(wacom);
}
wacom->expect = 0;
return wacom->result;
}
static int wacom_setup(struct wacom *wacom, struct serio *serio)
{
int err;
/* Note that setting the link speed is the job of inputattach.
* We assume that reset negotiation has already happened,
* here. */
err = wacom_send_and_wait(wacom, serio, REQUEST_MODEL_AND_ROM_VERSION,
"model and version");
if (err)
return err;
if (!(wacom->res_x && wacom->res_y)) {
err = wacom_send_and_wait(wacom, serio,
REQUEST_CONFIGURATION_STRING,
"configuration string");
if (err)
return err;
}
if (!(wacom->max_x && wacom->max_y)) {
err = wacom_send_and_wait(wacom, serio,
REQUEST_MAX_COORDINATES,
"coordinates string");
if (err)
return err;
}
return wacom_send_setup_string(wacom, serio);
}
static int wacom_connect(struct serio *serio, struct serio_driver *drv)
{
struct wacom *wacom;
struct input_dev *input_dev;
int err = -ENOMEM;
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
input_dev = input_allocate_device();
if (!wacom || !input_dev)
goto free_device;
wacom->dev = input_dev;
wacom->extra_z_bits = 1;
wacom->eraser_mask = 0x04;
wacom->tool = wacom->idx = 0;
snprintf(wacom->phys, sizeof(wacom->phys), "%s/input0", serio->phys);
input_dev->phys = wacom->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_WACOM_IV;
input_dev->id.product = serio->id.extra;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] =
BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_REL);
set_bit(ABS_MISC, input_dev->absbit);
set_bit(BTN_TOOL_PEN, input_dev->keybit);
set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
set_bit(BTN_TOUCH, input_dev->keybit);
set_bit(BTN_STYLUS, input_dev->keybit);
set_bit(BTN_LEFT, input_dev->keybit);
set_bit(BTN_RIGHT, input_dev->keybit);
set_bit(BTN_MIDDLE, input_dev->keybit);
serio_set_drvdata(serio, wacom);
err = serio_open(serio, drv);
if (err)
goto free_device;
err = wacom_setup(wacom, serio);
if (err)
goto close_serio;
set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
if (!(wacom->flags & F_COVERS_SCREEN))
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
if (wacom->flags & F_HAS_STYLUS2)
__set_bit(BTN_STYLUS2, input_dev->keybit);
if (wacom->flags & F_HAS_SCROLLWHEEL)
__set_bit(REL_WHEEL, input_dev->relbit);
input_abs_set_res(wacom->dev, ABS_X, wacom->res_x);
input_abs_set_res(wacom->dev, ABS_Y, wacom->res_y);
input_set_abs_params(wacom->dev, ABS_X, 0, wacom->max_x, 0, 0);
input_set_abs_params(wacom->dev, ABS_Y, 0, wacom->max_y, 0, 0);
input_set_abs_params(wacom->dev, ABS_PRESSURE, -1,
(1 << (7 + wacom->extra_z_bits)) - 1, 0, 0);
err = input_register_device(wacom->dev);
if (err)
goto close_serio;
return 0;
close_serio:
serio_close(serio);
free_device:
serio_set_drvdata(serio, NULL);
input_free_device(input_dev);
kfree(wacom);
return err;
}
static struct serio_device_id wacom_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_WACOM_IV,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, wacom_serio_ids);
static struct serio_driver wacom_drv = {
.driver = {
.name = "wacom_serial4",
},
.description = "Wacom protocol 4 serial tablet driver",
.id_table = wacom_serio_ids,
.interrupt = wacom_interrupt,
.connect = wacom_connect,
.disconnect = wacom_disconnect,
};
module_serio_driver(wacom_drv);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,165 +0,0 @@
/*
* drivers/input/tablet/wacom_wac.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef WACOM_WAC_H
#define WACOM_WAC_H
#include <linux/types.h>
/* maximum packet length for USB devices */
#define WACOM_PKGLEN_MAX 68
#define WACOM_NAME_MAX 64
/* 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_TPC1FG 5
#define WACOM_PKGLEN_TPC1FG_B 10
#define WACOM_PKGLEN_TPC2FG 14
#define WACOM_PKGLEN_BBTOUCH 20
#define WACOM_PKGLEN_BBTOUCH3 64
#define WACOM_PKGLEN_BBPEN 10
#define WACOM_PKGLEN_WIRELESS 32
#define WACOM_PKGLEN_MTOUCH 62
#define WACOM_PKGLEN_MTTPC 40
#define WACOM_PKGLEN_DTUS 68
#define WACOM_PKGLEN_PENABLED 8
/* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET 11
#define WACOM_BYTES_PER_24HDT_PACKET 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_INTUOS5PAD 3
#define WACOM_REPORT_DTUSPAD 21
#define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13
#define WACOM_REPORT_TPCMT 13
#define WACOM_REPORT_TPCMT2 3
#define WACOM_REPORT_TPCHID 15
#define WACOM_REPORT_TPCST 16
#define WACOM_REPORT_DTUS 17
#define WACOM_REPORT_TPC1FGE 18
#define WACOM_REPORT_24HDT 1
#define WACOM_REPORT_WL 128
#define WACOM_REPORT_USB 192
/* device quirks */
#define WACOM_QUIRK_MULTI_INPUT 0x0001
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
#define WACOM_QUIRK_NO_INPUT 0x0004
#define WACOM_QUIRK_MONITOR 0x0008
enum {
PENPARTNER = 0,
GRAPHIRE,
WACOM_G4,
PTU,
PL,
DTU,
DTUS,
INTUOS,
INTUOS3S,
INTUOS3,
INTUOS3L,
INTUOS4S,
INTUOS4,
INTUOS4L,
INTUOS5S,
INTUOS5,
INTUOS5L,
INTUOSPS,
INTUOSPM,
INTUOSPL,
INTUOSHT,
WACOM_21UX2,
WACOM_22HD,
DTK,
WACOM_24HD,
CINTIQ_HYBRID,
CINTIQ,
WACOM_BEE,
WACOM_13HD,
WACOM_MO,
WIRELESS,
BAMBOO_PT,
WACOM_24HDT,
TABLETPC, /* add new TPC below */
TABLETPCE,
TABLETPC2FG,
MTSCREEN,
MTTPC,
MTTPC_B,
MAX_TYPE
};
struct wacom_features {
const char *name;
int pktlen;
int x_max;
int y_max;
int pressure_max;
int distance_max;
int type;
int x_resolution;
int y_resolution;
int x_min;
int y_min;
int device_type;
int x_phy;
int y_phy;
unsigned char unit;
unsigned char unitExpo;
int x_fuzz;
int y_fuzz;
int pressure_fuzz;
int distance_fuzz;
unsigned quirks;
unsigned touch_max;
int oVid;
int oPid;
};
struct wacom_shared {
bool stylus_in_proximity;
bool touch_down;
/* for wireless device to access USB interfaces */
unsigned touch_max;
int type;
struct input_dev *touch_input;
};
struct wacom_wac {
char name[WACOM_NAME_MAX];
unsigned char *data;
int tool[2];
int id[2];
__u32 serial[2];
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
int pid;
int battery_capacity;
int num_contacts_left;
};
#endif

View file

@ -471,6 +471,18 @@ config TOUCHSCREEN_HP7XX
To compile this driver as a module, choose M here: the
module will be called jornada720_ts.
config TOUCHSCREEN_IPAQ_MICRO
tristate "HP iPAQ Atmel Micro ASIC touchscreen"
depends on MFD_IPAQ_MICRO
help
Say Y here to enable support for the touchscreen attached to
the Atmel Micro peripheral controller on iPAQ h3100/h3600/h3700
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called ipaq-micro-ts.
config TOUCHSCREEN_HTCPEN
tristate "HTC Shift X9500 touchscreen"
depends on ISA
@ -555,18 +567,6 @@ config TOUCHSCREEN_TI_AM335X_TSC
To compile this driver as a module, choose M here: the
module will be called ti_am335x_tsc.
config TOUCHSCREEN_ATMEL_TSADCC
tristate "Atmel Touchscreen Interface"
depends on ARCH_AT91
help
Say Y here if you have a 4-wire touchscreen connected to the
ADC Controller on your Atmel SoC.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called atmel_tsadcc.
config TOUCHSCREEN_UCB1400
tristate "Philips UCB1400 touchscreen"
depends on AC97_BUS

View file

@ -14,7 +14,6 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
@ -47,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o
obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o

View file

@ -1302,8 +1302,10 @@ static int ads7846_probe(struct spi_device *spi)
pdata = dev_get_platdata(&spi->dev);
if (!pdata) {
pdata = ads7846_probe_dt(&spi->dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
if (IS_ERR(pdata)) {
err = PTR_ERR(pdata);
goto err_free_mem;
}
}
ts->model = pdata->model ? : 7846;

File diff suppressed because it is too large Load diff

View file

@ -1,358 +0,0 @@
/*
* Atmel Touch Screen Driver
*
* Copyright (c) 2008 ATMEL
* Copyright (c) 2008 Dan Liang
* Copyright (c) 2008 TimeSys Corporation
* Copyright (c) 2008 Justin Waters
*
* Based on touchscreen code from Atmel Corporation.
*
* 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/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/platform_data/atmel.h>
#include <mach/cpu.h>
/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
#define ATMEL_TSADCC_CR 0x00 /* Control register */
#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/
#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */
#define ATMEL_TSADCC_MR 0x04 /* Mode register */
#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */
#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */
#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */
#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */
#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */
#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */
#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */
#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */
#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0)
#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0)
#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0)
#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0)
#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0)
#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0)
#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0)
#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */
#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */
#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */
#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */
#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */
#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */
#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */
#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */
#define ATMEL_TSADCC_SR 0x1C /* Status register */
#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */
#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */
#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */
#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */
#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */
#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */
#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */
#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */
#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */
#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */
#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */
#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */
#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */
#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */
#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */
#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */
#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */
#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */
#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */
#define ATMEL_TSADCC_XPOS 0x50
#define ATMEL_TSADCC_Z1DAT 0x54
#define ATMEL_TSADCC_Z2DAT 0x58
#define PRESCALER_VAL(x) ((x) >> 8)
#define ADC_DEFAULT_CLOCK 100000
struct atmel_tsadcc {
struct input_dev *input;
char phys[32];
struct clk *clk;
int irq;
unsigned int prev_absx;
unsigned int prev_absy;
unsigned char bufferedmeasure;
};
static void __iomem *tsc_base;
#define atmel_tsadcc_read(reg) __raw_readl(tsc_base + (reg))
#define atmel_tsadcc_write(reg, val) __raw_writel((val), tsc_base + (reg))
static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
{
struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
struct input_dev *input_dev = ts_dev->input;
unsigned int status;
unsigned int reg;
status = atmel_tsadcc_read(ATMEL_TSADCC_SR);
status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR);
if (status & ATMEL_TSADCC_NOCNT) {
/* Contact lost */
reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
atmel_tsadcc_write(ATMEL_TSADCC_IDR,
ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
input_report_key(input_dev, BTN_TOUCH, 0);
ts_dev->bufferedmeasure = 0;
input_sync(input_dev);
} else if (status & ATMEL_TSADCC_PENCNT) {
/* Pen detected */
reg = atmel_tsadcc_read(ATMEL_TSADCC_MR);
reg &= ~ATMEL_TSADCC_PENDBC;
atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT);
atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
atmel_tsadcc_write(ATMEL_TSADCC_IER,
ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16));
} else if (status & ATMEL_TSADCC_EOC(3)) {
/* Conversion finished */
if (ts_dev->bufferedmeasure) {
/* Last measurement is always discarded, since it can
* be erroneous.
* Always report previous measurement */
input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
input_report_key(input_dev, BTN_TOUCH, 1);
input_sync(input_dev);
} else
ts_dev->bufferedmeasure = 1;
/* Now make new measurement */
ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
}
return IRQ_HANDLED;
}
/*
* The functions for inserting/removing us as a module.
*/
static int atmel_tsadcc_probe(struct platform_device *pdev)
{
struct atmel_tsadcc *ts_dev;
struct input_dev *input_dev;
struct resource *res;
struct at91_tsadcc_data *pdata = dev_get_platdata(&pdev->dev);
int err;
unsigned int prsc;
unsigned int reg;
if (!pdata)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no mmio resource defined.\n");
return -ENXIO;
}
/* Allocate memory for device */
ts_dev = kzalloc(sizeof(struct atmel_tsadcc), GFP_KERNEL);
if (!ts_dev) {
dev_err(&pdev->dev, "failed to allocate memory.\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, ts_dev);
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&pdev->dev, "failed to allocate input device.\n");
err = -EBUSY;
goto err_free_mem;
}
ts_dev->irq = platform_get_irq(pdev, 0);
if (ts_dev->irq < 0) {
dev_err(&pdev->dev, "no irq ID is designated.\n");
err = -ENODEV;
goto err_free_dev;
}
if (!request_mem_region(res->start, resource_size(res),
"atmel tsadcc regs")) {
dev_err(&pdev->dev, "resources is unavailable.\n");
err = -EBUSY;
goto err_free_dev;
}
tsc_base = ioremap(res->start, resource_size(res));
if (!tsc_base) {
dev_err(&pdev->dev, "failed to map registers.\n");
err = -ENOMEM;
goto err_release_mem;
}
err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, 0,
pdev->dev.driver->name, ts_dev);
if (err) {
dev_err(&pdev->dev, "failed to allocate irq.\n");
goto err_unmap_regs;
}
ts_dev->clk = clk_get(&pdev->dev, "tsc_clk");
if (IS_ERR(ts_dev->clk)) {
dev_err(&pdev->dev, "failed to get ts_clk\n");
err = PTR_ERR(ts_dev->clk);
goto err_free_irq;
}
ts_dev->input = input_dev;
ts_dev->bufferedmeasure = 0;
snprintf(ts_dev->phys, sizeof(ts_dev->phys),
"%s/input0", dev_name(&pdev->dev));
input_dev->name = "atmel touch screen controller";
input_dev->phys = ts_dev->phys;
input_dev->dev.parent = &pdev->dev;
__set_bit(EV_ABS, input_dev->evbit);
input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
/* clk_enable() always returns 0, no need to check it */
clk_enable(ts_dev->clk);
prsc = clk_get_rate(ts_dev->clk);
dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);
if (!pdata->adc_clock)
pdata->adc_clock = ADC_DEFAULT_CLOCK;
prsc = (prsc / (2 * pdata->adc_clock)) - 1;
/* saturate if this value is too high */
if (cpu_is_at91sam9rl()) {
if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL))
prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL);
} else {
if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL))
prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL);
}
dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */
((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */
(prsc << 8) |
((0x26 << 16) & ATMEL_TSADCC_STARTUP) |
((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST);
atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
atmel_tsadcc_write(ATMEL_TSADCC_TSR,
(pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
atmel_tsadcc_read(ATMEL_TSADCC_SR);
atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
/* All went ok, so register to the input system */
err = input_register_device(input_dev);
if (err)
goto err_fail;
return 0;
err_fail:
clk_disable(ts_dev->clk);
clk_put(ts_dev->clk);
err_free_irq:
free_irq(ts_dev->irq, ts_dev);
err_unmap_regs:
iounmap(tsc_base);
err_release_mem:
release_mem_region(res->start, resource_size(res));
err_free_dev:
input_free_device(input_dev);
err_free_mem:
kfree(ts_dev);
return err;
}
static int atmel_tsadcc_remove(struct platform_device *pdev)
{
struct atmel_tsadcc *ts_dev = platform_get_drvdata(pdev);
struct resource *res;
free_irq(ts_dev->irq, ts_dev);
input_unregister_device(ts_dev->input);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iounmap(tsc_base);
release_mem_region(res->start, resource_size(res));
clk_disable(ts_dev->clk);
clk_put(ts_dev->clk);
kfree(ts_dev);
return 0;
}
static struct platform_driver atmel_tsadcc_driver = {
.probe = atmel_tsadcc_probe,
.remove = atmel_tsadcc_remove,
.driver = {
.name = "atmel_tsadcc",
},
};
module_platform_driver(atmel_tsadcc_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Atmel TouchScreen Driver");
MODULE_AUTHOR("Dan Liang <dan.liang@atmel.com>");

View file

@ -733,8 +733,7 @@ edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
static void
edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
if (tsdata->debug_dir)
debugfs_remove_recursive(tsdata->debug_dir);
debugfs_remove_recursive(tsdata->debug_dir);
kfree(tsdata->raw_buffer);
}

View file

@ -0,0 +1,166 @@
/*
* 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.
*
* h3600 atmel micro companion support, touchscreen subdevice
* Author : Alessandro Gardich <gremlin@gremlin.it>
* Author : Dmitry Artamonow <mad_soft@inbox.ru>
* Author : Linus Walleij <linus.walleij@linaro.org>
*
*/
#include <asm/byteorder.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mfd/ipaq-micro.h>
struct touchscreen_data {
struct input_dev *input;
struct ipaq_micro *micro;
};
static void micro_ts_receive(void *data, int len, unsigned char *msg)
{
struct touchscreen_data *ts = data;
if (len == 4) {
input_report_abs(ts->input, ABS_X,
be16_to_cpup((__be16 *) &msg[2]));
input_report_abs(ts->input, ABS_Y,
be16_to_cpup((__be16 *) &msg[0]));
input_report_key(ts->input, BTN_TOUCH, 1);
input_sync(ts->input);
} else if (len == 0) {
input_report_abs(ts->input, ABS_X, 0);
input_report_abs(ts->input, ABS_Y, 0);
input_report_key(ts->input, BTN_TOUCH, 0);
input_sync(ts->input);
}
}
static void micro_ts_toggle_receive(struct touchscreen_data *ts, bool enable)
{
struct ipaq_micro *micro = ts->micro;
spin_lock_irq(&micro->lock);
if (enable) {
micro->ts = micro_ts_receive;
micro->ts_data = ts;
} else {
micro->ts = NULL;
micro->ts_data = NULL;
}
spin_unlock_irq(&ts->micro->lock);
}
static int micro_ts_open(struct input_dev *input)
{
struct touchscreen_data *ts = input_get_drvdata(input);
micro_ts_toggle_receive(ts, true);
return 0;
}
static void micro_ts_close(struct input_dev *input)
{
struct touchscreen_data *ts = input_get_drvdata(input);
micro_ts_toggle_receive(ts, false);
}
static int micro_ts_probe(struct platform_device *pdev)
{
struct ipaq_micro *micro = dev_get_drvdata(pdev->dev.parent);
struct touchscreen_data *ts;
int error;
ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
ts->micro = micro;
ts->input = devm_input_allocate_device(&pdev->dev);
if (!ts->input) {
dev_err(&pdev->dev, "failed to allocate input device\n");
return -ENOMEM;
}
ts->input->name = "ipaq micro ts";
ts->input->open = micro_ts_open;
ts->input->close = micro_ts_close;
input_set_drvdata(ts->input, ts);
input_set_capability(ts->input, EV_KEY, BTN_TOUCH);
input_set_capability(ts->input, EV_ABS, ABS_X);
input_set_capability(ts->input, EV_ABS, ABS_Y);
input_set_abs_params(ts->input, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(ts->input, ABS_Y, 0, 1023, 0, 0);
error = input_register_device(ts->input);
if (error) {
dev_err(&pdev->dev, "error registering touch input\n");
return error;
}
platform_set_drvdata(pdev, ts);
dev_info(&pdev->dev, "iPAQ micro touchscreen\n");
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int micro_ts_suspend(struct device *dev)
{
struct touchscreen_data *ts = dev_get_drvdata(dev);
micro_ts_toggle_receive(ts, false);
return 0;
}
static int micro_ts_resume(struct device *dev)
{
struct touchscreen_data *ts = dev_get_drvdata(dev);
struct input_dev *input = ts->input;
mutex_lock(&input->mutex);
if (input->users)
micro_ts_toggle_receive(ts, true);
mutex_unlock(&input->mutex);
return 0;
}
#endif
static const struct dev_pm_ops micro_ts_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume)
};
static struct platform_driver micro_ts_device_driver = {
.driver = {
.name = "ipaq-micro-ts",
.pm = &micro_ts_dev_pm_ops,
},
.probe = micro_ts_probe,
};
module_platform_driver(micro_ts_device_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("driver for iPAQ Atmel micro touchscreen");
MODULE_ALIAS("platform:ipaq-micro-ts");

View file

@ -36,22 +36,21 @@ struct jornada_ts {
static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts)
{
/* 3 low word X samples */
jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY);
jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY);
jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY);
/* 3 low word X samples */
jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY);
jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY);
jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY);
/* 3 low word Y samples */
jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY);
jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY);
jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY);
/* 3 low word Y samples */
jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY);
jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY);
jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY);
/* combined x samples bits */
jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY);
/* combined x samples bits */
jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY);
/* combined y samples bits */
jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY);
/* combined y samples bits */
jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY);
}
static int jornada720_ts_average(int coords[4])
@ -104,13 +103,13 @@ static int jornada720_ts_probe(struct platform_device *pdev)
struct input_dev *input_dev;
int error;
jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL);
input_dev = input_allocate_device();
jornada_ts = devm_kzalloc(&pdev->dev, sizeof(*jornada_ts), GFP_KERNEL);
if (!jornada_ts)
return -ENOMEM;
if (!jornada_ts || !input_dev) {
error = -ENOMEM;
goto fail1;
}
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev)
return -ENOMEM;
platform_set_drvdata(pdev, jornada_ts);
@ -126,36 +125,18 @@ static int jornada720_ts_probe(struct platform_device *pdev)
input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
error = request_irq(IRQ_GPIO9,
jornada720_ts_interrupt,
IRQF_TRIGGER_RISING,
"HP7XX Touchscreen driver", pdev);
error = devm_request_irq(&pdev->dev, IRQ_GPIO9,
jornada720_ts_interrupt,
IRQF_TRIGGER_RISING,
"HP7XX Touchscreen driver", pdev);
if (error) {
printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n");
goto fail1;
dev_err(&pdev->dev, "HP7XX TS : Unable to acquire irq!\n");
return error;
}
error = input_register_device(jornada_ts->dev);
if (error)
goto fail2;
return 0;
fail2:
free_irq(IRQ_GPIO9, pdev);
fail1:
input_free_device(input_dev);
kfree(jornada_ts);
return error;
}
static int jornada720_ts_remove(struct platform_device *pdev)
{
struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
free_irq(IRQ_GPIO9, pdev);
input_unregister_device(jornada_ts->dev);
kfree(jornada_ts);
return error;
return 0;
}
@ -165,7 +146,6 @@ MODULE_ALIAS("platform:jornada_ts");
static struct platform_driver jornada720_ts_driver = {
.probe = jornada720_ts_probe,
.remove = jornada720_ts_remove,
.driver = {
.name = "jornada_ts",
.owner = THIS_MODULE,

View file

@ -248,8 +248,7 @@ static int mcs5000_ts_probe(struct i2c_client *client,
return 0;
}
#ifdef CONFIG_PM
static int mcs5000_ts_suspend(struct device *dev)
static int __maybe_unused mcs5000_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@ -259,7 +258,7 @@ static int mcs5000_ts_suspend(struct device *dev)
return 0;
}
static int mcs5000_ts_resume(struct device *dev)
static int __maybe_unused mcs5000_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
@ -269,7 +268,6 @@ static int mcs5000_ts_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);

View file

@ -23,22 +23,51 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/pixcir_ts.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */
struct pixcir_i2c_ts_data {
struct i2c_client *client;
struct input_dev *input;
const struct pixcir_ts_platform_data *chip;
const struct pixcir_ts_platform_data *pdata;
bool running;
int max_fingers; /* Max fingers supported in this instance */
};
static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
struct pixcir_touch {
int x;
int y;
int id;
};
struct pixcir_report_data {
int num_touches;
struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
};
static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
struct pixcir_report_data *report)
{
struct pixcir_i2c_ts_data *tsdata = data;
u8 rdbuf[10], wrbuf[1] = { 0 };
u8 rdbuf[2 + PIXCIR_MAX_SLOTS * 5];
u8 wrbuf[1] = { 0 };
u8 *bufptr;
u8 touch;
int ret;
int ret, i;
int readsize;
const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip;
memset(report, 0, sizeof(struct pixcir_report_data));
i = chip->has_hw_ids ? 1 : 0;
readsize = 2 + tsdata->max_fingers * (4 + i);
if (readsize > sizeof(rdbuf))
readsize = sizeof(rdbuf);
ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
if (ret != sizeof(wrbuf)) {
@ -48,7 +77,7 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
return;
}
ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
ret = i2c_master_recv(tsdata->client, rdbuf, readsize);
if (ret != sizeof(rdbuf)) {
dev_err(&tsdata->client->dev,
"%s: i2c_master_recv failed(), ret=%d\n",
@ -56,45 +85,103 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
return;
}
touch = rdbuf[0];
if (touch) {
u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
touch = rdbuf[0] & 0x7;
if (touch > tsdata->max_fingers)
touch = tsdata->max_fingers;
input_report_key(tsdata->input, BTN_TOUCH, 1);
input_report_abs(tsdata->input, ABS_X, posx1);
input_report_abs(tsdata->input, ABS_Y, posy1);
report->num_touches = touch;
bufptr = &rdbuf[2];
input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
input_mt_sync(tsdata->input);
for (i = 0; i < touch; i++) {
report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
if (touch == 2) {
input_report_abs(tsdata->input,
ABS_MT_POSITION_X, posx2);
input_report_abs(tsdata->input,
ABS_MT_POSITION_Y, posy2);
input_mt_sync(tsdata->input);
if (chip->has_hw_ids) {
report->touches[i].id = bufptr[4];
bufptr = bufptr + 5;
} else {
bufptr = bufptr + 4;
}
} else {
input_report_key(tsdata->input, BTN_TOUCH, 0);
}
}
static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
struct pixcir_report_data *report)
{
struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
int slots[PIXCIR_MAX_SLOTS];
struct pixcir_touch *touch;
int n, i, slot;
struct device *dev = &ts->client->dev;
const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip;
n = report->num_touches;
if (n > PIXCIR_MAX_SLOTS)
n = PIXCIR_MAX_SLOTS;
if (!chip->has_hw_ids) {
for (i = 0; i < n; i++) {
touch = &report->touches[i];
pos[i].x = touch->x;
pos[i].y = touch->y;
}
input_mt_assign_slots(ts->input, slots, pos, n);
}
input_sync(tsdata->input);
for (i = 0; i < n; i++) {
touch = &report->touches[i];
if (chip->has_hw_ids) {
slot = input_mt_get_slot_by_key(ts->input, touch->id);
if (slot < 0) {
dev_dbg(dev, "no free slot for id 0x%x\n",
touch->id);
continue;
}
} else {
slot = slots[i];
}
input_mt_slot(ts->input, slot);
input_mt_report_slot_state(ts->input,
MT_TOOL_FINGER, true);
input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
i, slot, touch->x, touch->y);
}
input_mt_sync_frame(ts->input);
input_sync(ts->input);
}
static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
{
struct pixcir_i2c_ts_data *tsdata = dev_id;
const struct pixcir_ts_platform_data *pdata = tsdata->chip;
const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
struct pixcir_report_data report;
while (tsdata->running) {
pixcir_ts_poscheck(tsdata);
/* parse packet */
pixcir_ts_parse(tsdata, &report);
if (gpio_get_value(pdata->gpio_attb))
/* report it */
pixcir_ts_report(tsdata, &report);
if (gpio_get_value(pdata->gpio_attb)) {
if (report.num_touches) {
/*
* Last report with no finger up?
* Do it now then.
*/
input_mt_sync_frame(tsdata->input);
input_sync(tsdata->input);
}
break;
}
msleep(20);
}
@ -323,16 +410,69 @@ unlock:
static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
#ifdef CONFIG_OF
static const struct of_device_id pixcir_of_match[];
static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
{
struct pixcir_ts_platform_data *pdata;
struct device_node *np = dev->of_node;
const struct of_device_id *match;
match = of_match_device(of_match_ptr(pixcir_of_match), dev);
if (!match)
return ERR_PTR(-EINVAL);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data;
pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
/* gpio_attb validity is checked in probe */
if (of_property_read_u32(np, "touchscreen-size-x", &pdata->x_max)) {
dev_err(dev, "Failed to get touchscreen-size-x property\n");
return ERR_PTR(-EINVAL);
}
pdata->x_max -= 1;
if (of_property_read_u32(np, "touchscreen-size-y", &pdata->y_max)) {
dev_err(dev, "Failed to get touchscreen-size-y property\n");
return ERR_PTR(-EINVAL);
}
pdata->y_max -= 1;
dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__,
pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb);
return pdata;
}
#else
static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
{
return ERR_PTR(-EINVAL);
}
#endif
static int pixcir_i2c_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct pixcir_ts_platform_data *pdata =
dev_get_platdata(&client->dev);
struct device *dev = &client->dev;
struct device_node *np = dev->of_node;
struct pixcir_i2c_ts_data *tsdata;
struct input_dev *input;
int error;
if (np && !pdata) {
pdata = pixcir_parse_dt(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
if (!pdata) {
dev_err(&client->dev, "platform data not defined\n");
return -EINVAL;
@ -343,6 +483,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
return -EINVAL;
}
if (!pdata->chip.max_fingers) {
dev_err(dev, "Invalid max_fingers in pdata\n");
return -EINVAL;
}
tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
if (!tsdata)
return -ENOMEM;
@ -355,7 +500,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
tsdata->client = client;
tsdata->input = input;
tsdata->chip = pdata;
tsdata->pdata = pdata;
input->name = client->name;
input->id.bustype = BUS_I2C;
@ -371,6 +516,20 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
tsdata->max_fingers = tsdata->pdata->chip.max_fingers;
if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) {
tsdata->max_fingers = PIXCIR_MAX_SLOTS;
dev_info(dev, "Limiting maximum fingers to %d\n",
tsdata->max_fingers);
}
error = input_mt_init_slots(input, tsdata->max_fingers,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error) {
dev_err(dev, "Error initializing Multi-Touch slots\n");
return error;
}
input_set_drvdata(input, tsdata);
error = devm_gpio_request_one(dev, pdata->gpio_attb,
@ -419,15 +578,36 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
static const struct i2c_device_id pixcir_i2c_ts_id[] = {
{ "pixcir_ts", 0 },
{ "pixcir_tangoc", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
#ifdef CONFIG_OF
static const struct pixcir_i2c_chip_data pixcir_ts_data = {
.max_fingers = 2,
/* no hw id support */
};
static const struct pixcir_i2c_chip_data pixcir_tangoc_data = {
.max_fingers = 5,
.has_hw_ids = true,
};
static const struct of_device_id pixcir_of_match[] = {
{ .compatible = "pixcir,pixcir_ts", .data = &pixcir_ts_data },
{ .compatible = "pixcir,pixcir_tangoc", .data = &pixcir_tangoc_data },
{ }
};
MODULE_DEVICE_TABLE(of, pixcir_of_match);
#endif
static struct i2c_driver pixcir_i2c_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pixcir_ts",
.pm = &pixcir_dev_pm_ops,
.of_match_table = of_match_ptr(pixcir_of_match),
},
.probe = pixcir_i2c_ts_probe,
.remove = pixcir_i2c_ts_remove,

View file

@ -264,7 +264,7 @@ static int s3c2410ts_probe(struct platform_device *pdev)
return -ENOENT;
}
clk_enable(ts.clock);
clk_prepare_enable(ts.clock);
dev_dbg(dev, "got and enabled clocks\n");
ts.irq_tc = ret = platform_get_irq(pdev, 0);
@ -369,7 +369,7 @@ static int s3c2410ts_remove(struct platform_device *pdev)
free_irq(ts.irq_tc, ts.input);
del_timer_sync(&touch_timer);
clk_disable(ts.clock);
clk_disable_unprepare(ts.clock);
clk_put(ts.clock);
input_unregister_device(ts.input);

View file

@ -29,6 +29,8 @@
#include <linux/sysfs.h>
#include <linux/input/mt.h>
#include <linux/platform_data/zforce_ts.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
@ -117,6 +119,8 @@ struct zforce_ts {
const struct zforce_ts_platdata *pdata;
char phys[32];
struct regulator *reg_vdd;
bool suspending;
bool suspended;
bool boot_complete;
@ -690,6 +694,11 @@ static void zforce_reset(void *data)
struct zforce_ts *ts = data;
gpio_set_value(ts->pdata->gpio_rst, 0);
udelay(10);
if (!IS_ERR(ts->reg_vdd))
regulator_disable(ts->reg_vdd);
}
static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev)
@ -765,10 +774,32 @@ static int zforce_probe(struct i2c_client *client,
return ret;
}
ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd");
if (IS_ERR(ts->reg_vdd)) {
ret = PTR_ERR(ts->reg_vdd);
if (ret == -EPROBE_DEFER)
return ret;
} else {
ret = regulator_enable(ts->reg_vdd);
if (ret)
return ret;
/*
* according to datasheet add 100us grace time after regular
* regulator enable delay.
*/
udelay(100);
}
ret = devm_add_action(&client->dev, zforce_reset, ts);
if (ret) {
dev_err(&client->dev, "failed to register reset action, %d\n",
ret);
/* hereafter the regulator will be disabled by the action */
if (!IS_ERR(ts->reg_vdd))
regulator_disable(ts->reg_vdd);
return ret;
}