From 4492efffffeb88d87e7aa74765f3c53b3a7dd40f Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Fri, 19 Mar 2010 22:18:15 -0700 Subject: Input: wacom - share pen info with touch of the same ID Touch enbaled devices share the same product ID with pen. However, we do not want to post touch events while pen is in prox. To do so, we used to keep a local static variable to keep track of if pen is in prox or not. This works fine for Tablet PC devices since there is only one device attached. With the newer touch enabled regular tablets, we can not make this assumption any more, i.e, one system may have more than one identical tablet plugged in. This patch adds an new entry, shared, into the struct wacom_wac so touch data can access pen data to locally. This solution assumes the two tools (touch and pen) of the same ID will be probed one after the other without interruption in between by another Wacom device of the same ID. --- drivers/input/tablet/wacom_sys.c | 83 +++++++++++++++++++++++++++++++++++++++- drivers/input/tablet/wacom_wac.c | 33 ++++++---------- drivers/input/tablet/wacom_wac.h | 5 +++ 3 files changed, 99 insertions(+), 22 deletions(-) (limited to 'drivers/input/tablet') diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index f46502589e4e..a03ca219d49f 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -528,6 +528,81 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, return error; } +struct wacom_usbdev_data { + struct list_head list; + struct kref kref; + struct usb_device *dev; + struct wacom_shared shared; +}; + +static LIST_HEAD(wacom_udev_list); +static DEFINE_MUTEX(wacom_udev_list_lock); + +static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev) +{ + struct wacom_usbdev_data *data; + + list_for_each_entry(data, &wacom_udev_list, list) { + if (data->dev == dev) { + kref_get(&data->kref); + return data; + } + } + + return NULL; +} + +static int wacom_add_shared_data(struct wacom_wac *wacom, + struct usb_device *dev) +{ + struct wacom_usbdev_data *data; + int retval = 0; + + mutex_lock(&wacom_udev_list_lock); + + data = wacom_get_usbdev_data(dev); + if (!data) { + data = kzalloc(sizeof(struct wacom_usbdev_data), GFP_KERNEL); + if (!data) { + retval = -ENOMEM; + goto out; + } + + kref_init(&data->kref); + data->dev = dev; + list_add_tail(&data->list, &wacom_udev_list); + } + + wacom->shared = &data->shared; + +out: + mutex_unlock(&wacom_udev_list_lock); + return retval; +} + +static void wacom_release_shared_data(struct kref *kref) +{ + struct wacom_usbdev_data *data = + container_of(kref, struct wacom_usbdev_data, kref); + + mutex_lock(&wacom_udev_list_lock); + list_del(&data->list); + mutex_unlock(&wacom_udev_list_lock); + + kfree(data); +} + +static void wacom_remove_shared_data(struct wacom_wac *wacom) +{ + struct wacom_usbdev_data *data; + + if (wacom->shared) { + data = container_of(wacom->shared, struct wacom_usbdev_data, shared); + kref_put(&data->kref, wacom_release_shared_data); + wacom->shared = NULL; + } +} + static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); @@ -600,6 +675,10 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i features->device_type == BTN_TOOL_PEN ? " Pen" : " Finger", sizeof(wacom_wac->name)); + + error = wacom_add_shared_data(wacom_wac, dev); + if (error) + goto fail3; } input_dev->name = wacom_wac->name; @@ -624,7 +703,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i error = input_register_device(wacom->dev); if (error) - goto fail3; + goto fail4; /* Note that if query fails it is not a hard failure */ wacom_query_tablet_data(intf, features); @@ -632,6 +711,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i usb_set_intfdata(intf, wacom); return 0; + fail4: wacom_remove_shared_data(wacom_wac); fail3: usb_free_urb(wacom->irq); fail2: usb_buffer_free(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); fail1: input_free_device(input_dev); @@ -651,6 +731,7 @@ static void wacom_disconnect(struct usb_interface *intf) usb_free_urb(wacom->irq); usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX, wacom->wacom_wac->data, wacom->data_dma); + wacom_remove_shared_data(wacom->wacom_wac); kfree(wacom->wacom_wac); kfree(wacom); } diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index b3ba3437a2eb..428144af865f 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -688,7 +688,6 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) struct wacom_features *features = &wacom->features; char *data = wacom->data; int prox = 0, pressure, idx = -1; - static int stylusInProx, touchInProx = 1, touchOut; struct urb *urb = ((struct wacom_combo *)wcombo)->urb; dbg("wacom_tpc_irq: received report #%d", data[0]); @@ -707,16 +706,12 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) prox = data[1] & 0x03; } - if (!stylusInProx) { /* stylus not in prox */ + if (!wacom->shared->stylus_in_proximity) { if (prox) { - if (touchInProx) { - wacom_tpc_touch_in(wacom, wcombo); - touchOut = 1; - return 1; - } + wacom_tpc_touch_in(wacom, wcombo); } else { - /* 2FGT out-prox */ if (data[0] == WACOM_REPORT_TPC2FG) { + /* 2FGT out-prox */ idx = (wacom->id[1] & 0x01) - 1; if (idx == 0) { wacom_tpc_touch_out(wacom, wcombo, idx); @@ -727,23 +722,19 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) idx = (wacom->id[1] & 0x02) - 1; if (idx == 1) wacom_tpc_touch_out(wacom, wcombo, idx); - } else /* one finger touch */ + } else { + /* one finger touch */ wacom_tpc_touch_out(wacom, wcombo, 0); - touchOut = 0; - touchInProx = 1; - return 1; + } + wacom->id[0] = 0; } - } else if (touchOut || !prox) { /* force touch out-prox */ + } else if (wacom->id[0]) { /* force touch out-prox */ wacom_tpc_touch_out(wacom, wcombo, 0); - touchOut = 0; - touchInProx = 1; - return 1; } + return 1; } else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */ prox = data[1] & 0x20; - touchInProx = 0; - if (!wacom->id[0]) { /* first in prox */ /* Going into proximity select tool */ wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; @@ -751,6 +742,8 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) wacom->id[0] = STYLUS_DEVICE_ID; else wacom->id[0] = ERASER_DEVICE_ID; + + wacom->shared->stylus_in_proximity = true; } wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02); wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10); @@ -763,12 +756,10 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05); if (!prox) { /* out-prox */ wacom->id[0] = 0; - /* pen is out so touch can be enabled now */ - touchInProx = 1; + wacom->shared->stylus_in_proximity = false; } wacom_report_key(wcombo, wacom->tool[0], prox); wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); - stylusInProx = prox; return 1; } return 0; diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index b50cf04e61a8..4b55fc7ad8ae 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -71,6 +71,10 @@ struct wacom_features { unsigned char unitExpo; }; +struct wacom_shared { + bool stylus_in_proximity; +}; + struct wacom_wac { char name[64]; unsigned char *data; @@ -78,6 +82,7 @@ struct wacom_wac { int id[2]; __u32 serial[2]; struct wacom_features features; + struct wacom_shared *shared; }; #endif -- cgit v1.2.3-58-ga151