Input: wacom - create inputs when wireless connect
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>
This commit is contained in:
parent
d3825d51c3
commit
16bf288c4b
|
@ -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);
|
||||
|
|
|
@ -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 * features->x_resolution) / 100;
|
||||
features->y_phy =
|
||||
(features->y_max * features->y_resolution) / 100;
|
||||
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);
|
||||
|
@ -907,6 +978,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));
|
||||
|
||||
|
@ -977,6 +1049,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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ struct wacom_wac {
|
|||
struct wacom_features features;
|
||||
struct wacom_shared *shared;
|
||||
struct input_dev *input;
|
||||
int pid;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue