Commit 1c5ff2ab authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:
 - new driver for eGalaxTouch serial touchscreen
 - new driver for TS-4800 touchscreen
 - an update for Goodix touchscreen driver
 - PS/2 mouse module was reworked to limit number of protocols we try on
   pass-through ports to speed up their detection time
 - wacom_w8001 touchscreen driver now reports pen and touch via separate
   instances of input devices
 - other driver changes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (42 commits)
  Input: elantech - mark protocols v2 and v3 as semi-mt
  Input: wacom_w8001 - drop use of ABS_MT_TOOL_TYPE
  Input: gpio-keys - fix check for disabling unsupported keys
  Input: omap-keypad - remove dead check
  Input: ti_am335x_tsc - fix HWPEN interrupt handling
  Input: omap-keypad - set tasklet data earlier
  Input: rohm_bu21023 - fix handling of retrying firmware update
  Input: ALPS - report v3 pinnacle trackstick device only if is present
  Input: ALPS - detect trackstick presence for v7 protocol
  Input: pcap_ts - use to_delayed_work
  Input: bma150 - constify bma150_cfg structure
  Input: i8042 - add Fujitsu Lifebook U745 to the nomux list
  Input: egalax_ts_serial - fix potential NULL dereference on error
  Input: uinput - sanity check on ff_effects_max and EV_FF
  Input: uinput - rework ABS validation
  Input: uinput - add new UINPUT_DEV_SETUP and UI_ABS_SETUP ioctl
  Input: goodix - use "inverted_[xy]" flags instead of "rotated_screen"
  Input: goodix - add axis swapping and axis inversion support
  Input: goodix - use goodix_i2c_write_u8 instead of i2c_master_send
  Input: goodix - add power management support
  ...
parents d6a32277 009f7738
...@@ -13,6 +13,17 @@ Required properties: ...@@ -13,6 +13,17 @@ Required properties:
- interrupt-parent : Interrupt controller to which the chip is connected - interrupt-parent : Interrupt controller to which the chip is connected
- interrupts : Interrupt to which the chip is connected - interrupts : Interrupt to which the chip is connected
Optional properties:
- irq-gpios : GPIO pin used for IRQ. The driver uses the
interrupt gpio pin as output to reset the device.
- reset-gpios : GPIO pin used for reset
- touchscreen-inverted-x : X axis is inverted (boolean)
- touchscreen-inverted-y : Y axis is inverted (boolean)
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
(swapping is done after inverting the axis)
Example: Example:
i2c@00000000 { i2c@00000000 {
...@@ -23,6 +34,9 @@ Example: ...@@ -23,6 +34,9 @@ Example:
reg = <0x5d>; reg = <0x5d>;
interrupt-parent = <&gpio>; interrupt-parent = <&gpio>;
interrupts = <0 0>; interrupts = <0 0>;
irq-gpios = <&gpio1 0 0>;
reset-gpios = <&gpio1 1 0>;
}; };
/* ... */ /* ... */
......
...@@ -9,7 +9,9 @@ Required properties: ...@@ -9,7 +9,9 @@ Required properties:
- touchscreen-size-y: vertical resolution of touchscreen (in pixels) - touchscreen-size-y: vertical resolution of touchscreen (in pixels)
Optional properties: Optional properties:
- reset-gpio: GPIO connected to the RESET line of the chip - reset-gpios: GPIO connected to the RESET line of the chip
- enable-gpios: GPIO connected to the ENABLE line of the chip
- wake-gpios: GPIO connected to the WAKE line of the chip
Example: Example:
......
* TS-4800 Touchscreen bindings
Required properties:
- compatible: must be "technologic,ts4800-ts"
- reg: physical base address of the controller and length of memory mapped
region.
- syscon: phandle / integers array that points to the syscon node which
describes the FPGA's syscon registers.
- phandle to FPGA's syscon
- offset to the touchscreen register
- offset to the touchscreen enable bit
...@@ -943,3 +943,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id) ...@@ -943,3 +943,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
} }
return count; return count;
} }
struct acpi_crs_lookup {
struct list_head node;
struct acpi_device *adev;
const char *con_id;
};
static DEFINE_MUTEX(acpi_crs_lookup_lock);
static LIST_HEAD(acpi_crs_lookup_list);
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
{
struct acpi_crs_lookup *l, *lookup = NULL;
/* Never allow fallback if the device has properties */
if (adev->data.properties || adev->driver_gpios)
return false;
mutex_lock(&acpi_crs_lookup_lock);
list_for_each_entry(l, &acpi_crs_lookup_list, node) {
if (l->adev == adev) {
lookup = l;
break;
}
}
if (!lookup) {
lookup = kmalloc(sizeof(*lookup), GFP_KERNEL);
if (lookup) {
lookup->adev = adev;
lookup->con_id = con_id;
list_add_tail(&lookup->node, &acpi_crs_lookup_list);
}
}
mutex_unlock(&acpi_crs_lookup_lock);
return lookup &&
((!lookup->con_id && !con_id) ||
(lookup->con_id && con_id &&
strcmp(lookup->con_id, con_id) == 0));
}
...@@ -1874,6 +1874,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, ...@@ -1874,6 +1874,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
/* Then from plain _CRS GPIOs */ /* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) { if (IS_ERR(desc)) {
if (!acpi_can_fallback_to_crs(adev, con_id))
return ERR_PTR(-ENOENT);
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
if (IS_ERR(desc)) if (IS_ERR(desc))
return desc; return desc;
......
...@@ -48,6 +48,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, ...@@ -48,6 +48,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
struct acpi_gpio_info *info); struct acpi_gpio_info *info);
int acpi_gpio_count(struct device *dev, const char *con_id); int acpi_gpio_count(struct device *dev, const char *con_id);
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
#else #else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
...@@ -74,6 +76,12 @@ static inline int acpi_gpio_count(struct device *dev, const char *con_id) ...@@ -74,6 +76,12 @@ static inline int acpi_gpio_count(struct device *dev, const char *con_id)
{ {
return -ENODEV; return -ENODEV;
} }
static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
const char *con_id)
{
return false;
}
#endif #endif
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
......
...@@ -96,13 +96,29 @@ struct gpio_keys_drvdata { ...@@ -96,13 +96,29 @@ struct gpio_keys_drvdata {
* Return value of this function can be used to allocate bitmap * Return value of this function can be used to allocate bitmap
* large enough to hold all bits for given type. * large enough to hold all bits for given type.
*/ */
static inline int get_n_events_by_type(int type) static int get_n_events_by_type(int type)
{ {
BUG_ON(type != EV_SW && type != EV_KEY); BUG_ON(type != EV_SW && type != EV_KEY);
return (type == EV_KEY) ? KEY_CNT : SW_CNT; return (type == EV_KEY) ? KEY_CNT : SW_CNT;
} }
/**
* get_bm_events_by_type() - returns bitmap of supported events per @type
* @input: input device from which bitmap is retrieved
* @type: type of button (%EV_KEY, %EV_SW)
*
* Return value of this function can be used to allocate bitmap
* large enough to hold all bits for given type.
*/
static const unsigned long *get_bm_events_by_type(struct input_dev *dev,
int type)
{
BUG_ON(type != EV_SW && type != EV_KEY);
return (type == EV_KEY) ? dev->keybit : dev->swbit;
}
/** /**
* gpio_keys_disable_button() - disables given GPIO button * gpio_keys_disable_button() - disables given GPIO button
* @bdata: button data for button to be disabled * @bdata: button data for button to be disabled
...@@ -213,6 +229,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ...@@ -213,6 +229,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
const char *buf, unsigned int type) const char *buf, unsigned int type)
{ {
int n_events = get_n_events_by_type(type); int n_events = get_n_events_by_type(type);
const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
unsigned long *bits; unsigned long *bits;
ssize_t error; ssize_t error;
int i; int i;
...@@ -226,6 +243,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ...@@ -226,6 +243,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
goto out; goto out;
/* First validate */ /* First validate */
if (!bitmap_subset(bits, bitmap, n_events)) {
error = -EINVAL;
goto out;
}
for (i = 0; i < ddata->pdata->nbuttons; i++) { for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i]; struct gpio_button_data *bdata = &ddata->data[i];
...@@ -239,11 +261,6 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ...@@ -239,11 +261,6 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
} }
} }
if (i == ddata->pdata->nbuttons) {
error = -EINVAL;
goto out;
}
mutex_lock(&ddata->disable_lock); mutex_lock(&ddata->disable_lock);
for (i = 0; i < ddata->pdata->nbuttons; i++) { for (i = 0; i < ddata->pdata->nbuttons; i++) {
......
...@@ -155,14 +155,6 @@ static void omap_kp_tasklet(unsigned long data) ...@@ -155,14 +155,6 @@ static void omap_kp_tasklet(unsigned long data)
"pressed" : "released"); "pressed" : "released");
#else #else
key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)]; key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)];
if (key < 0) {
printk(KERN_WARNING
"omap-keypad: Spurious key event %d-%d\n",
col, row);
/* We scan again after a couple of seconds */
spurious = 1;
continue;
}
if (!(kp_cur_group == (key & GROUP_MASK) || if (!(kp_cur_group == (key & GROUP_MASK) ||
kp_cur_group == -1)) kp_cur_group == -1))
...@@ -292,8 +284,8 @@ static int omap_kp_probe(struct platform_device *pdev) ...@@ -292,8 +284,8 @@ static int omap_kp_probe(struct platform_device *pdev)
setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp); setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
/* get the irq and init timer*/ /* get the irq and init timer*/
tasklet_enable(&kp_tasklet);
kp_tasklet.data = (unsigned long) omap_kp; kp_tasklet.data = (unsigned long) omap_kp;
tasklet_enable(&kp_tasklet);
ret = device_create_file(&pdev->dev, &dev_attr_enable); ret = device_create_file(&pdev->dev, &dev_attr_enable);
if (ret < 0) if (ret < 0)
......
...@@ -147,7 +147,7 @@ struct bma150_data { ...@@ -147,7 +147,7 @@ struct bma150_data {
* are stated and verified by Bosch Sensortec where they are configured * are stated and verified by Bosch Sensortec where they are configured
* to provide a generic sensitivity performance. * to provide a generic sensitivity performance.
*/ */
static struct bma150_cfg default_cfg = { static const struct bma150_cfg default_cfg = {
.any_motion_int = 1, .any_motion_int = 1,
.hg_int = 1, .hg_int = 1,
.lg_int = 1, .lg_int = 1,
......
...@@ -179,13 +179,13 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data) ...@@ -179,13 +179,13 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
input_report_key(onkey->input, KEY_POWER, 1); input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input); input_sync(onkey->input);
schedule_delayed_work(&onkey->work, 0); schedule_delayed_work(&onkey->work, 0);
dev_dbg(onkey->dev, "KEY_POWER pressed.\n"); dev_dbg(onkey->dev, "KEY_POWER long press.\n");
} else { } else {
input_report_key(onkey->input, KEY_SLEEP, 1); input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input); input_sync(onkey->input);
input_report_key(onkey->input, KEY_SLEEP, 0); input_report_key(onkey->input, KEY_POWER, 0);
input_sync(onkey->input); input_sync(onkey->input);
dev_dbg(onkey->dev, "KEY_SLEEP pressed.\n"); dev_dbg(onkey->dev, "KEY_POWER short press.\n");
} }
return IRQ_HANDLED; return IRQ_HANDLED;
......
...@@ -345,23 +345,19 @@ static struct platform_driver grover_beep_driver = { ...@@ -345,23 +345,19 @@ static struct platform_driver grover_beep_driver = {
.shutdown = sparcspkr_shutdown, .shutdown = sparcspkr_shutdown,
}; };
static struct platform_driver * const drivers[] = {
&bbc_beep_driver,
&grover_beep_driver,
};
static int __init sparcspkr_init(void) static int __init sparcspkr_init(void)
{ {
int err = platform_driver_register(&bbc_beep_driver); return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
if (!err) {
err = platform_driver_register(&grover_beep_driver);
if (err)
platform_driver_unregister(&bbc_beep_driver);
}
return err;
} }
static void __exit sparcspkr_exit(void) static void __exit sparcspkr_exit(void)
{ {
platform_driver_unregister(&bbc_beep_driver); platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
platform_driver_unregister(&grover_beep_driver);
} }
module_init(sparcspkr_init); module_init(sparcspkr_init);
......
...@@ -256,13 +256,29 @@ static void uinput_destroy_device(struct uinput_device *udev) ...@@ -256,13 +256,29 @@ static void uinput_destroy_device(struct uinput_device *udev)
static int uinput_create_device(struct uinput_device *udev) static int uinput_create_device(struct uinput_device *udev)
{ {
struct input_dev *dev = udev->dev; struct input_dev *dev = udev->dev;
int error; int error, nslot;
if (udev->state != UIST_SETUP_COMPLETE) { if (udev->state != UIST_SETUP_COMPLETE) {
printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
return -EINVAL; return -EINVAL;
} }
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
error = input_mt_init_slots(dev, nslot, 0);
if (error)
goto fail1;
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
}
if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {
printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n",
UINPUT_NAME);
error = -EINVAL;
goto fail1;
}
if (udev->ff_effects_max) { if (udev->ff_effects_max) {
error = input_ff_create(dev, udev->ff_effects_max); error = input_ff_create(dev, udev->ff_effects_max);
if (error) if (error)
...@@ -308,51 +324,50 @@ static int uinput_open(struct inode *inode, struct file *file) ...@@ -308,51 +324,50 @@ static int uinput_open(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int uinput_validate_absbits(struct input_dev *dev) static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
const struct input_absinfo *abs)
{ {
unsigned int cnt;
int nslot;
if (!test_bit(EV_ABS, dev->evbit))
return 0;
/*
* Check if absmin/absmax/absfuzz/absflat are sane.
*/
for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
int min, max; int min, max;
min = input_abs_get_min(dev, cnt); min = abs->minimum;
max = input_abs_get_max(dev, cnt); max = abs->maximum;
if ((min != 0 || max != 0) && max <= min) { if ((min != 0 || max != 0) && max <= min) {
printk(KERN_DEBUG printk(KERN_DEBUG
"%s: invalid abs[%02x] min:%d max:%d\n", "%s: invalid abs[%02x] min:%d max:%d\n",
UINPUT_NAME, cnt, UINPUT_NAME, code, min, max);
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
return -EINVAL; return -EINVAL;
} }
if (input_abs_get_flat(dev, cnt) > if (abs->flat > max - min) {
input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) {
printk(KERN_DEBUG printk(KERN_DEBUG
"%s: abs_flat #%02x out of range: %d " "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
"(min:%d/max:%d)\n", UINPUT_NAME, code, abs->flat, min, max);
UINPUT_NAME, cnt,
input_abs_get_flat(dev, cnt),
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
return -EINVAL; return -EINVAL;
} }
}
if (test_bit(ABS_MT_SLOT, dev->absbit)) { return 0;
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)) { static int uinput_validate_absbits(struct input_dev *dev)
input_set_events_per_packet(dev, 60); {
unsigned int cnt;
int error;
if (!test_bit(EV_ABS, dev->evbit))
return 0;
/*
* Check if absmin/absmax/absfuzz/absflat are sane.
*/
for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
if (!dev->absinfo)
return -EINVAL;
error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
if (error)
return error;
} }
return 0; return 0;
...@@ -370,7 +385,70 @@ static int uinput_allocate_device(struct uinput_device *udev) ...@@ -370,7 +385,70 @@ static int uinput_allocate_device(struct uinput_device *udev)
return 0; return 0;
} }
static int uinput_setup_device(struct uinput_device *udev, static int uinput_dev_setup(struct uinput_device *udev,
struct uinput_setup __user *arg)
{
struct uinput_setup setup;
struct input_dev *dev;
if (udev->state == UIST_CREATED)
return -EINVAL;
if (copy_from_user(&setup, arg, sizeof(setup)))
return -EFAULT;
if (!setup.name[0])
return -EINVAL;
dev = udev->dev;
dev->id = setup.id;
udev->ff_effects_max = setup.ff_effects_max;
kfree(dev->name);
dev->name = kstrndup(setup.name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL);
if (!dev->name)
return -ENOMEM;
udev->state = UIST_SETUP_COMPLETE;
return 0;
}
static int uinput_abs_setup(struct uinput_device *udev,
struct uinput_setup __user *arg, size_t size)
{
struct uinput_abs_setup setup = {};
struct input_dev *dev;
int error;
if (size > sizeof(setup))
return -E2BIG;
if (udev->state == UIST_CREATED)
return -EINVAL;
if (copy_from_user(&setup, arg, size))
return -EFAULT;
if (setup.code > ABS_MAX)
return -ERANGE;
dev = udev->dev;
error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);
if (error)
return error;
input_alloc_absinfo(dev);
if (!dev->absinfo)
return -ENOMEM;
set_bit(setup.code, dev->absbit);
dev->absinfo[setup.code] = setup.absinfo;
return 0;
}
/* legacy setup via write() */
static int uinput_setup_device_legacy(struct uinput_device *udev,
const char __user *buffer, size_t count) const char __user *buffer, size_t count)
{ {
struct uinput_user_dev *user_dev; struct uinput_user_dev *user_dev;
...@@ -474,7 +552,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, ...@@ -474,7 +552,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer,
retval = udev->state == UIST_CREATED ? retval = udev->state == UIST_CREATED ?
uinput_inject_events(udev, buffer, count) : uinput_inject_events(udev, buffer, count) :
uinput_setup_device(udev, buffer, count); uinput_setup_device_legacy(udev, buffer, count);
mutex_unlock(&udev->mutex); mutex_unlock(&udev->mutex);
...@@ -735,6 +813,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, ...@@ -735,6 +813,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
uinput_destroy_device(udev); uinput_destroy_device(udev);
goto out; goto out;
case UI_DEV_SETUP:
retval = uinput_dev_setup(udev, p);
goto out;
/* UI_ABS_SETUP is handled in the variable size ioctls */
case UI_SET_EVBIT: case UI_SET_EVBIT:
retval = uinput_set_bit(arg, evbit, EV_MAX); retval = uinput_set_bit(arg, evbit, EV_MAX);
goto out; goto out;
...@@ -879,6 +963,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, ...@@ -879,6 +963,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
name = dev_name(&udev->dev->dev); name = dev_name(&udev->dev->dev);
retval = uinput_str_to_user(p, name, size); retval = uinput_str_to_user(p, name, size);
goto out; goto out;
case UI_ABS_SETUP & ~IOCSIZE_MASK:
retval = uinput_abs_setup(udev, p, size);
goto out;
} }
retval = -EINVAL; retval = -EINVAL;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define ALPS_CMD_NIBBLE_10 0x01f2 #define ALPS_CMD_NIBBLE_10 0x01f2
#define ALPS_REG_BASE_RUSHMORE 0xc2c0 #define ALPS_REG_BASE_RUSHMORE 0xc2c0
#define ALPS_REG_BASE_V7 0xc2c0
#define ALPS_REG_BASE_PINNACLE 0x0000 #define ALPS_REG_BASE_PINNACLE 0x0000
static const struct alps_nibble_commands alps_v3_nibble_commands[] = { static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
...@@ -2047,7 +2048,7 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse) ...@@ -2047,7 +2048,7 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse)
return 0; return 0;
} }
static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base) static int alps_probe_trackstick_v3_v7(struct psmouse *psmouse, int reg_base)
{ {
int ret = -EIO, reg_val; int ret = -EIO, reg_val;
...@@ -2128,15 +2129,12 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base) ...@@ -2128,15 +2129,12 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
static int alps_hw_init_v3(struct psmouse *psmouse) static int alps_hw_init_v3(struct psmouse *psmouse)
{ {
struct alps_data *priv = psmouse->private;
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
int reg_val; int reg_val;
unsigned char param[4]; unsigned char param[4];
reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE); if ((priv->flags & ALPS_DUALPOINT) &&
if (reg_val == -EIO)
goto error;
if (reg_val == 0 &&
alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO) alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
goto error; goto error;
...@@ -2613,6 +2611,11 @@ static int alps_set_protocol(struct psmouse *psmouse, ...@@ -2613,6 +2611,11 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->decode_fields = alps_decode_pinnacle; priv->decode_fields = alps_decode_pinnacle;
priv->nibble_commands = alps_v3_nibble_commands; priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP; priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
if (alps_probe_trackstick_v3_v7(psmouse,
ALPS_REG_BASE_PINNACLE) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break; break;
case ALPS_PROTO_V3_RUSHMORE: case ALPS_PROTO_V3_RUSHMORE:
...@@ -2625,7 +2628,7 @@ static int alps_set_protocol(struct psmouse *psmouse, ...@@ -2625,7 +2628,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->x_bits = 16; priv->x_bits = 16;
priv->y_bits = 12; priv->y_bits = 12;
if (alps_probe_trackstick_v3(psmouse, if (alps_probe_trackstick_v3_v7(psmouse,
ALPS_REG_BASE_RUSHMORE) < 0) ALPS_REG_BASE_RUSHMORE) < 0)
priv->flags &= ~ALPS_DUALPOINT; priv->flags &= ~ALPS_DUALPOINT;
...@@ -2676,6 +2679,9 @@ static int alps_set_protocol(struct psmouse *psmouse, ...@@ -2676,6 +2679,9 @@ static int alps_set_protocol(struct psmouse *psmouse,
if (priv->fw_ver[1] != 0xba) if (priv->fw_ver[1] != 0xba)
priv->flags |= ALPS_BUTTONPAD; priv->flags |= ALPS_BUTTONPAD;
if (alps_probe_trackstick_v3_v7(psmouse, ALPS_REG_BASE_V7) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break; break;
case ALPS_PROTO_V8: case ALPS_PROTO_V8:
......
...@@ -1222,7 +1222,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) ...@@ -1222,7 +1222,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
ETP_WMAX_V2, 0, 0); ETP_WMAX_V2, 0, 0);
} }
input_mt_init_slots(dev, 2, 0); input_mt_init_slots(dev, 2, INPUT_MT_SEMI_MT);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
break; break;
......
...@@ -49,12 +49,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties) ...@@ -49,12 +49,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties)
return 0; return 0;
} }
static void focaltech_reset(struct psmouse *psmouse)
{
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
}
#ifdef CONFIG_MOUSE_PS2_FOCALTECH #ifdef CONFIG_MOUSE_PS2_FOCALTECH
/* /*
...@@ -300,6 +294,12 @@ static int focaltech_switch_protocol(struct psmouse *psmouse) ...@@ -300,6 +294,12 @@ static int focaltech_switch_protocol(struct psmouse *psmouse)
return 0; return 0;
} }
static void focaltech_reset(struct psmouse *psmouse)
{
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
}
static void focaltech_disconnect(struct psmouse *psmouse) static void focaltech_disconnect(struct psmouse *psmouse)
{ {
focaltech_reset(psmouse); focaltech_reset(psmouse);
...@@ -456,14 +456,4 @@ int focaltech_init(struct psmouse *psmouse) ...@@ -456,14 +456,4 @@ int focaltech_init(struct psmouse *psmouse)
kfree(priv); kfree(priv);
return error; return error;
} }
#else /* CONFIG_MOUSE_PS2_FOCALTECH */
int focaltech_init(struct psmouse *psmouse)
{
focaltech_reset(psmouse);
return 0;
}
#endif /* CONFIG_MOUSE_PS2_FOCALTECH */ #endif /* CONFIG_MOUSE_PS2_FOCALTECH */
...@@ -18,6 +18,14 @@ ...@@ -18,6 +18,14 @@
#define _FOCALTECH_H #define _FOCALTECH_H
int focaltech_detect(struct psmouse *psmouse, bool set_properties); int focaltech_detect(struct psmouse *psmouse, bool set_properties);
#ifdef CONFIG_MOUSE_PS2_FOCALTECH
int focaltech_init(struct psmouse *psmouse); int focaltech_init(struct psmouse *psmouse);
#else
static inline int focaltech_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
#endif
#endif #endif
...@@ -325,7 +325,7 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, ...@@ -325,7 +325,7 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
* that support it. * that support it.
*/ */
int ps2pp_init(struct psmouse *psmouse, bool set_properties) int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4]; unsigned char param[4];
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
#define _LOGIPS2PP_H #define _LOGIPS2PP_H
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
int ps2pp_init(struct psmouse *psmouse, bool set_properties); int ps2pp_detect(struct psmouse *psmouse, bool set_properties);
#else #else
inline int ps2pp_init(struct psmouse *psmouse, bool set_properties) static inline int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{ {
return -ENOSYS; return -ENOSYS;
} }
......
...@@ -119,6 +119,7 @@ struct psmouse_protocol { ...@@ -119,6 +119,7 @@ struct psmouse_protocol {
enum psmouse_type type; enum psmouse_type type;
bool maxproto; bool maxproto;
bool ignore_parity; /* Protocol should ignore parity errors from KBC */ bool ignore_parity; /* Protocol should ignore parity errors from KBC */
bool try_passthru; /* Try protocol also on passthrough ports */
const char *name; const char *name;
const char *alias; const char *alias;
int (*detect)(struct psmouse *, bool); int (*detect)(struct psmouse *, bool);
...@@ -129,7 +130,6 @@ struct psmouse_protocol { ...@@ -129,7 +130,6 @@ struct psmouse_protocol {
* psmouse_process_byte() analyzes the PS/2 data stream and reports * psmouse_process_byte() analyzes the PS/2 data stream and reports
* relevant events to the input module once full packet has arrived. * relevant events to the input module once full packet has arrived.
*/ */
psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
{ {
struct input_dev *dev = psmouse->dev; struct input_dev *dev = psmouse->dev;
...@@ -138,22 +138,16 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) ...@@ -138,22 +138,16 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
if (psmouse->pktcnt < psmouse->pktsize) if (psmouse->pktcnt < psmouse->pktsize)
return PSMOUSE_GOOD_DATA; return PSMOUSE_GOOD_DATA;
/* /* Full packet accumulated, process it */
* Full packet accumulated, process it
*/
/*
* Scroll wheel on IntelliMice, scroll buttons on NetMice
*/
if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS) switch (psmouse->type) {
case PSMOUSE_IMPS:
/* IntelliMouse has scroll wheel */
input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
break;
/* case PSMOUSE_IMEX:
* Scroll wheel and buttons on IntelliMouse Explorer /* Scroll wheel and buttons on IntelliMouse Explorer */
*/
if (psmouse->type == PSMOUSE_IMEX) {
switch (packet[3] & 0xC0) { switch (packet[3] & 0xC0) {
case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */ case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
...@@ -168,39 +162,42 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) ...@@ -168,39 +162,42 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
break; break;
} }
} break;
/* case PSMOUSE_GENPS:
* Extra buttons on Genius NewNet 3D /* Report scroll buttons on NetMice */
*/ input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
if (psmouse->type == PSMOUSE_GENPS) { /* Extra buttons on Genius NewNet 3D */
input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1); input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1); input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
} break;
/* case PSMOUSE_THINKPS:
* Extra button on ThinkingMouse /* Extra button on ThinkingMouse */
*/
if (psmouse->type == PSMOUSE_THINKPS) {
input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1); input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1);
/* Without this bit of weirdness moving up gives wildly high Y changes. */
/*
* Without this bit of weirdness moving up gives wildly
* high Y changes.
*/
packet[1] |= (packet[0] & 0x40) << 1; packet[1] |= (packet[0] & 0x40) << 1;
} break;
/* case PSMOUSE_CORTRON:
* Cortron PS2 Trackball reports SIDE button on the 4th bit of the first /*
* byte. * Cortron PS2 Trackball reports SIDE button in the
* 4th bit of the first byte.
*/ */
if (psmouse->type == PSMOUSE_CORTRON) {
input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1); input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1);
packet[0] |= 0x08; packet[0] |= 0x08;
} break;
/* default:
* Generic PS/2 Mouse break;
*/ }
/* Generic PS/2 Mouse */
input_report_key(dev, BTN_LEFT, packet[0] & 1); input_report_key(dev, BTN_LEFT, packet[0] & 1);
input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
...@@ -222,7 +219,6 @@ void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, ...@@ -222,7 +219,6 @@ void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
/* /*
* __psmouse_set_state() sets new psmouse state and resets all flags. * __psmouse_set_state() sets new psmouse state and resets all flags.
*/ */
static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
{ {
psmouse->state = new_state; psmouse->state = new_state;
...@@ -231,13 +227,11 @@ static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_sta ...@@ -231,13 +227,11 @@ static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_sta
psmouse->last = jiffies; psmouse->last = jiffies;
} }
/* /*
* psmouse_set_state() sets new psmouse state and resets all flags and * psmouse_set_state() sets new psmouse state and resets all flags and
* counters while holding serio lock so fighting with interrupt handler * counters while holding serio lock so fighting with interrupt handler
* is not a concern. * is not a concern.
*/ */
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
{ {
serio_pause_rx(psmouse->ps2dev.serio); serio_pause_rx(psmouse->ps2dev.serio);
...@@ -249,7 +243,6 @@ void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) ...@@ -249,7 +243,6 @@ void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
* psmouse_handle_byte() processes one byte of the input data stream * psmouse_handle_byte() processes one byte of the input data stream
* by calling corresponding protocol handler. * by calling corresponding protocol handler.
*/ */
static int psmouse_handle_byte(struct psmouse *psmouse) static int psmouse_handle_byte(struct psmouse *psmouse)
{ {
psmouse_ret_t rc = psmouse->protocol_handler(psmouse); psmouse_ret_t rc = psmouse->protocol_handler(psmouse);
...@@ -292,7 +285,6 @@ static int psmouse_handle_byte(struct psmouse *psmouse) ...@@ -292,7 +285,6 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
* psmouse_interrupt() handles incoming characters, either passing them * psmouse_interrupt() handles incoming characters, either passing them
* for normal processing or gathering them as command response. * for normal processing or gathering them as command response.
*/ */
static irqreturn_t psmouse_interrupt(struct serio *serio, static irqreturn_t psmouse_interrupt(struct serio *serio,
unsigned char data, unsigned int flags) unsigned char data, unsigned int flags)
{ {
...@@ -335,9 +327,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -335,9 +327,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
} }
psmouse->packet[psmouse->pktcnt++] = data; psmouse->packet[psmouse->pktcnt++] = data;
/*
* Check if this is a new device announcement (0xAA 0x00) /* Check if this is a new device announcement (0xAA 0x00) */
*/
if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) {
if (psmouse->pktcnt == 1) { if (psmouse->pktcnt == 1) {
psmouse->last = jiffies; psmouse->last = jiffies;
...@@ -351,9 +342,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -351,9 +342,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
serio_reconnect(serio); serio_reconnect(serio);
goto out; goto out;
} }
/*
* Not a new device, try processing first byte normally /* Not a new device, try processing first byte normally */
*/
psmouse->pktcnt = 1; psmouse->pktcnt = 1;
if (psmouse_handle_byte(psmouse)) if (psmouse_handle_byte(psmouse))
goto out; goto out;
...@@ -361,8 +351,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -361,8 +351,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
psmouse->packet[psmouse->pktcnt++] = data; psmouse->packet[psmouse->pktcnt++] = data;
} }
/* /*
* See if we need to force resync because mouse was idle for too long * See if we need to force resync because mouse was idle for
* too long.
*/ */
if (psmouse->state == PSMOUSE_ACTIVATED && if (psmouse->state == PSMOUSE_ACTIVATED &&
psmouse->pktcnt == 1 && psmouse->resync_time && psmouse->pktcnt == 1 && psmouse->resync_time &&
...@@ -380,7 +371,6 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -380,7 +371,6 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/* /*
* psmouse_sliced_command() sends an extended PS/2 command to the mouse * psmouse_sliced_command() sends an extended PS/2 command to the mouse
* using sliced syntax, understood by advanced devices, such as Logitech * using sliced syntax, understood by advanced devices, such as Logitech
...@@ -404,7 +394,6 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command) ...@@ -404,7 +394,6 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
return 0; return 0;
} }
/* /*
* psmouse_reset() resets the mouse into power-on state. * psmouse_reset() resets the mouse into power-on state.
*/ */
...@@ -424,7 +413,6 @@ int psmouse_reset(struct psmouse *psmouse) ...@@ -424,7 +413,6 @@ int psmouse_reset(struct psmouse *psmouse)
/* /*
* Here we set the mouse resolution. * Here we set the mouse resolution.
*/ */
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{ {
static const unsigned char params[] = { 0, 1, 2, 2, 3 }; static const unsigned char params[] = { 0, 1, 2, 2, 3 };
...@@ -441,7 +429,6 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) ...@@ -441,7 +429,6 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
/* /*
* Here we set the mouse report rate. * Here we set the mouse report rate.
*/ */
static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
{ {
static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
...@@ -457,7 +444,6 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) ...@@ -457,7 +444,6 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
/* /*
* Here we set the mouse scaling. * Here we set the mouse scaling.
*/ */
static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale) static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
{ {
ps2_command(&psmouse->ps2dev, NULL, ps2_command(&psmouse->ps2dev, NULL,
...@@ -468,7 +454,6 @@ static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale) ...@@ -468,7 +454,6 @@ static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
/* /*
* psmouse_poll() - default poll handler. Everyone except for ALPS uses it. * psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
*/ */
static int psmouse_poll(struct psmouse *psmouse) static int psmouse_poll(struct psmouse *psmouse)
{ {
return ps2_command(&psmouse->ps2dev, psmouse->packet, return ps2_command(&psmouse->ps2dev, psmouse->packet,
...@@ -602,7 +587,7 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) ...@@ -602,7 +587,7 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
if (param[0] != 4) if (param[0] != 4)
return -1; return -1;
/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */ /* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
param[0] = 200; param[0] = 200;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 80; param[0] = 80;
...@@ -672,7 +657,7 @@ static int ps2bare_detect(struct psmouse *psmouse, bool set_properties) ...@@ -672,7 +657,7 @@ static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
if (!psmouse->name) if (!psmouse->name)
psmouse->name = "Mouse"; psmouse->name = "Mouse";
/* /*
* We have no way of figuring true number of buttons so let's * We have no way of figuring true number of buttons so let's
* assume that the device has 3. * assume that the device has 3.
*/ */
...@@ -699,284 +684,6 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties) ...@@ -699,284 +684,6 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties)
return 0; return 0;
} }
/*
* Apply default settings to the psmouse structure. Most of them will
* be overridden by individual protocol initialization routines.
*/
static void psmouse_apply_defaults(struct psmouse *psmouse)
{
struct input_dev *input_dev = psmouse->dev;
memset(input_dev->evbit, 0, sizeof(input_dev->evbit));
memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
memset(input_dev->relbit, 0, sizeof(input_dev->relbit));
memset(input_dev->absbit, 0, sizeof(input_dev->absbit));
memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit));
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_REL, input_dev->evbit);
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_RIGHT, input_dev->keybit);
__set_bit(REL_X, input_dev->relbit);
__set_bit(REL_Y, input_dev->relbit);
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
psmouse->set_rate = psmouse_set_rate;
psmouse->set_resolution = psmouse_set_resolution;
psmouse->set_scale = psmouse_set_scale;
psmouse->poll = psmouse_poll;
psmouse->protocol_handler = psmouse_process_byte;
psmouse->pktsize = 3;
psmouse->reconnect = NULL;
psmouse->disconnect = NULL;
psmouse->cleanup = NULL;
psmouse->pt_activate = NULL;
psmouse->pt_deactivate = NULL;
}
/*
* Apply default settings to the psmouse structure and call specified
* protocol detection or initialization routine.
*/
static int psmouse_do_detect(int (*detect)(struct psmouse *psmouse,
bool set_properties),
struct psmouse *psmouse, bool set_properties)
{
if (set_properties)
psmouse_apply_defaults(psmouse);
return detect(psmouse, set_properties);
}
/*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol
* the mouse may have.
*/
static int psmouse_extensions(struct psmouse *psmouse,
unsigned int max_proto, bool set_properties)
{
bool synaptics_hardware = false;
/* Always check for focaltech, this is safe as it uses pnp-id matching */
if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) {
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || focaltech_init(psmouse) == 0) {
if (IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH))
return PSMOUSE_FOCALTECH;
/*
* Note that we need to also restrict
* psmouse_max_proto so that psmouse_initialize()
* does not try to reset rate and resolution,
* because even that upsets the device.
*/
psmouse_max_proto = PSMOUSE_PS2;
return PSMOUSE_PS2;
}
}
}
/*
* We always check for lifebook because it does not disturb mouse
* (it only checks DMI information).
*/
if (psmouse_do_detect(lifebook_detect, psmouse, set_properties) == 0) {
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || lifebook_init(psmouse) == 0)
return PSMOUSE_LIFEBOOK;
}
}
if (psmouse_do_detect(vmmouse_detect, psmouse, set_properties) == 0) {
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || vmmouse_init(psmouse) == 0)
return PSMOUSE_VMMOUSE;
}
}
/*
* Try Kensington ThinkingMouse (we try first, because synaptics probe
* upsets the thinkingmouse).
*/
if (max_proto > PSMOUSE_IMEX &&
psmouse_do_detect(thinking_detect, psmouse, set_properties) == 0) {
return PSMOUSE_THINKPS;
}
/*
* Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol
* support is disabled in config - we need to know if it is synaptics so we
* can reset it properly after probing for intellimouse.
*/
if (max_proto > PSMOUSE_PS2 &&
psmouse_do_detect(synaptics_detect, psmouse, set_properties) == 0) {
synaptics_hardware = true;
if (max_proto > PSMOUSE_IMEX) {
/*
* Try activating protocol, but check if support is enabled first, since
* we try detecting Synaptics even when protocol is disabled.
*/
if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) &&
(!set_properties || synaptics_init(psmouse) == 0)) {
return PSMOUSE_SYNAPTICS;
}
/*
* Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
* Unfortunately Logitech/Genius probes confuse some firmware versions so
* we'll have to skip them.
*/
max_proto = PSMOUSE_IMEX;
}
/*
* Make sure that touchpad is in relative mode, gestures (taps) are enabled
*/
synaptics_reset(psmouse);
}
/*
* Try Cypress Trackpad.
* Must try it before Finger Sensing Pad because Finger Sensing Pad probe
* upsets some modules of Cypress Trackpads.
*/
if (max_proto > PSMOUSE_IMEX &&
cypress_detect(psmouse, set_properties) == 0) {
if (IS_ENABLED(CONFIG_MOUSE_PS2_CYPRESS)) {
if (cypress_init(psmouse) == 0)
return PSMOUSE_CYPRESS;
/*
* Finger Sensing Pad probe upsets some modules of
* Cypress Trackpad, must avoid Finger Sensing Pad
* probe if Cypress Trackpad device detected.
*/
return PSMOUSE_PS2;
}
max_proto = PSMOUSE_IMEX;
}
/*
* Try ALPS TouchPad
*/
if (max_proto > PSMOUSE_IMEX) {
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
if (psmouse_do_detect(alps_detect,
psmouse, set_properties) == 0) {
if (!set_properties || alps_init(psmouse) == 0)
return PSMOUSE_ALPS;
/*
* Init failed, try basic relative protocols
*/
max_proto = PSMOUSE_IMEX;
}
}
/*
* Try OLPC HGPK touchpad.
*/
if (max_proto > PSMOUSE_IMEX &&
psmouse_do_detect(hgpk_detect, psmouse, set_properties) == 0) {
if (!set_properties || hgpk_init(psmouse) == 0)
return PSMOUSE_HGPK;
/*
* Init failed, try basic relative protocols
*/
max_proto = PSMOUSE_IMEX;
}
/*
* Try Elantech touchpad.
*/
if (max_proto > PSMOUSE_IMEX &&
psmouse_do_detect(elantech_detect, psmouse, set_properties) == 0) {
if (!set_properties || elantech_init(psmouse) == 0)
return PSMOUSE_ELANTECH;
/*
* Init failed, try basic relative protocols
*/
max_proto = PSMOUSE_IMEX;
}
if (max_proto > PSMOUSE_IMEX) {
if (psmouse_do_detect(genius_detect,
psmouse, set_properties) == 0)
return PSMOUSE_GENPS;
if (psmouse_do_detect(ps2pp_init,
psmouse, set_properties) == 0)
return PSMOUSE_PS2PP;
if (psmouse_do_detect(trackpoint_detect,
psmouse, set_properties) == 0)
return PSMOUSE_TRACKPOINT;
if (psmouse_do_detect(touchkit_ps2_detect,
psmouse, set_properties) == 0)
return PSMOUSE_TOUCHKIT_PS2;
}
/*
* Try Finger Sensing Pad. We do it here because its probe upsets
* Trackpoint devices (causing TP_READ_ID command to time out).
*/
if (max_proto > PSMOUSE_IMEX) {
if (psmouse_do_detect(fsp_detect,
psmouse, set_properties) == 0) {
if (!set_properties || fsp_init(psmouse) == 0)
return PSMOUSE_FSP;
/*
* Init failed, try basic relative protocols
*/
max_proto = PSMOUSE_IMEX;
}
}
/*
* Reset to defaults in case the device got confused by extended
* protocol probes. Note that we follow up with full reset because
* some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
*/
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
if (max_proto >= PSMOUSE_IMEX &&
psmouse_do_detect(im_explorer_detect,
psmouse, set_properties) == 0) {
return PSMOUSE_IMEX;
}
if (max_proto >= PSMOUSE_IMPS &&
psmouse_do_detect(intellimouse_detect,
psmouse, set_properties) == 0) {
return PSMOUSE_IMPS;
}
/*
* Okay, all failed, we have a standard mouse here. The number of the buttons
* is still a question, though. We assume 3.
*/
psmouse_do_detect(ps2bare_detect, psmouse, set_properties);
if (synaptics_hardware) {
/*
* We detected Synaptics hardware but it did not respond to IMPS/2 probes.
* We need to reset the touchpad because if there is a track point on the
* pass through port it could get disabled while probing for protocol
* extensions.
*/
psmouse_reset(psmouse);
}
return PSMOUSE_PS2;
}
static const struct psmouse_protocol psmouse_protocols[] = { static const struct psmouse_protocol psmouse_protocols[] = {
{ {
.type = PSMOUSE_PS2, .type = PSMOUSE_PS2,
...@@ -985,13 +692,14 @@ static const struct psmouse_protocol psmouse_protocols[] = { ...@@ -985,13 +692,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.maxproto = true, .maxproto = true,
.ignore_parity = true, .ignore_parity = true,
.detect = ps2bare_detect, .detect = ps2bare_detect,
.try_passthru = true,
}, },
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
{ {
.type = PSMOUSE_PS2PP, .type = PSMOUSE_PS2PP,
.name = "PS2++", .name = "PS2++",
.alias = "logitech", .alias = "logitech",
.detect = ps2pp_init, .detect = ps2pp_detect,
}, },
#endif #endif
{ {
...@@ -1022,6 +730,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { ...@@ -1022,6 +730,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.maxproto = true, .maxproto = true,
.ignore_parity = true, .ignore_parity = true,
.detect = intellimouse_detect, .detect = intellimouse_detect,
.try_passthru = true,
}, },
{ {
.type = PSMOUSE_IMEX, .type = PSMOUSE_IMEX,
...@@ -1030,6 +739,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { ...@@ -1030,6 +739,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.maxproto = true, .maxproto = true,
.ignore_parity = true, .ignore_parity = true,
.detect = im_explorer_detect, .detect = im_explorer_detect,
.try_passthru = true,
}, },
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS #ifdef CONFIG_MOUSE_PS2_SYNAPTICS
{ {
...@@ -1061,6 +771,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { ...@@ -1061,6 +771,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.type = PSMOUSE_LIFEBOOK, .type = PSMOUSE_LIFEBOOK,
.name = "LBPS/2", .name = "LBPS/2",
.alias = "lifebook", .alias = "lifebook",
.detect = lifebook_detect,
.init = lifebook_init, .init = lifebook_init,
}, },
#endif #endif
...@@ -1070,6 +781,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { ...@@ -1070,6 +781,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.name = "TPPS/2", .name = "TPPS/2",
.alias = "trackpoint", .alias = "trackpoint",
.detect = trackpoint_detect, .detect = trackpoint_detect,
.try_passthru = true,
}, },
#endif #endif
#ifdef CONFIG_MOUSE_PS2_TOUCHKIT #ifdef CONFIG_MOUSE_PS2_TOUCHKIT
...@@ -1138,7 +850,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { ...@@ -1138,7 +850,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
}, },
}; };
static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) static const struct psmouse_protocol *__psmouse_protocol_by_type(enum psmouse_type type)
{ {
int i; int i;
...@@ -1146,6 +858,17 @@ static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type ...@@ -1146,6 +858,17 @@ static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type
if (psmouse_protocols[i].type == type) if (psmouse_protocols[i].type == type)
return &psmouse_protocols[i]; return &psmouse_protocols[i];
return NULL;
}
static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
{
const struct psmouse_protocol *proto;
proto = __psmouse_protocol_by_type(type);
if (proto)
return proto;
WARN_ON(1); WARN_ON(1);
return &psmouse_protocols[0]; return &psmouse_protocols[0];
} }
...@@ -1166,23 +889,288 @@ static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name, ...@@ -1166,23 +889,288 @@ static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name,
return NULL; return NULL;
} }
/*
* Apply default settings to the psmouse structure. Most of them will
* be overridden by individual protocol initialization routines.
*/
static void psmouse_apply_defaults(struct psmouse *psmouse)
{
struct input_dev *input_dev = psmouse->dev;
memset(input_dev->evbit, 0, sizeof(input_dev->evbit));
memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
memset(input_dev->relbit, 0, sizeof(input_dev->relbit));
memset(input_dev->absbit, 0, sizeof(input_dev->absbit));
memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit));
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_REL, input_dev->evbit);
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_RIGHT, input_dev->keybit);
__set_bit(REL_X, input_dev->relbit);
__set_bit(REL_Y, input_dev->relbit);
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
psmouse->set_rate = psmouse_set_rate;
psmouse->set_resolution = psmouse_set_resolution;
psmouse->set_scale = psmouse_set_scale;
psmouse->poll = psmouse_poll;
psmouse->protocol_handler = psmouse_process_byte;
psmouse->pktsize = 3;
psmouse->reconnect = NULL;
psmouse->disconnect = NULL;
psmouse->cleanup = NULL;
psmouse->pt_activate = NULL;
psmouse->pt_deactivate = NULL;
}
static bool psmouse_try_protocol(struct psmouse *psmouse,
enum psmouse_type type,
unsigned int *max_proto,
bool set_properties, bool init_allowed)
{
const struct psmouse_protocol *proto;
proto = __psmouse_protocol_by_type(type);
if (!proto)
return false;
if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU &&
!proto->try_passthru) {
return false;
}
if (set_properties)
psmouse_apply_defaults(psmouse);
if (proto->detect(psmouse, set_properties) != 0)
return false;
if (set_properties && proto->init && init_allowed) {
if (proto->init(psmouse) != 0) {
/*
* We detected device, but init failed. Adjust
* max_proto so we only try standard protocols.
*/
if (*max_proto > PSMOUSE_IMEX)
*max_proto = PSMOUSE_IMEX;
return false;
}
}
return true;
}
/* /*
* psmouse_probe() probes for a PS/2 mouse. * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
* the mouse may have.
*/ */
static int psmouse_extensions(struct psmouse *psmouse,
unsigned int max_proto, bool set_properties)
{
bool synaptics_hardware = false;
/*
* Always check for focaltech, this is safe as it uses pnp-id
* matching.
*/
if (psmouse_try_protocol(psmouse, PSMOUSE_FOCALTECH,
&max_proto, set_properties, false)) {
if (max_proto > PSMOUSE_IMEX &&
IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH) &&
(!set_properties || focaltech_init(psmouse) == 0)) {
return PSMOUSE_FOCALTECH;
}
/*
* Restrict psmouse_max_proto so that psmouse_initialize()
* does not try to reset rate and resolution, because even
* that upsets the device.
* This also causes us to basically fall through to basic
* protocol detection, where we fully reset the mouse,
* and set it up as bare PS/2 protocol device.
*/
psmouse_max_proto = max_proto = PSMOUSE_PS2;
}
/*
* We always check for LifeBook because it does not disturb mouse
* (it only checks DMI information).
*/
if (psmouse_try_protocol(psmouse, PSMOUSE_LIFEBOOK, &max_proto,
set_properties, max_proto > PSMOUSE_IMEX))
return PSMOUSE_LIFEBOOK;
if (psmouse_try_protocol(psmouse, PSMOUSE_VMMOUSE, &max_proto,
set_properties, max_proto > PSMOUSE_IMEX))
return PSMOUSE_VMMOUSE;
/*
* Try Kensington ThinkingMouse (we try first, because Synaptics
* probe upsets the ThinkingMouse).
*/
if (max_proto > PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_THINKPS, &max_proto,
set_properties, true)) {
return PSMOUSE_THINKPS;
}
/*
* Try Synaptics TouchPad. Note that probing is done even if
* Synaptics protocol support is disabled in config - we need to
* know if it is Synaptics so we can reset it properly after
* probing for IntelliMouse.
*/
if (max_proto > PSMOUSE_PS2 &&
psmouse_try_protocol(psmouse, PSMOUSE_SYNAPTICS, &max_proto,
set_properties, false)) {
synaptics_hardware = true;
if (max_proto > PSMOUSE_IMEX) {
/*
* Try activating protocol, but check if support is
* enabled first, since we try detecting Synaptics
* even when protocol is disabled.
*/
if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) &&
(!set_properties || synaptics_init(psmouse) == 0)) {
return PSMOUSE_SYNAPTICS;
}
/*
* Some Synaptics touchpads can emulate extended
* protocols (like IMPS/2). Unfortunately
* Logitech/Genius probes confuse some firmware
* versions so we'll have to skip them.
*/
max_proto = PSMOUSE_IMEX;
}
/*
* Make sure that touchpad is in relative mode, gestures
* (taps) are enabled.
*/
synaptics_reset(psmouse);
}
/*
* Try Cypress Trackpad. We must try it before Finger Sensing Pad
* because Finger Sensing Pad probe upsets some modules of Cypress
* Trackpads.
*/
if (max_proto > PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_CYPRESS, &max_proto,
set_properties, true)) {
return PSMOUSE_CYPRESS;
}
/* Try ALPS TouchPad */
if (max_proto > PSMOUSE_IMEX) {
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
if (psmouse_try_protocol(psmouse, PSMOUSE_ALPS,
&max_proto, set_properties, true))
return PSMOUSE_ALPS;
}
/* Try OLPC HGPK touchpad */
if (max_proto > PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_HGPK, &max_proto,
set_properties, true)) {
return PSMOUSE_HGPK;
}
/* Try Elantech touchpad */
if (max_proto > PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH,
&max_proto, set_properties, true)) {
return PSMOUSE_ELANTECH;
}
if (max_proto > PSMOUSE_IMEX) {
if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS,
&max_proto, set_properties, true))
return PSMOUSE_GENPS;
if (psmouse_try_protocol(psmouse, PSMOUSE_PS2PP,
&max_proto, set_properties, true))
return PSMOUSE_PS2PP;
if (psmouse_try_protocol(psmouse, PSMOUSE_TRACKPOINT,
&max_proto, set_properties, true))
return PSMOUSE_TRACKPOINT;
if (psmouse_try_protocol(psmouse, PSMOUSE_TOUCHKIT_PS2,
&max_proto, set_properties, true))
return PSMOUSE_TOUCHKIT_PS2;
}
/*
* Try Finger Sensing Pad. We do it here because its probe upsets
* Trackpoint devices (causing TP_READ_ID command to time out).
*/
if (max_proto > PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_FSP,
&max_proto, set_properties, true)) {
return PSMOUSE_FSP;
}
/*
* Reset to defaults in case the device got confused by extended
* protocol probes. Note that we follow up with full reset because
* some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
*/
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
if (max_proto >= PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_IMEX,
&max_proto, set_properties, true)) {
return PSMOUSE_IMEX;
}
if (max_proto >= PSMOUSE_IMPS &&
psmouse_try_protocol(psmouse, PSMOUSE_IMPS,
&max_proto, set_properties, true)) {
return PSMOUSE_IMPS;
}
/*
* Okay, all failed, we have a standard mouse here. The number of
* the buttons is still a question, though. We assume 3.
*/
psmouse_try_protocol(psmouse, PSMOUSE_PS2,
&max_proto, set_properties, true);
if (synaptics_hardware) {
/*
* We detected Synaptics hardware but it did not respond to
* IMPS/2 probes. We need to reset the touchpad because if
* there is a track point on the pass through port it could
* get disabled while probing for protocol extensions.
*/
psmouse_reset(psmouse);
}
return PSMOUSE_PS2;
}
/*
* psmouse_probe() probes for a PS/2 mouse.
*/
static int psmouse_probe(struct psmouse *psmouse) static int psmouse_probe(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2]; unsigned char param[2];
/* /*
* First, we check if it's a mouse. It should send 0x00 or 0x03 * First, we check if it's a mouse. It should send 0x00 or 0x03 in
* in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. * case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
* Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and subsequent * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and
* ID queries, probably due to a firmware bug. * subsequent ID queries, probably due to a firmware bug.
*/ */
param[0] = 0xa5; param[0] = 0xa5;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
return -1; return -1;
...@@ -1191,10 +1179,10 @@ static int psmouse_probe(struct psmouse *psmouse) ...@@ -1191,10 +1179,10 @@ static int psmouse_probe(struct psmouse *psmouse)
param[0] != 0x04 && param[0] != 0xff) param[0] != 0x04 && param[0] != 0xff)
return -1; return -1;
/* /*
* Then we reset and disable the mouse so that it doesn't generate events. * Then we reset and disable the mouse so that it doesn't generate
* events.
*/ */
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS)) if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
psmouse_warn(psmouse, "Failed to reset mouse on %s\n", psmouse_warn(psmouse, "Failed to reset mouse on %s\n",
ps2dev->serio->phys); ps2dev->serio->phys);
...@@ -1205,13 +1193,11 @@ static int psmouse_probe(struct psmouse *psmouse) ...@@ -1205,13 +1193,11 @@ static int psmouse_probe(struct psmouse *psmouse)
/* /*
* psmouse_initialize() initializes the mouse to a sane state. * psmouse_initialize() initializes the mouse to a sane state.
*/ */
static void psmouse_initialize(struct psmouse *psmouse) static void psmouse_initialize(struct psmouse *psmouse)
{ {
/* /*
* We set the mouse report rate, resolution and scaling. * We set the mouse report rate, resolution and scaling.
*/ */
if (psmouse_max_proto != PSMOUSE_PS2) { if (psmouse_max_proto != PSMOUSE_PS2) {
psmouse->set_rate(psmouse, psmouse->rate); psmouse->set_rate(psmouse, psmouse->rate);
psmouse->set_resolution(psmouse, psmouse->resolution); psmouse->set_resolution(psmouse, psmouse->resolution);
...@@ -1222,7 +1208,6 @@ static void psmouse_initialize(struct psmouse *psmouse) ...@@ -1222,7 +1208,6 @@ static void psmouse_initialize(struct psmouse *psmouse)
/* /*
* psmouse_activate() enables the mouse so that we get motion reports from it. * psmouse_activate() enables the mouse so that we get motion reports from it.
*/ */
int psmouse_activate(struct psmouse *psmouse) int psmouse_activate(struct psmouse *psmouse)
{ {
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
...@@ -1236,10 +1221,9 @@ int psmouse_activate(struct psmouse *psmouse) ...@@ -1236,10 +1221,9 @@ int psmouse_activate(struct psmouse *psmouse)
} }
/* /*
* psmouse_deactivate() puts the mouse into poll mode so that we don't get motion * psmouse_deactivate() puts the mouse into poll mode so that we don't get
* reports from it unless we explicitly request it. * motion reports from it unless we explicitly request it.
*/ */
int psmouse_deactivate(struct psmouse *psmouse) int psmouse_deactivate(struct psmouse *psmouse)
{ {
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) { if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) {
...@@ -1252,11 +1236,9 @@ int psmouse_deactivate(struct psmouse *psmouse) ...@@ -1252,11 +1236,9 @@ int psmouse_deactivate(struct psmouse *psmouse)
return 0; return 0;
} }
/* /*
* psmouse_resync() attempts to re-validate current protocol. * psmouse_resync() attempts to re-validate current protocol.
*/ */
static void psmouse_resync(struct work_struct *work) static void psmouse_resync(struct work_struct *work)
{ {
struct psmouse *parent = NULL, *psmouse = struct psmouse *parent = NULL, *psmouse =
...@@ -1276,7 +1258,7 @@ static void psmouse_resync(struct work_struct *work) ...@@ -1276,7 +1258,7 @@ static void psmouse_resync(struct work_struct *work)
psmouse_deactivate(parent); psmouse_deactivate(parent);
} }
/* /*
* Some mice don't ACK commands sent while they are in the middle of * Some mice don't ACK commands sent while they are in the middle of
* transmitting motion packet. To avoid delay we use ps2_sendbyte() * transmitting motion packet. To avoid delay we use ps2_sendbyte()
* instead of ps2_command() which would wait for 200ms for an ACK * instead of ps2_command() which would wait for 200ms for an ACK
...@@ -1294,7 +1276,7 @@ static void psmouse_resync(struct work_struct *work) ...@@ -1294,7 +1276,7 @@ static void psmouse_resync(struct work_struct *work)
} else } else
psmouse->acks_disable_command = true; psmouse->acks_disable_command = true;
/* /*
* Poll the mouse. If it was reset the packet will be shorter than * Poll the mouse. If it was reset the packet will be shorter than
* psmouse->pktsize and ps2_command will fail. We do not expect and * psmouse->pktsize and ps2_command will fail. We do not expect and
* do not handle scenario when mouse "upgrades" its protocol while * do not handle scenario when mouse "upgrades" its protocol while
...@@ -1317,10 +1299,11 @@ static void psmouse_resync(struct work_struct *work) ...@@ -1317,10 +1299,11 @@ static void psmouse_resync(struct work_struct *work)
psmouse_set_state(psmouse, PSMOUSE_RESYNCING); psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
} }
} }
/*
* Now try to enable mouse. We try to do that even if poll failed and also /*
* repeat our attempts 5 times, otherwise we may be left out with disabled * Now try to enable mouse. We try to do that even if poll failed
* mouse. * and also repeat our attempts 5 times, otherwise we may be left
* out with disabled mouse.
*/ */
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
...@@ -1353,7 +1336,6 @@ static void psmouse_resync(struct work_struct *work) ...@@ -1353,7 +1336,6 @@ static void psmouse_resync(struct work_struct *work)
/* /*
* psmouse_cleanup() resets the mouse into power-on state. * psmouse_cleanup() resets the mouse into power-on state.
*/ */
static void psmouse_cleanup(struct serio *serio) static void psmouse_cleanup(struct serio *serio)
{ {
struct psmouse *psmouse = serio_get_drvdata(serio); struct psmouse *psmouse = serio_get_drvdata(serio);
...@@ -1378,12 +1360,12 @@ static void psmouse_cleanup(struct serio *serio) ...@@ -1378,12 +1360,12 @@ static void psmouse_cleanup(struct serio *serio)
if (psmouse->cleanup) if (psmouse->cleanup)
psmouse->cleanup(psmouse); psmouse->cleanup(psmouse);
/* /*
* Reset the mouse to defaults (bare PS/2 protocol). * Reset the mouse to defaults (bare PS/2 protocol).
*/ */
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
/* /*
* Some boxes, such as HP nx7400, get terribly confused if mouse * Some boxes, such as HP nx7400, get terribly confused if mouse
* is not fully enabled before suspending/shutting down. * is not fully enabled before suspending/shutting down.
*/ */
...@@ -1402,7 +1384,6 @@ static void psmouse_cleanup(struct serio *serio) ...@@ -1402,7 +1384,6 @@ static void psmouse_cleanup(struct serio *serio)
/* /*
* psmouse_disconnect() closes and frees. * psmouse_disconnect() closes and frees.
*/ */
static void psmouse_disconnect(struct serio *serio) static void psmouse_disconnect(struct serio *serio)
{ {
struct psmouse *psmouse, *parent = NULL; struct psmouse *psmouse, *parent = NULL;
...@@ -1602,7 +1583,6 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) ...@@ -1602,7 +1583,6 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
goto out; goto out;
} }
static int psmouse_reconnect(struct serio *serio) static int psmouse_reconnect(struct serio *serio)
{ {
struct psmouse *psmouse = serio_get_drvdata(serio); struct psmouse *psmouse = serio_get_drvdata(serio);
......
...@@ -257,6 +257,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { ...@@ -257,6 +257,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
}, },
}, },
{
/* Fujitsu Lifebook U745 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"),
},
},
{ {
/* Fujitsu T70H */ /* Fujitsu T70H */
.matches = { .matches = {
......
...@@ -295,6 +295,16 @@ config TOUCHSCREEN_EGALAX ...@@ -295,6 +295,16 @@ config TOUCHSCREEN_EGALAX
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called egalax_ts. module will be called egalax_ts.
config TOUCHSCREEN_EGALAX_SERIAL
tristate "EETI eGalax serial touchscreen"
select SERIO
help
Say Y here to enable support for serial connected EETI
eGalax touch panels.
To compile this driver as a module, choose M here: the
module will be called egalax_ts_serial.
config TOUCHSCREEN_FT6236 config TOUCHSCREEN_FT6236
tristate "FT6236 I2C touchscreen" tristate "FT6236 I2C touchscreen"
depends on I2C depends on I2C
...@@ -324,6 +334,7 @@ config TOUCHSCREEN_FUJITSU ...@@ -324,6 +334,7 @@ config TOUCHSCREEN_FUJITSU
config TOUCHSCREEN_GOODIX config TOUCHSCREEN_GOODIX
tristate "Goodix I2C touchscreen" tristate "Goodix I2C touchscreen"
depends on I2C depends on I2C
depends on GPIOLIB
help help
Say Y here if you have the Goodix touchscreen (such as one Say Y here if you have the Goodix touchscreen (such as one
installed in Onda v975w tablets) connected to your installed in Onda v975w tablets) connected to your
...@@ -927,6 +938,22 @@ config TOUCHSCREEN_TOUCHIT213 ...@@ -927,6 +938,22 @@ config TOUCHSCREEN_TOUCHIT213
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called touchit213. module will be called touchit213.
config TOUCHSCREEN_TS4800
tristate "TS-4800 touchscreen"
depends on HAS_IOMEM && OF
select MFD_SYSCON
select INPUT_POLLDEV
help
Say Y here if you have a touchscreen on a TS-4800 board.
On TS-4800, the touchscreen is not handled directly by Linux but by
a companion FPGA.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called ts4800_ts.
config TOUCHSCREEN_TSC_SERIO config TOUCHSCREEN_TSC_SERIO
tristate "TSC-10/25/40 serial touchscreen support" tristate "TSC-10/25/40 serial touchscreen support"
select SERIO select SERIO
......
...@@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o ...@@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
...@@ -68,6 +69,7 @@ obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o ...@@ -68,6 +69,7 @@ obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_TS4800) += ts4800-ts.o
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o
obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o
......
/*
* EETI Egalax serial touchscreen driver
*
* Copyright (c) 2015 Zoltán Böszörményi <zboszor@pr.hu>
*
* based on the
*
* Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett)
*/
/*
* 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/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#define DRIVER_DESC "EETI Egalax serial touchscreen driver"
/*
* Definitions & global arrays.
*/
#define EGALAX_FORMAT_MAX_LENGTH 6
#define EGALAX_FORMAT_START_BIT BIT(7)
#define EGALAX_FORMAT_PRESSURE_BIT BIT(6)
#define EGALAX_FORMAT_TOUCH_BIT BIT(0)
#define EGALAX_FORMAT_RESOLUTION_MASK 0x06
#define EGALAX_MIN_XC 0
#define EGALAX_MAX_XC 0x4000
#define EGALAX_MIN_YC 0
#define EGALAX_MAX_YC 0x4000
/*
* Per-touchscreen data.
*/
struct egalax {
struct input_dev *input;
struct serio *serio;
int idx;
u8 data[EGALAX_FORMAT_MAX_LENGTH];
char phys[32];
};
static void egalax_process_data(struct egalax *egalax)
{
struct input_dev *dev = egalax->input;
u8 *data = egalax->data;
u16 x, y;
u8 shift;
u8 mask;
shift = 3 - ((data[0] & EGALAX_FORMAT_RESOLUTION_MASK) >> 1);
mask = 0xff >> (shift + 1);
x = (((u16)(data[1] & mask) << 7) | (data[2] & 0x7f)) << shift;
y = (((u16)(data[3] & mask) << 7) | (data[4] & 0x7f)) << shift;
input_report_key(dev, BTN_TOUCH, data[0] & EGALAX_FORMAT_TOUCH_BIT);
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
input_sync(dev);
}
static irqreturn_t egalax_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct egalax *egalax = serio_get_drvdata(serio);
int pkt_len;
egalax->data[egalax->idx++] = data;
if (likely(egalax->data[0] & EGALAX_FORMAT_START_BIT)) {
pkt_len = egalax->data[0] & EGALAX_FORMAT_PRESSURE_BIT ? 6 : 5;
if (pkt_len == egalax->idx) {
egalax_process_data(egalax);
egalax->idx = 0;
}
} else {
dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
egalax->data[0]);
egalax->idx = 0;
}
return IRQ_HANDLED;
}
/*
* egalax_connect() is the routine that is called when someone adds a
* new serio device that supports egalax protocol and registers it as
* an input device. This is usually accomplished using inputattach.
*/
static int egalax_connect(struct serio *serio, struct serio_driver *drv)
{
struct egalax *egalax;
struct input_dev *input_dev;
int error;
egalax = kzalloc(sizeof(struct egalax), GFP_KERNEL);
input_dev = input_allocate_device();
if (!egalax || !input_dev) {
error = -ENOMEM;
goto err_free_mem;
}
egalax->serio = serio;
egalax->input = input_dev;
snprintf(egalax->phys, sizeof(egalax->phys),
"%s/input0", serio->phys);
input_dev->name = "EETI eGalaxTouch Serial TouchScreen";
input_dev->phys = egalax->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_EGALAX;
input_dev->id.product = 0;
input_dev->id.version = 0x0001;
input_dev->dev.parent = &serio->dev;
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
EGALAX_MIN_XC, EGALAX_MAX_XC, 0, 0);
input_set_abs_params(input_dev, ABS_Y,
EGALAX_MIN_YC, EGALAX_MAX_YC, 0, 0);
serio_set_drvdata(serio, egalax);
error = serio_open(serio, drv);
if (error)
goto err_reset_drvdata;
error = input_register_device(input_dev);
if (error)
goto err_close_serio;
return 0;
err_close_serio:
serio_close(serio);
err_reset_drvdata:
serio_set_drvdata(serio, NULL);
err_free_mem:
input_free_device(input_dev);
kfree(egalax);
return error;
}
static void egalax_disconnect(struct serio *serio)
{
struct egalax *egalax = serio_get_drvdata(serio);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_unregister_device(egalax->input);
kfree(egalax);
}
/*
* The serio driver structure.
*/
static const struct serio_device_id egalax_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_EGALAX,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, egalax_serio_ids);
static struct serio_driver egalax_drv = {
.driver = {
.name = "egalax",
},
.description = DRIVER_DESC,
.id_table = egalax_serio_ids,
.interrupt = egalax_interrupt,
.connect = egalax_connect,
.disconnect = egalax_disconnect,
};
module_serio_driver(egalax_drv);
MODULE_AUTHOR("Zoltán Böszörményi <zboszor@pr.hu>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL v2");
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Driver for Goodix Touchscreens * Driver for Goodix Touchscreens
* *
* Copyright (c) 2014 Red Hat Inc. * Copyright (c) 2014 Red Hat Inc.
* Copyright (c) 2015 K. Merker <merker@debian.org>
* *
* This code is based on gt9xx.c authored by andrew@goodix.com: * This code is based on gt9xx.c authored by andrew@goodix.com:
* *
...@@ -16,6 +17,8 @@ ...@@ -16,6 +17,8 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
...@@ -33,11 +36,24 @@ struct goodix_ts_data { ...@@ -33,11 +36,24 @@ struct goodix_ts_data {
struct input_dev *input_dev; struct input_dev *input_dev;
int abs_x_max; int abs_x_max;
int abs_y_max; int abs_y_max;
bool swapped_x_y;
bool inverted_x;
bool inverted_y;
unsigned int max_touch_num; unsigned int max_touch_num;
unsigned int int_trigger_type; unsigned int int_trigger_type;
bool rotated_screen; int cfg_len;
struct gpio_desc *gpiod_int;
struct gpio_desc *gpiod_rst;
u16 id;
u16 version;
const char *cfg_name;
struct completion firmware_loading_complete;
unsigned long irq_flags;
}; };
#define GOODIX_GPIO_INT_NAME "irq"
#define GOODIX_GPIO_RST_NAME "reset"
#define GOODIX_MAX_HEIGHT 4096 #define GOODIX_MAX_HEIGHT 4096
#define GOODIX_MAX_WIDTH 4096 #define GOODIX_MAX_WIDTH 4096
#define GOODIX_INT_TRIGGER 1 #define GOODIX_INT_TRIGGER 1
...@@ -45,8 +61,13 @@ struct goodix_ts_data { ...@@ -45,8 +61,13 @@ struct goodix_ts_data {
#define GOODIX_MAX_CONTACTS 10 #define GOODIX_MAX_CONTACTS 10
#define GOODIX_CONFIG_MAX_LENGTH 240 #define GOODIX_CONFIG_MAX_LENGTH 240
#define GOODIX_CONFIG_911_LENGTH 186
#define GOODIX_CONFIG_967_LENGTH 228
/* Register defines */ /* Register defines */
#define GOODIX_REG_COMMAND 0x8040
#define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_READ_COOR_ADDR 0x814E #define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_REG_CONFIG_DATA 0x8047 #define GOODIX_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140 #define GOODIX_REG_ID 0x8140
...@@ -115,6 +136,63 @@ static int goodix_i2c_read(struct i2c_client *client, ...@@ -115,6 +136,63 @@ static int goodix_i2c_read(struct i2c_client *client,
return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0); return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
} }
/**
* goodix_i2c_write - write data to a register of the i2c slave device.
*
* @client: i2c device.
* @reg: the register to write to.
* @buf: raw data buffer to write.
* @len: length of the buffer to write
*/
static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
unsigned len)
{
u8 *addr_buf;
struct i2c_msg msg;
int ret;
addr_buf = kmalloc(len + 2, GFP_KERNEL);
if (!addr_buf)
return -ENOMEM;
addr_buf[0] = reg >> 8;
addr_buf[1] = reg & 0xFF;
memcpy(&addr_buf[2], buf, len);
msg.flags = 0;
msg.addr = client->addr;
msg.buf = addr_buf;
msg.len = len + 2;
ret = i2c_transfer(client->adapter, &msg, 1);
kfree(addr_buf);
return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
}
static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
{
return goodix_i2c_write(client, reg, &value, sizeof(value));
}
static int goodix_get_cfg_len(u16 id)
{
switch (id) {
case 911:
case 9271:
case 9110:
case 927:
case 928:
return GOODIX_CONFIG_911_LENGTH;
case 912:
case 967:
return GOODIX_CONFIG_967_LENGTH;
default:
return GOODIX_CONFIG_MAX_LENGTH;
}
}
static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
{ {
int touch_num; int touch_num;
...@@ -155,10 +233,13 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data) ...@@ -155,10 +233,13 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
int input_y = get_unaligned_le16(&coor_data[3]); int input_y = get_unaligned_le16(&coor_data[3]);
int input_w = get_unaligned_le16(&coor_data[5]); int input_w = get_unaligned_le16(&coor_data[5]);
if (ts->rotated_screen) { /* Inversions have to happen before axis swapping */
if (ts->inverted_x)
input_x = ts->abs_x_max - input_x; input_x = ts->abs_x_max - input_x;
if (ts->inverted_y)
input_y = ts->abs_y_max - input_y; input_y = ts->abs_y_max - input_y;
} if (ts->swapped_x_y)
swap(input_x, input_y);
input_mt_slot(ts->input_dev, id); input_mt_slot(ts->input_dev, id);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
...@@ -202,21 +283,195 @@ static void goodix_process_events(struct goodix_ts_data *ts) ...@@ -202,21 +283,195 @@ static void goodix_process_events(struct goodix_ts_data *ts)
*/ */
static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
{ {
static const u8 end_cmd[] = {
GOODIX_READ_COOR_ADDR >> 8,
GOODIX_READ_COOR_ADDR & 0xff,
0
};
struct goodix_ts_data *ts = dev_id; struct goodix_ts_data *ts = dev_id;
goodix_process_events(ts); goodix_process_events(ts);
if (i2c_master_send(ts->client, end_cmd, sizeof(end_cmd)) < 0) if (goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0) < 0)
dev_err(&ts->client->dev, "I2C write end_cmd error\n"); dev_err(&ts->client->dev, "I2C write end_cmd error\n");
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void goodix_free_irq(struct goodix_ts_data *ts)
{
devm_free_irq(&ts->client->dev, ts->client->irq, ts);
}
static int goodix_request_irq(struct goodix_ts_data *ts)
{
return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
NULL, goodix_ts_irq_handler,
ts->irq_flags, ts->client->name, ts);
}
/**
* goodix_check_cfg - Checks if config fw is valid
*
* @ts: goodix_ts_data pointer
* @cfg: firmware config data
*/
static int goodix_check_cfg(struct goodix_ts_data *ts,
const struct firmware *cfg)
{
int i, raw_cfg_len;
u8 check_sum = 0;
if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
dev_err(&ts->client->dev,
"The length of the config fw is not correct");
return -EINVAL;
}
raw_cfg_len = cfg->size - 2;
for (i = 0; i < raw_cfg_len; i++)
check_sum += cfg->data[i];
check_sum = (~check_sum) + 1;
if (check_sum != cfg->data[raw_cfg_len]) {
dev_err(&ts->client->dev,
"The checksum of the config fw is not correct");
return -EINVAL;
}
if (cfg->data[raw_cfg_len + 1] != 1) {
dev_err(&ts->client->dev,
"Config fw must have Config_Fresh register set");
return -EINVAL;
}
return 0;
}
/**
* goodix_send_cfg - Write fw config to device
*
* @ts: goodix_ts_data pointer
* @cfg: config firmware to write to device
*/
static int goodix_send_cfg(struct goodix_ts_data *ts,
const struct firmware *cfg)
{
int error;
error = goodix_check_cfg(ts, cfg);
if (error)
return error;
error = goodix_i2c_write(ts->client, GOODIX_REG_CONFIG_DATA, cfg->data,
cfg->size);
if (error) {
dev_err(&ts->client->dev, "Failed to write config data: %d",
error);
return error;
}
dev_dbg(&ts->client->dev, "Config sent successfully.");
/* Let the firmware reconfigure itself, so sleep for 10ms */
usleep_range(10000, 11000);
return 0;
}
static int goodix_int_sync(struct goodix_ts_data *ts)
{
int error;
error = gpiod_direction_output(ts->gpiod_int, 0);
if (error)
return error;
msleep(50); /* T5: 50ms */
error = gpiod_direction_input(ts->gpiod_int);
if (error)
return error;
return 0;
}
/**
* goodix_reset - Reset device during power on
*
* @ts: goodix_ts_data pointer
*/
static int goodix_reset(struct goodix_ts_data *ts)
{
int error;
/* begin select I2C slave addr */
error = gpiod_direction_output(ts->gpiod_rst, 0);
if (error)
return error;
msleep(20); /* T2: > 10ms */
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
error = gpiod_direction_output(ts->gpiod_int, ts->client->addr == 0x14);
if (error)
return error;
usleep_range(100, 2000); /* T3: > 100us */
error = gpiod_direction_output(ts->gpiod_rst, 1);
if (error)
return error;
usleep_range(6000, 10000); /* T4: > 5ms */
/* end select I2C slave addr */
error = gpiod_direction_input(ts->gpiod_rst);
if (error)
return error;
error = goodix_int_sync(ts);
if (error)
return error;
return 0;
}
/**
* goodix_get_gpio_config - Get GPIO config from ACPI/DT
*
* @ts: goodix_ts_data pointer
*/
static int goodix_get_gpio_config(struct goodix_ts_data *ts)
{
int error;
struct device *dev;
struct gpio_desc *gpiod;
if (!ts->client)
return -EINVAL;
dev = &ts->client->dev;
/* Get the interrupt GPIO pin number */
gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
if (IS_ERR(gpiod)) {
error = PTR_ERR(gpiod);
if (error != -EPROBE_DEFER)
dev_dbg(dev, "Failed to get %s GPIO: %d\n",
GOODIX_GPIO_INT_NAME, error);
return error;
}
ts->gpiod_int = gpiod;
/* Get the reset line GPIO pin number */
gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN);
if (IS_ERR(gpiod)) {
error = PTR_ERR(gpiod);
if (error != -EPROBE_DEFER)
dev_dbg(dev, "Failed to get %s GPIO: %d\n",
GOODIX_GPIO_RST_NAME, error);
return error;
}
ts->gpiod_rst = gpiod;
return 0;
}
/** /**
* goodix_read_config - Read the embedded configuration of the panel * goodix_read_config - Read the embedded configuration of the panel
* *
...@@ -230,14 +485,15 @@ static void goodix_read_config(struct goodix_ts_data *ts) ...@@ -230,14 +485,15 @@ static void goodix_read_config(struct goodix_ts_data *ts)
int error; int error;
error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA, error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
config, config, ts->cfg_len);
GOODIX_CONFIG_MAX_LENGTH);
if (error) { if (error) {
dev_warn(&ts->client->dev, dev_warn(&ts->client->dev,
"Error reading config (%d), using defaults\n", "Error reading config (%d), using defaults\n",
error); error);
ts->abs_x_max = GOODIX_MAX_WIDTH; ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT; ts->abs_y_max = GOODIX_MAX_HEIGHT;
if (ts->swapped_x_y)
swap(ts->abs_x_max, ts->abs_y_max);
ts->int_trigger_type = GOODIX_INT_TRIGGER; ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS; ts->max_touch_num = GOODIX_MAX_CONTACTS;
return; return;
...@@ -245,6 +501,8 @@ static void goodix_read_config(struct goodix_ts_data *ts) ...@@ -245,6 +501,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]); ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]); ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
if (ts->swapped_x_y)
swap(ts->abs_x_max, ts->abs_y_max);
ts->int_trigger_type = config[TRIGGER_LOC] & 0x03; ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f; ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f;
if (!ts->abs_x_max || !ts->abs_y_max || !ts->max_touch_num) { if (!ts->abs_x_max || !ts->abs_y_max || !ts->max_touch_num) {
...@@ -252,42 +510,45 @@ static void goodix_read_config(struct goodix_ts_data *ts) ...@@ -252,42 +510,45 @@ static void goodix_read_config(struct goodix_ts_data *ts)
"Invalid config, using defaults\n"); "Invalid config, using defaults\n");
ts->abs_x_max = GOODIX_MAX_WIDTH; ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT; ts->abs_y_max = GOODIX_MAX_HEIGHT;
if (ts->swapped_x_y)
swap(ts->abs_x_max, ts->abs_y_max);
ts->max_touch_num = GOODIX_MAX_CONTACTS; ts->max_touch_num = GOODIX_MAX_CONTACTS;
} }
ts->rotated_screen = dmi_check_system(rotated_screen); if (dmi_check_system(rotated_screen)) {
if (ts->rotated_screen) ts->inverted_x = true;
ts->inverted_y = true;
dev_dbg(&ts->client->dev, dev_dbg(&ts->client->dev,
"Applying '180 degrees rotated screen' quirk\n"); "Applying '180 degrees rotated screen' quirk\n");
}
} }
/** /**
* goodix_read_version - Read goodix touchscreen version * goodix_read_version - Read goodix touchscreen version
* *
* @client: the i2c client * @ts: our goodix_ts_data pointer
* @version: output buffer containing the version on success
* @id: output buffer containing the id on success
*/ */
static int goodix_read_version(struct i2c_client *client, u16 *version, u16 *id) static int goodix_read_version(struct goodix_ts_data *ts)
{ {
int error; int error;
u8 buf[6]; u8 buf[6];
char id_str[5]; char id_str[5];
error = goodix_i2c_read(client, GOODIX_REG_ID, buf, sizeof(buf)); error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf));
if (error) { if (error) {
dev_err(&client->dev, "read version failed: %d\n", error); dev_err(&ts->client->dev, "read version failed: %d\n", error);
return error; return error;
} }
memcpy(id_str, buf, 4); memcpy(id_str, buf, 4);
id_str[4] = 0; id_str[4] = 0;
if (kstrtou16(id_str, 10, id)) if (kstrtou16(id_str, 10, &ts->id))
*id = 0x1001; ts->id = 0x1001;
*version = get_unaligned_le16(&buf[4]); ts->version = get_unaligned_le16(&buf[4]);
dev_info(&client->dev, "ID %d, version: %04x\n", *id, *version); dev_info(&ts->client->dev, "ID %d, version: %04x\n", ts->id,
ts->version);
return 0; return 0;
} }
...@@ -321,13 +582,10 @@ static int goodix_i2c_test(struct i2c_client *client) ...@@ -321,13 +582,10 @@ static int goodix_i2c_test(struct i2c_client *client)
* goodix_request_input_dev - Allocate, populate and register the input device * goodix_request_input_dev - Allocate, populate and register the input device
* *
* @ts: our goodix_ts_data pointer * @ts: our goodix_ts_data pointer
* @version: device firmware version
* @id: device ID
* *
* Must be called during probe * Must be called during probe
*/ */
static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version, static int goodix_request_input_dev(struct goodix_ts_data *ts)
u16 id)
{ {
int error; int error;
...@@ -351,8 +609,8 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version, ...@@ -351,8 +609,8 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
ts->input_dev->phys = "input/ts"; ts->input_dev->phys = "input/ts";
ts->input_dev->id.bustype = BUS_I2C; ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0x0416; ts->input_dev->id.vendor = 0x0416;
ts->input_dev->id.product = id; ts->input_dev->id.product = ts->id;
ts->input_dev->id.version = version; ts->input_dev->id.version = ts->version;
error = input_register_device(ts->input_dev); error = input_register_device(ts->input_dev);
if (error) { if (error) {
...@@ -364,13 +622,75 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version, ...@@ -364,13 +622,75 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
return 0; return 0;
} }
/**
* goodix_configure_dev - Finish device initialization
*
* @ts: our goodix_ts_data pointer
*
* Must be called from probe to finish initialization of the device.
* Contains the common initialization code for both devices that
* declare gpio pins and devices that do not. It is either called
* directly from probe or from request_firmware_wait callback.
*/
static int goodix_configure_dev(struct goodix_ts_data *ts)
{
int error;
ts->swapped_x_y = device_property_read_bool(&ts->client->dev,
"touchscreen-swapped-x-y");
ts->inverted_x = device_property_read_bool(&ts->client->dev,
"touchscreen-inverted-x");
ts->inverted_y = device_property_read_bool(&ts->client->dev,
"touchscreen-inverted-y");
goodix_read_config(ts);
error = goodix_request_input_dev(ts);
if (error)
return error;
ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT;
error = goodix_request_irq(ts);
if (error) {
dev_err(&ts->client->dev, "request IRQ failed: %d\n", error);
return error;
}
return 0;
}
/**
* goodix_config_cb - Callback to finish device init
*
* @ts: our goodix_ts_data pointer
*
* request_firmware_wait callback that finishes
* initialization of the device.
*/
static void goodix_config_cb(const struct firmware *cfg, void *ctx)
{
struct goodix_ts_data *ts = ctx;
int error;
if (cfg) {
/* send device configuration to the firmware */
error = goodix_send_cfg(ts, cfg);
if (error)
goto err_release_cfg;
}
goodix_configure_dev(ts);
err_release_cfg:
release_firmware(cfg);
complete_all(&ts->firmware_loading_complete);
}
static int goodix_ts_probe(struct i2c_client *client, static int goodix_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct goodix_ts_data *ts; struct goodix_ts_data *ts;
unsigned long irq_flags;
int error; int error;
u16 version_info, id_info;
dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
...@@ -385,6 +705,20 @@ static int goodix_ts_probe(struct i2c_client *client, ...@@ -385,6 +705,20 @@ static int goodix_ts_probe(struct i2c_client *client,
ts->client = client; ts->client = client;
i2c_set_clientdata(client, ts); i2c_set_clientdata(client, ts);
init_completion(&ts->firmware_loading_complete);
error = goodix_get_gpio_config(ts);
if (error)
return error;
if (ts->gpiod_int && ts->gpiod_rst) {
/* reset the controller */
error = goodix_reset(ts);
if (error) {
dev_err(&client->dev, "Controller reset failed.\n");
return error;
}
}
error = goodix_i2c_test(client); error = goodix_i2c_test(client);
if (error) { if (error) {
...@@ -392,30 +726,125 @@ static int goodix_ts_probe(struct i2c_client *client, ...@@ -392,30 +726,125 @@ static int goodix_ts_probe(struct i2c_client *client,
return error; return error;
} }
error = goodix_read_version(client, &version_info, &id_info); error = goodix_read_version(ts);
if (error) { if (error) {
dev_err(&client->dev, "Read version failed.\n"); dev_err(&client->dev, "Read version failed.\n");
return error; return error;
} }
goodix_read_config(ts); ts->cfg_len = goodix_get_cfg_len(ts->id);
if (ts->gpiod_int && ts->gpiod_rst) {
/* update device config */
ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL,
"goodix_%d_cfg.bin", ts->id);
if (!ts->cfg_name)
return -ENOMEM;
error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name,
&client->dev, GFP_KERNEL, ts,
goodix_config_cb);
if (error) {
dev_err(&client->dev,
"Failed to invoke firmware loader: %d\n",
error);
return error;
}
error = goodix_request_input_dev(ts, version_info, id_info); return 0;
} else {
error = goodix_configure_dev(ts);
if (error) if (error)
return error; return error;
}
irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT; return 0;
error = devm_request_threaded_irq(&ts->client->dev, client->irq, }
NULL, goodix_ts_irq_handler,
irq_flags, client->name, ts); static int goodix_ts_remove(struct i2c_client *client)
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if (ts->gpiod_int && ts->gpiod_rst)
wait_for_completion(&ts->firmware_loading_complete);
return 0;
}
static int __maybe_unused goodix_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
int error;
/* We need gpio pins to suspend/resume */
if (!ts->gpiod_int || !ts->gpiod_rst)
return 0;
wait_for_completion(&ts->firmware_loading_complete);
/* Free IRQ as IRQ pin is used as output in the suspend sequence */
goodix_free_irq(ts);
/* Output LOW on the INT pin for 5 ms */
error = gpiod_direction_output(ts->gpiod_int, 0);
if (error) { if (error) {
dev_err(&client->dev, "request IRQ failed: %d\n", error); goodix_request_irq(ts);
return error; return error;
} }
usleep_range(5000, 6000);
error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND,
GOODIX_CMD_SCREEN_OFF);
if (error) {
dev_err(&ts->client->dev, "Screen off command failed\n");
gpiod_direction_input(ts->gpiod_int);
goodix_request_irq(ts);
return -EAGAIN;
}
/*
* The datasheet specifies that the interval between sending screen-off
* command and wake-up should be longer than 58 ms. To avoid waking up
* sooner, delay 58ms here.
*/
msleep(58);
return 0; return 0;
} }
static int __maybe_unused goodix_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
int error;
if (!ts->gpiod_int || !ts->gpiod_rst)
return 0;
/*
* Exit sleep mode by outputting HIGH level to INT pin
* for 2ms~5ms.
*/
error = gpiod_direction_output(ts->gpiod_int, 1);
if (error)
return error;
usleep_range(2000, 5000);
error = goodix_int_sync(ts);
if (error)
return error;
error = goodix_request_irq(ts);
if (error)
return error;
return 0;
}
static SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
static const struct i2c_device_id goodix_ts_id[] = { static const struct i2c_device_id goodix_ts_id[] = {
{ "GDIX1001:00", 0 }, { "GDIX1001:00", 0 },
{ } { }
...@@ -446,11 +875,13 @@ MODULE_DEVICE_TABLE(of, goodix_of_match); ...@@ -446,11 +875,13 @@ MODULE_DEVICE_TABLE(of, goodix_of_match);
static struct i2c_driver goodix_ts_driver = { static struct i2c_driver goodix_ts_driver = {
.probe = goodix_ts_probe, .probe = goodix_ts_probe,
.remove = goodix_ts_remove,
.id_table = goodix_ts_id, .id_table = goodix_ts_id,
.driver = { .driver = {
.name = "Goodix-TS", .name = "Goodix-TS",
.acpi_match_table = ACPI_PTR(goodix_acpi_match), .acpi_match_table = ACPI_PTR(goodix_acpi_match),
.of_match_table = of_match_ptr(goodix_of_match), .of_match_table = of_match_ptr(goodix_of_match),
.pm = &goodix_pm_ops,
}, },
}; };
module_i2c_driver(goodix_ts_driver); module_i2c_driver(goodix_ts_driver);
......
...@@ -87,7 +87,7 @@ static void pcap_ts_read_xy(void *data, u16 res[2]) ...@@ -87,7 +87,7 @@ static void pcap_ts_read_xy(void *data, u16 res[2])
static void pcap_ts_work(struct work_struct *work) static void pcap_ts_work(struct work_struct *work)
{ {
struct delayed_work *dw = container_of(work, struct delayed_work, work); struct delayed_work *dw = to_delayed_work(work);
struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work); struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work);
u8 ch[2]; u8 ch[2];
......
...@@ -38,6 +38,8 @@ struct pixcir_i2c_ts_data { ...@@ -38,6 +38,8 @@ struct pixcir_i2c_ts_data {
struct input_dev *input; struct input_dev *input;
struct gpio_desc *gpio_attb; struct gpio_desc *gpio_attb;
struct gpio_desc *gpio_reset; struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_enable;
struct gpio_desc *gpio_wake;
const struct pixcir_i2c_chip_data *chip; const struct pixcir_i2c_chip_data *chip;
int max_fingers; /* Max fingers supported in this instance */ int max_fingers; /* Max fingers supported in this instance */
bool running; bool running;
...@@ -208,6 +210,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, ...@@ -208,6 +210,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
struct device *dev = &ts->client->dev; struct device *dev = &ts->client->dev;
int ret; int ret;
if (mode == PIXCIR_POWER_ACTIVE || mode == PIXCIR_POWER_IDLE) {
if (ts->gpio_wake)
gpiod_set_value_cansleep(ts->gpio_wake, 1);
}
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE); ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: can't read reg 0x%x : %d\n", dev_err(dev, "%s: can't read reg 0x%x : %d\n",
...@@ -228,6 +235,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, ...@@ -228,6 +235,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
return ret; return ret;
} }
if (mode == PIXCIR_POWER_HALT) {
if (ts->gpio_wake)
gpiod_set_value_cansleep(ts->gpio_wake, 0);
}
return 0; return 0;
} }
...@@ -302,6 +314,11 @@ static int pixcir_start(struct pixcir_i2c_ts_data *ts) ...@@ -302,6 +314,11 @@ static int pixcir_start(struct pixcir_i2c_ts_data *ts)
struct device *dev = &ts->client->dev; struct device *dev = &ts->client->dev;
int error; int error;
if (ts->gpio_enable) {
gpiod_set_value_cansleep(ts->gpio_enable, 1);
msleep(100);
}
/* LEVEL_TOUCH interrupt with active low polarity */ /* LEVEL_TOUCH interrupt with active low polarity */
error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0); error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
if (error) { if (error) {
...@@ -343,6 +360,9 @@ static int pixcir_stop(struct pixcir_i2c_ts_data *ts) ...@@ -343,6 +360,9 @@ static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
/* Wait till running ISR is complete */ /* Wait till running ISR is complete */
synchronize_irq(ts->client->irq); synchronize_irq(ts->client->irq);
if (ts->gpio_enable)
gpiod_set_value_cansleep(ts->gpio_enable, 0);
return 0; return 0;
} }
...@@ -534,6 +554,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, ...@@ -534,6 +554,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
return error; return error;
} }
tsdata->gpio_wake = devm_gpiod_get_optional(dev, "wake",
GPIOD_OUT_HIGH);
if (IS_ERR(tsdata->gpio_wake)) {
error = PTR_ERR(tsdata->gpio_wake);
if (error != -EPROBE_DEFER)
dev_err(dev, "Failed to get wake gpio: %d\n", error);
return error;
}
tsdata->gpio_enable = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_HIGH);
if (IS_ERR(tsdata->gpio_enable)) {
error = PTR_ERR(tsdata->gpio_enable);
if (error != -EPROBE_DEFER)
dev_err(dev, "Failed to get enable gpio: %d\n", error);
return error;
}
if (tsdata->gpio_enable)
msleep(100);
error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata); client->name, tsdata);
......
...@@ -725,7 +725,7 @@ static int rohm_ts_load_firmware(struct i2c_client *client, ...@@ -725,7 +725,7 @@ static int rohm_ts_load_firmware(struct i2c_client *client,
break; break;
error = -EIO; error = -EIO;
} while (++retry >= FIRMWARE_RETRY_MAX); } while (++retry <= FIRMWARE_RETRY_MAX);
out: out:
error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL); error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
......
...@@ -273,8 +273,6 @@ static irqreturn_t titsc_irq(int irq, void *dev) ...@@ -273,8 +273,6 @@ static irqreturn_t titsc_irq(int irq, void *dev)
status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); status = titsc_readl(ts_dev, REG_RAWIRQSTATUS);
if (status & IRQENB_HW_PEN) { if (status & IRQENB_HW_PEN) {
ts_dev->pen_down = true; ts_dev->pen_down = true;
titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00);
titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
irqclr |= IRQENB_HW_PEN; irqclr |= IRQENB_HW_PEN;
} }
......
/*
* Touchscreen driver for the TS-4800 board
*
* Copyright (c) 2015 - Savoir-faire Linux
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/bitops.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* polling interval in ms */
#define POLL_INTERVAL 3
#define DEBOUNCE_COUNT 1
/* sensor values are 12-bit wide */
#define MAX_12BIT ((1 << 12) - 1)
#define PENDOWN_MASK 0x1
#define X_OFFSET 0x0
#define Y_OFFSET 0x2
struct ts4800_ts {
struct input_polled_dev *poll_dev;
struct device *dev;
char phys[32];
void __iomem *base;
struct regmap *regmap;
unsigned int reg;
unsigned int bit;
bool pendown;
int debounce;
};
static void ts4800_ts_open(struct input_polled_dev *dev)
{
struct ts4800_ts *ts = dev->private;
int ret;
ts->pendown = false;
ts->debounce = DEBOUNCE_COUNT;
ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, ts->bit);
if (ret)
dev_warn(ts->dev, "Failed to enable touchscreen\n");
}
static void ts4800_ts_close(struct input_polled_dev *dev)
{
struct ts4800_ts *ts = dev->private;
int ret;
ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, 0);
if (ret)
dev_warn(ts->dev, "Failed to disable touchscreen\n");
}
static void ts4800_ts_poll(struct input_polled_dev *dev)
{
struct input_dev *input_dev = dev->input;
struct ts4800_ts *ts = dev->private;
u16 last_x = readw(ts->base + X_OFFSET);
u16 last_y = readw(ts->base + Y_OFFSET);
bool pendown = last_x & PENDOWN_MASK;
if (pendown) {
if (ts->debounce) {
ts->debounce--;
return;
}
if (!ts->pendown) {
input_report_key(input_dev, BTN_TOUCH, 1);
ts->pendown = true;
}
last_x = ((~last_x) >> 4) & MAX_12BIT;
last_y = ((~last_y) >> 4) & MAX_12BIT;
input_report_abs(input_dev, ABS_X, last_x);
input_report_abs(input_dev, ABS_Y, last_y);
input_sync(input_dev);
} else if (ts->pendown) {
ts->pendown = false;
ts->debounce = DEBOUNCE_COUNT;
input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
}
}
static int ts4800_parse_dt(struct platform_device *pdev,
struct ts4800_ts *ts)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *syscon_np;
u32 reg, bit;
int error;
syscon_np = of_parse_phandle(np, "syscon", 0);
if (!syscon_np) {
dev_err(dev, "no syscon property\n");
return -ENODEV;
}
error = of_property_read_u32_index(np, "syscon", 1, &reg);
if (error < 0) {
dev_err(dev, "no offset in syscon\n");
return error;
}
ts->reg = reg;
error = of_property_read_u32_index(np, "syscon", 2, &bit);
if (error < 0) {
dev_err(dev, "no bit in syscon\n");
return error;
}
ts->bit = BIT(bit);
ts->regmap = syscon_node_to_regmap(syscon_np);
if (IS_ERR(ts->regmap)) {
dev_err(dev, "cannot get parent's regmap\n");
return PTR_ERR(ts->regmap);
}
return 0;
}
static int ts4800_ts_probe(struct platform_device *pdev)
{
struct input_polled_dev *poll_dev;
struct ts4800_ts *ts;
struct resource *res;
int error;
ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
error = ts4800_parse_dt(pdev, ts);
if (error)
return error;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ts->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ts->base))
return PTR_ERR(ts->base);
poll_dev = devm_input_allocate_polled_device(&pdev->dev);
if (!poll_dev)
return -ENOMEM;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&pdev->dev));
ts->poll_dev = poll_dev;
ts->dev = &pdev->dev;
poll_dev->private = ts;
poll_dev->poll_interval = POLL_INTERVAL;
poll_dev->open = ts4800_ts_open;
poll_dev->close = ts4800_ts_close;
poll_dev->poll = ts4800_ts_poll;
poll_dev->input->name = "TS-4800 Touchscreen";
poll_dev->input->phys = ts->phys;
input_set_capability(poll_dev->input, EV_KEY, BTN_TOUCH);
input_set_abs_params(poll_dev->input, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(poll_dev->input, ABS_Y, 0, MAX_12BIT, 0, 0);
error = input_register_polled_device(poll_dev);
if (error) {
dev_err(&pdev->dev,
"Unabled to register polled input device (%d)\n",
error);
return error;
}
return 0;
}
static const struct of_device_id ts4800_ts_of_match[] = {
{ .compatible = "technologic,ts4800-ts", },
{ },
};
MODULE_DEVICE_TABLE(of, ts4800_ts_of_match);
static struct platform_driver ts4800_ts_driver = {
.driver = {
.name = "ts4800-ts",
.of_match_table = ts4800_ts_of_match,
},
.probe = ts4800_ts_probe,
};
module_platform_driver(ts4800_ts_driver);
MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
MODULE_DESCRIPTION("TS-4800 Touchscreen Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:ts4800_ts");
...@@ -80,7 +80,8 @@ struct w8001_touch_query { ...@@ -80,7 +80,8 @@ struct w8001_touch_query {
*/ */
struct w8001 { struct w8001 {
struct input_dev *dev; struct input_dev *pen_dev;
struct input_dev *touch_dev;
struct serio *serio; struct serio *serio;
struct completion cmd_done; struct completion cmd_done;
int id; int id;
...@@ -95,7 +96,10 @@ struct w8001 { ...@@ -95,7 +96,10 @@ struct w8001 {
u16 max_touch_y; u16 max_touch_y;
u16 max_pen_x; u16 max_pen_x;
u16 max_pen_y; u16 max_pen_y;
char name[64]; char pen_name[64];
char touch_name[64];
int open_count;
struct mutex mutex;
}; };
static void parse_pen_data(u8 *data, struct w8001_coord *coord) static void parse_pen_data(u8 *data, struct w8001_coord *coord)
...@@ -141,7 +145,7 @@ static void scale_touch_coordinates(struct w8001 *w8001, ...@@ -141,7 +145,7 @@ static void scale_touch_coordinates(struct w8001 *w8001,
static void parse_multi_touch(struct w8001 *w8001) static void parse_multi_touch(struct w8001 *w8001)
{ {
struct input_dev *dev = w8001->dev; struct input_dev *dev = w8001->touch_dev;
unsigned char *data = w8001->data; unsigned char *data = w8001->data;
unsigned int x, y; unsigned int x, y;
int i; int i;
...@@ -151,7 +155,6 @@ static void parse_multi_touch(struct w8001 *w8001) ...@@ -151,7 +155,6 @@ static void parse_multi_touch(struct w8001 *w8001)
bool touch = data[0] & (1 << i); bool touch = data[0] & (1 << i);
input_mt_slot(dev, i); input_mt_slot(dev, i);
input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
if (touch) { if (touch) {
x = (data[6 * i + 1] << 7) | data[6 * i + 2]; x = (data[6 * i + 1] << 7) | data[6 * i + 2];
y = (data[6 * i + 3] << 7) | data[6 * i + 4]; y = (data[6 * i + 3] << 7) | data[6 * i + 4];
...@@ -207,7 +210,7 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query) ...@@ -207,7 +210,7 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
{ {
struct input_dev *dev = w8001->dev; struct input_dev *dev = w8001->pen_dev;
/* /*
* We have 1 bit for proximity (rdy) and 3 bits for tip, side, * We have 1 bit for proximity (rdy) and 3 bits for tip, side,
...@@ -233,11 +236,6 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) ...@@ -233,11 +236,6 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
break; break;
case BTN_TOOL_FINGER: case BTN_TOOL_FINGER:
input_report_key(dev, BTN_TOUCH, 0);
input_report_key(dev, BTN_TOOL_FINGER, 0);
input_sync(dev);
/* fall through */
case KEY_RESERVED: case KEY_RESERVED:
w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
break; break;
...@@ -261,7 +259,7 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) ...@@ -261,7 +259,7 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord) static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
{ {
struct input_dev *dev = w8001->dev; struct input_dev *dev = w8001->touch_dev;
unsigned int x = coord->x; unsigned int x = coord->x;
unsigned int y = coord->y; unsigned int y = coord->y;
...@@ -271,7 +269,6 @@ static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord) ...@@ -271,7 +269,6 @@ static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
input_report_abs(dev, ABS_X, x); input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y); input_report_abs(dev, ABS_Y, y);
input_report_key(dev, BTN_TOUCH, coord->tsw); input_report_key(dev, BTN_TOUCH, coord->tsw);
input_report_key(dev, BTN_TOOL_FINGER, coord->tsw);
input_sync(dev); input_sync(dev);
...@@ -369,22 +366,36 @@ static int w8001_command(struct w8001 *w8001, unsigned char command, ...@@ -369,22 +366,36 @@ static int w8001_command(struct w8001 *w8001, unsigned char command,
static int w8001_open(struct input_dev *dev) static int w8001_open(struct input_dev *dev)
{ {
struct w8001 *w8001 = input_get_drvdata(dev); struct w8001 *w8001 = input_get_drvdata(dev);
int err;
return w8001_command(w8001, W8001_CMD_START, false); err = mutex_lock_interruptible(&w8001->mutex);
if (err)
return err;
if (w8001->open_count++ == 0) {
err = w8001_command(w8001, W8001_CMD_START, false);
if (err)
w8001->open_count--;
}
mutex_unlock(&w8001->mutex);
return err;
} }
static void w8001_close(struct input_dev *dev) static void w8001_close(struct input_dev *dev)
{ {
struct w8001 *w8001 = input_get_drvdata(dev); struct w8001 *w8001 = input_get_drvdata(dev);
mutex_lock(&w8001->mutex);
if (--w8001->open_count == 0)
w8001_command(w8001, W8001_CMD_STOP, false); w8001_command(w8001, W8001_CMD_STOP, false);
mutex_unlock(&w8001->mutex);
} }
static int w8001_setup(struct w8001 *w8001) static int w8001_detect(struct w8001 *w8001)
{ {
struct input_dev *dev = w8001->dev;
struct w8001_coord coord;
struct w8001_touch_query touch;
int error; int error;
error = w8001_command(w8001, W8001_CMD_STOP, false); error = w8001_command(w8001, W8001_CMD_STOP, false);
...@@ -393,19 +404,29 @@ static int w8001_setup(struct w8001 *w8001) ...@@ -393,19 +404,29 @@ static int w8001_setup(struct w8001 *w8001)
msleep(250); /* wait 250ms before querying the device */ msleep(250); /* wait 250ms before querying the device */
dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); return 0;
strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name)); }
__set_bit(INPUT_PROP_DIRECT, dev->propbit); static int w8001_setup_pen(struct w8001 *w8001, char *basename,
size_t basename_sz)
{
struct input_dev *dev = w8001->pen_dev;
struct w8001_coord coord;
int error;
/* penabled? */ /* penabled? */
error = w8001_command(w8001, W8001_CMD_QUERY, true); error = w8001_command(w8001, W8001_CMD_QUERY, true);
if (!error) { if (error)
return error;
__set_bit(EV_KEY, dev->evbit);
__set_bit(EV_ABS, dev->evbit);
__set_bit(BTN_TOUCH, dev->keybit); __set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_PEN, dev->keybit); __set_bit(BTN_TOOL_PEN, dev->keybit);
__set_bit(BTN_TOOL_RUBBER, dev->keybit); __set_bit(BTN_TOOL_RUBBER, dev->keybit);
__set_bit(BTN_STYLUS, dev->keybit); __set_bit(BTN_STYLUS, dev->keybit);
__set_bit(BTN_STYLUS2, dev->keybit); __set_bit(BTN_STYLUS2, dev->keybit);
__set_bit(INPUT_PROP_DIRECT, dev->propbit);
parse_pen_data(w8001->response, &coord); parse_pen_data(w8001->response, &coord);
w8001->max_pen_x = coord.x; w8001->max_pen_x = coord.x;
...@@ -420,20 +441,36 @@ static int w8001_setup(struct w8001 *w8001) ...@@ -420,20 +441,36 @@ static int w8001_setup(struct w8001 *w8001)
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
} }
w8001->id = 0x90; w8001->id = 0x90;
strlcat(w8001->name, " Penabled", sizeof(w8001->name)); strlcat(basename, " Penabled", basename_sz);
}
return 0;
}
static int w8001_setup_touch(struct w8001 *w8001, char *basename,
size_t basename_sz)
{
struct input_dev *dev = w8001->touch_dev;
struct w8001_touch_query touch;
int error;
/* Touch enabled? */ /* Touch enabled? */
error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true); error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
if (error)
return error;
/* /*
* Some non-touch devices may reply to the touch query. But their * Some non-touch devices may reply to the touch query. But their
* second byte is empty, which indicates touch is not supported. * second byte is empty, which indicates touch is not supported.
*/ */
if (!error && w8001->response[1]) { if (!w8001->response[1])
return -ENXIO;
__set_bit(EV_KEY, dev->evbit);
__set_bit(EV_ABS, dev->evbit);
__set_bit(BTN_TOUCH, dev->keybit); __set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_FINGER, dev->keybit); __set_bit(INPUT_PROP_DIRECT, dev->propbit);
parse_touchquery(w8001->response, &touch); parse_touchquery(w8001->response, &touch);
w8001->max_touch_x = touch.x; w8001->max_touch_x = touch.x;
...@@ -456,42 +493,56 @@ static int w8001_setup(struct w8001 *w8001) ...@@ -456,42 +493,56 @@ static int w8001_setup(struct w8001 *w8001)
case 2: case 2:
w8001->pktlen = W8001_PKTLEN_TOUCH93; w8001->pktlen = W8001_PKTLEN_TOUCH93;
w8001->id = 0x93; w8001->id = 0x93;
strlcat(w8001->name, " 1FG", sizeof(w8001->name)); strlcat(basename, " 1FG", basename_sz);
break; break;
case 1: case 1:
case 3: case 3:
case 4: case 4:
w8001->pktlen = W8001_PKTLEN_TOUCH9A; w8001->pktlen = W8001_PKTLEN_TOUCH9A;
strlcat(w8001->name, " 1FG", sizeof(w8001->name)); strlcat(basename, " 1FG", basename_sz);
w8001->id = 0x9a; w8001->id = 0x9a;
break; break;
case 5: case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG; w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
input_mt_init_slots(dev, 2, 0); input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, input_set_abs_params(dev, ABS_MT_POSITION_X,
0, touch.x, 0, 0); 0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, input_set_abs_params(dev, ABS_MT_POSITION_Y,
0, touch.y, 0, 0); 0, touch.y, 0, 0);
input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
strlcat(w8001->name, " 2FG", sizeof(w8001->name)); strlcat(basename, " 2FG", basename_sz);
if (w8001->max_pen_x && w8001->max_pen_y) if (w8001->max_pen_x && w8001->max_pen_y)
w8001->id = 0xE3; w8001->id = 0xE3;
else else
w8001->id = 0xE2; w8001->id = 0xE2;
break; break;
} }
}
strlcat(w8001->name, " Touchscreen", sizeof(w8001->name)); strlcat(basename, " Touchscreen", basename_sz);
return 0; return 0;
} }
static void w8001_set_devdata(struct input_dev *dev, struct w8001 *w8001,
struct serio *serio)
{
dev->phys = w8001->phys;
dev->id.bustype = BUS_RS232;
dev->id.product = w8001->id;
dev->id.vendor = 0x056a;
dev->id.version = 0x0100;
dev->open = w8001_open;
dev->close = w8001_close;
dev->dev.parent = &serio->dev;
input_set_drvdata(dev, w8001);
}
/* /*
* w8001_disconnect() is the opposite of w8001_connect() * w8001_disconnect() is the opposite of w8001_connect()
*/ */
...@@ -502,7 +553,10 @@ static void w8001_disconnect(struct serio *serio) ...@@ -502,7 +553,10 @@ static void w8001_disconnect(struct serio *serio)
serio_close(serio); serio_close(serio);
input_unregister_device(w8001->dev); if (w8001->pen_dev)
input_unregister_device(w8001->pen_dev);
if (w8001->touch_dev)
input_unregister_device(w8001->touch_dev);
kfree(w8001); kfree(w8001);
serio_set_drvdata(serio, NULL); serio_set_drvdata(serio, NULL);
...@@ -517,18 +571,23 @@ static void w8001_disconnect(struct serio *serio) ...@@ -517,18 +571,23 @@ static void w8001_disconnect(struct serio *serio)
static int w8001_connect(struct serio *serio, struct serio_driver *drv) static int w8001_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct w8001 *w8001; struct w8001 *w8001;
struct input_dev *input_dev; struct input_dev *input_dev_pen;
int err; struct input_dev *input_dev_touch;
char basename[64];
int err, err_pen, err_touch;
w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL); w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL);
input_dev = input_allocate_device(); input_dev_pen = input_allocate_device();
if (!w8001 || !input_dev) { input_dev_touch = input_allocate_device();
if (!w8001 || !input_dev_pen || !input_dev_touch) {
err = -ENOMEM; err = -ENOMEM;
goto fail1; goto fail1;
} }
w8001->serio = serio; w8001->serio = serio;
w8001->dev = input_dev; w8001->pen_dev = input_dev_pen;
w8001->touch_dev = input_dev_touch;
mutex_init(&w8001->mutex);
init_completion(&w8001->cmd_done); init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
...@@ -537,35 +596,67 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) ...@@ -537,35 +596,67 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
if (err) if (err)
goto fail2; goto fail2;
err = w8001_setup(w8001); err = w8001_detect(w8001);
if (err) if (err)
goto fail3; goto fail3;
input_dev->name = w8001->name; /* For backwards-compatibility we compose the basename based on
input_dev->phys = w8001->phys; * capabilities and then just append the tool type
input_dev->id.product = w8001->id; */
input_dev->id.bustype = BUS_RS232; strlcpy(basename, "Wacom Serial", sizeof(basename));
input_dev->id.vendor = 0x056a;
input_dev->id.version = 0x0100; err_pen = w8001_setup_pen(w8001, basename, sizeof(basename));
input_dev->dev.parent = &serio->dev; err_touch = w8001_setup_touch(w8001, basename, sizeof(basename));
if (err_pen && err_touch) {
err = -ENXIO;
goto fail3;
}
input_dev->open = w8001_open; if (!err_pen) {
input_dev->close = w8001_close; strlcpy(w8001->pen_name, basename, sizeof(w8001->pen_name));
strlcat(w8001->pen_name, " Pen", sizeof(w8001->pen_name));
input_dev_pen->name = w8001->pen_name;
input_set_drvdata(input_dev, w8001); w8001_set_devdata(input_dev_pen, w8001, serio);
err = input_register_device(w8001->dev); err = input_register_device(w8001->pen_dev);
if (err) if (err)
goto fail3; goto fail3;
} else {
input_free_device(input_dev_pen);
input_dev_pen = NULL;
w8001->pen_dev = NULL;
}
if (!err_touch) {
strlcpy(w8001->touch_name, basename, sizeof(w8001->touch_name));
strlcat(w8001->touch_name, " Finger",
sizeof(w8001->touch_name));
input_dev_touch->name = w8001->touch_name;
w8001_set_devdata(input_dev_touch, w8001, serio);
err = input_register_device(w8001->touch_dev);
if (err)
goto fail4;
} else {
input_free_device(input_dev_touch);
input_dev_touch = NULL;
w8001->touch_dev = NULL;
}
return 0; return 0;
fail4:
if (w8001->pen_dev)
input_unregister_device(w8001->pen_dev);
fail3: fail3:
serio_close(serio); serio_close(serio);
fail2: fail2:
serio_set_drvdata(serio, NULL); serio_set_drvdata(serio, NULL);
fail1: fail1:
input_free_device(input_dev); input_free_device(input_dev_pen);
input_free_device(input_dev_touch);
kfree(w8001); kfree(w8001);
return err; return err;
} }
......
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
* *
* Changes/Revisions: * Changes/Revisions:
* 0.5 08/13/2015 (David Herrmann <dh.herrmann@gmail.com> &
* Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_DEV_SETUP ioctl
* - add UI_ABS_SETUP ioctl
* - add UI_GET_VERSION ioctl
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>) * 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl * - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>) * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
......
...@@ -77,5 +77,6 @@ ...@@ -77,5 +77,6 @@
#define SERIO_PS2MULT 0x3c #define SERIO_PS2MULT 0x3c
#define SERIO_TSC40 0x3d #define SERIO_TSC40 0x3d
#define SERIO_WACOM_IV 0x3e #define SERIO_WACOM_IV 0x3e
#define SERIO_EGALAX 0x3f
#endif /* _UAPI_SERIO_H */ #endif /* _UAPI_SERIO_H */
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
* *
* Changes/Revisions: * Changes/Revisions:
* 0.5 08/13/2015 (David Herrmann <dh.herrmann@gmail.com> &
* Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_DEV_SETUP ioctl
* - add UI_ABS_SETUP ioctl
* - add UI_GET_VERSION ioctl
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>) * 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl * - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>) * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
...@@ -37,8 +42,8 @@ ...@@ -37,8 +42,8 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/input.h> #include <linux/input.h>
#define UINPUT_VERSION 4 #define UINPUT_VERSION 5
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_ff_upload { struct uinput_ff_upload {
__u32 request_id; __u32 request_id;
...@@ -58,6 +63,76 @@ struct uinput_ff_erase { ...@@ -58,6 +63,76 @@ struct uinput_ff_erase {
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1) #define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2) #define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
struct uinput_setup {
struct input_id id;
char name[UINPUT_MAX_NAME_SIZE];
__u32 ff_effects_max;
};
/**
* UI_DEV_SETUP - Set device parameters for setup
*
* This ioctl sets parameters for the input device to be created. It
* supersedes the old "struct uinput_user_dev" method, which wrote this data
* via write(). To actually set the absolute axes UI_ABS_SETUP should be
* used.
*
* The ioctl takes a "struct uinput_setup" object as argument. The fields of
* this object are as follows:
* id: See the description of "struct input_id". This field is
* copied unchanged into the new device.
* name: This is used unchanged as name for the new device.
* ff_effects_max: This limits the maximum numbers of force-feedback effects.
* See below for a description of FF with uinput.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_DEV_SETUP _IOW(UINPUT_IOCTL_BASE, 3, struct uinput_setup)
struct uinput_abs_setup {
__u16 code; /* axis code */
/* __u16 filler; */
struct input_absinfo absinfo;
};
/**
* UI_ABS_SETUP - Set absolute axis information for the device to setup
*
* This ioctl sets one absolute axis information for the input device to be
* created. It supersedes the old "struct uinput_user_dev" method, which wrote
* part of this data and the content of UI_DEV_SETUP via write().
*
* The ioctl takes a "struct uinput_abs_setup" object as argument. The fields
* of this object are as follows:
* code: The corresponding input code associated with this axis
* (ABS_X, ABS_Y, etc...)
* absinfo: See "struct input_absinfo" for a description of this field.
* This field is copied unchanged into the kernel for the
* specified axis. If the axis is not enabled via
* UI_SET_ABSBIT, this ioctl will enable it.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_ABS_SETUP _IOW(UINPUT_IOCTL_BASE, 4, struct uinput_abs_setup)
#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) #define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) #define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) #define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
...@@ -144,7 +219,6 @@ struct uinput_ff_erase { ...@@ -144,7 +219,6 @@ struct uinput_ff_erase {
#define UI_FF_UPLOAD 1 #define UI_FF_UPLOAD 1
#define UI_FF_ERASE 2 #define UI_FF_ERASE 2
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_user_dev { struct uinput_user_dev {
char name[UINPUT_MAX_NAME_SIZE]; char name[UINPUT_MAX_NAME_SIZE];
struct input_id id; struct input_id id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment