235 lines
7.5 KiB
Diff
235 lines
7.5 KiB
Diff
From: Chris Bagwell <chris@cnpbagwell.com>
|
|
Date: Sun, 25 Mar 2012 23:26:20 -0700
|
|
Subject: Input: wacom - create inputs when wireless connect
|
|
|
|
commit 16bf288c4be67b68c3fcb6561ff145702cb7bd22 upstream.
|
|
|
|
When a tablet connect or disconnect is detected, schedule
|
|
work queue to register or unregister related input devices.
|
|
|
|
When a wireless tablet connects, it reports same USB PID
|
|
used if tablet is connected with USB cable. Use this to
|
|
update features values, set input capabilities, and then
|
|
register device. From there, the Pen and Touch interfaces
|
|
will reuse the existing tablet's IRQ routines.
|
|
|
|
Its possible that 1 receiver is shared with 2 tablets with
|
|
different PID (small and medium Bamboo for example) so the
|
|
input is unregister at disconnect to better support this case.
|
|
|
|
Signed-off-by: Chris Bagwell <chris@cnpbagwell.com>
|
|
Tested-by: Jason Gerecke <killertofu@gmail.com>
|
|
Acked-by: Ping Cheng <pingc@wacom.com>
|
|
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
|
|
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
|
|
---
|
|
drivers/input/tablet/wacom.h | 7 +++
|
|
drivers/input/tablet/wacom_sys.c | 91 ++++++++++++++++++++++++++++++++++----
|
|
drivers/input/tablet/wacom_wac.c | 20 ++++++++-
|
|
drivers/input/tablet/wacom_wac.h | 1 +
|
|
4 files changed, 109 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
|
|
index 0783864a7dc2..febbfd9f3a84 100644
|
|
--- a/drivers/input/tablet/wacom.h
|
|
+++ b/drivers/input/tablet/wacom.h
|
|
@@ -112,6 +112,7 @@ struct wacom {
|
|
struct urb *irq;
|
|
struct wacom_wac wacom_wac;
|
|
struct mutex lock;
|
|
+ struct work_struct work;
|
|
bool open;
|
|
char phys[32];
|
|
struct wacom_led {
|
|
@@ -122,6 +123,12 @@ struct wacom {
|
|
} led;
|
|
};
|
|
|
|
+static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
|
|
+{
|
|
+ struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
|
|
+ schedule_work(&wacom->work);
|
|
+}
|
|
+
|
|
extern const struct usb_device_id wacom_ids[];
|
|
|
|
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
|
|
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
|
|
index 223246575860..1bcf555ff340 100644
|
|
--- a/drivers/input/tablet/wacom_sys.c
|
|
+++ b/drivers/input/tablet/wacom_sys.c
|
|
@@ -167,6 +167,19 @@ static void wacom_close(struct input_dev *dev)
|
|
usb_autopm_put_interface(wacom->intf);
|
|
}
|
|
|
|
+/*
|
|
+ * Static values for max X/Y and resolution of Pen interface is stored in
|
|
+ * features. This mean physical size of active area can be computed.
|
|
+ * This is useful to do when Pen and Touch have same active area of tablet.
|
|
+ * This means for Touch device, we only need to find max X/Y value and we
|
|
+ * have enough information to compute resolution of touch.
|
|
+ */
|
|
+static void wacom_set_phy_from_res(struct wacom_features *features)
|
|
+{
|
|
+ features->x_phy = (features->x_max * 100) / features->x_resolution;
|
|
+ features->y_phy = (features->y_max * 100) / features->y_resolution;
|
|
+}
|
|
+
|
|
static int wacom_parse_logical_collection(unsigned char *report,
|
|
struct wacom_features *features)
|
|
{
|
|
@@ -178,15 +191,7 @@ static int wacom_parse_logical_collection(unsigned char *report,
|
|
features->pktlen = WACOM_PKGLEN_BBTOUCH3;
|
|
features->device_type = BTN_TOOL_FINGER;
|
|
|
|
- /*
|
|
- * Stylus and Touch have same active area
|
|
- * so compute physical size based on stylus
|
|
- * data before its overwritten.
|
|
- */
|
|
- features->x_phy =
|
|
- (features->x_max * 100) / features->x_resolution;
|
|
- features->y_phy =
|
|
- (features->y_max * 100) / features->y_resolution;
|
|
+ wacom_set_phy_from_res(features);
|
|
|
|
features->x_max = features->y_max =
|
|
get_unaligned_le16(&report[10]);
|
|
@@ -869,6 +874,72 @@ static int wacom_register_input(struct wacom *wacom)
|
|
return error;
|
|
}
|
|
|
|
+static void wacom_wireless_work(struct work_struct *work)
|
|
+{
|
|
+ struct wacom *wacom = container_of(work, struct wacom, work);
|
|
+ struct usb_device *usbdev = wacom->usbdev;
|
|
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
|
+
|
|
+ /*
|
|
+ * Regardless if this is a disconnect or a new tablet,
|
|
+ * remove any existing input devices.
|
|
+ */
|
|
+
|
|
+ /* Stylus interface */
|
|
+ wacom = usb_get_intfdata(usbdev->config->interface[1]);
|
|
+ if (wacom->wacom_wac.input)
|
|
+ input_unregister_device(wacom->wacom_wac.input);
|
|
+ wacom->wacom_wac.input = 0;
|
|
+
|
|
+ /* Touch interface */
|
|
+ wacom = usb_get_intfdata(usbdev->config->interface[2]);
|
|
+ if (wacom->wacom_wac.input)
|
|
+ input_unregister_device(wacom->wacom_wac.input);
|
|
+ wacom->wacom_wac.input = 0;
|
|
+
|
|
+ if (wacom_wac->pid == 0) {
|
|
+ printk(KERN_INFO "wacom: wireless tablet disconnected\n");
|
|
+ } else {
|
|
+ const struct usb_device_id *id = wacom_ids;
|
|
+
|
|
+ printk(KERN_INFO
|
|
+ "wacom: wireless tablet connected with PID %x\n",
|
|
+ wacom_wac->pid);
|
|
+
|
|
+ while (id->match_flags) {
|
|
+ if (id->idVendor == USB_VENDOR_ID_WACOM &&
|
|
+ id->idProduct == wacom_wac->pid)
|
|
+ break;
|
|
+ id++;
|
|
+ }
|
|
+
|
|
+ if (!id->match_flags) {
|
|
+ printk(KERN_INFO
|
|
+ "wacom: ignorning unknown PID.\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Stylus interface */
|
|
+ wacom = usb_get_intfdata(usbdev->config->interface[1]);
|
|
+ wacom_wac = &wacom->wacom_wac;
|
|
+ wacom_wac->features =
|
|
+ *((struct wacom_features *)id->driver_info);
|
|
+ wacom_wac->features.device_type = BTN_TOOL_PEN;
|
|
+ wacom_register_input(wacom);
|
|
+
|
|
+ /* Touch interface */
|
|
+ wacom = usb_get_intfdata(usbdev->config->interface[2]);
|
|
+ wacom_wac = &wacom->wacom_wac;
|
|
+ wacom_wac->features =
|
|
+ *((struct wacom_features *)id->driver_info);
|
|
+ wacom_wac->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
|
|
+ wacom_wac->features.device_type = BTN_TOOL_FINGER;
|
|
+ wacom_set_phy_from_res(&wacom_wac->features);
|
|
+ wacom_wac->features.x_max = wacom_wac->features.y_max = 4096;
|
|
+ wacom_register_input(wacom);
|
|
+ }
|
|
+}
|
|
+
|
|
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|
{
|
|
struct usb_device *dev = interface_to_usbdev(intf);
|
|
@@ -909,6 +980,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
|
wacom->usbdev = dev;
|
|
wacom->intf = intf;
|
|
mutex_init(&wacom->lock);
|
|
+ INIT_WORK(&wacom->work, wacom_wireless_work);
|
|
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
|
|
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
|
|
|
|
@@ -979,6 +1051,7 @@ static void wacom_disconnect(struct usb_interface *intf)
|
|
usb_set_intfdata(intf, NULL);
|
|
|
|
usb_kill_urb(wacom->irq);
|
|
+ cancel_work_sync(&wacom->work);
|
|
if (wacom->wacom_wac.input)
|
|
input_unregister_device(wacom->wacom_wac.input);
|
|
wacom_destroy_leds(wacom);
|
|
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
|
|
index 8b73b05f5aef..1013ac345781 100644
|
|
--- a/drivers/input/tablet/wacom_wac.c
|
|
+++ b/drivers/input/tablet/wacom_wac.c
|
|
@@ -1046,9 +1046,27 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
|
|
|
|
static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
|
|
{
|
|
- if (len != WACOM_PKGLEN_WIRELESS)
|
|
+ unsigned char *data = wacom->data;
|
|
+ int connected;
|
|
+
|
|
+ if (len != WACOM_PKGLEN_WIRELESS || data[0] != 0x80)
|
|
return 0;
|
|
|
|
+ connected = data[1] & 0x01;
|
|
+ if (connected) {
|
|
+ int pid;
|
|
+
|
|
+ pid = get_unaligned_be16(&data[6]);
|
|
+ if (wacom->pid != pid) {
|
|
+ wacom->pid = pid;
|
|
+ wacom_schedule_work(wacom);
|
|
+ }
|
|
+ } else if (wacom->pid != 0) {
|
|
+ /* disconnected while previously connected */
|
|
+ wacom->pid = 0;
|
|
+ wacom_schedule_work(wacom);
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
|
|
index 2c04b6248a56..cffaf6b7e6e9 100644
|
|
--- a/drivers/input/tablet/wacom_wac.h
|
|
+++ b/drivers/input/tablet/wacom_wac.h
|
|
@@ -111,6 +111,7 @@ struct wacom_wac {
|
|
struct wacom_features features;
|
|
struct wacom_shared *shared;
|
|
struct input_dev *input;
|
|
+ int pid;
|
|
};
|
|
|
|
#endif
|
|
--
|
|
1.7.10.1
|
|
|