Skip to content

Commit

Permalink
Input: wacom - share pen info with touch of the same ID
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Ping Cheng authored and Dmitry Torokhov committed Apr 14, 2010
1 parent 3b57ca0 commit 4492eff
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 22 deletions.
83 changes: 82 additions & 1 deletion drivers/input/tablet/wacom_sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -624,14 +703,15 @@ 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);

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);
Expand All @@ -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);
}
Expand Down
33 changes: 12 additions & 21 deletions drivers/input/tablet/wacom_wac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand All @@ -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);
Expand All @@ -727,30 +722,28 @@ 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;
if (wacom->tool[0] == BTN_TOOL_PEN)
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);
Expand All @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions drivers/input/tablet/wacom_wac.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,18 @@ struct wacom_features {
unsigned char unitExpo;
};

struct wacom_shared {
bool stylus_in_proximity;
};

struct wacom_wac {
char name[64];
unsigned char *data;
int tool[2];
int id[2];
__u32 serial[2];
struct wacom_features features;
struct wacom_shared *shared;
};

#endif

0 comments on commit 4492eff

Please sign in to comment.