diff options
author | Ping Cheng <pingc@wacom.com> | 2010-03-20 06:18:15 +0100 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-04-14 08:24:06 +0200 |
commit | 4492efffffeb88d87e7aa74765f3c53b3a7dd40f (patch) | |
tree | 258b17da4faf0934efb8bc63a5163d77e047dbc8 | |
parent | Input: wacom - merge out and in prox events (diff) | |
download | linux-4492efffffeb88d87e7aa74765f3c53b3a7dd40f.tar.xz linux-4492efffffeb88d87e7aa74765f3c53b3a7dd40f.zip |
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.
-rw-r--r-- | drivers/input/tablet/wacom_sys.c | 83 | ||||
-rw-r--r-- | drivers/input/tablet/wacom_wac.c | 33 | ||||
-rw-r--r-- | drivers/input/tablet/wacom_wac.h | 5 |
3 files changed, 99 insertions, 22 deletions
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 |