Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Chris Bagwell and committed by
Dmitry Torokhov
16bf288c d3825d51

+109 -10
+7
drivers/input/tablet/wacom.h
··· 112 112 struct urb *irq; 113 113 struct wacom_wac wacom_wac; 114 114 struct mutex lock; 115 + struct work_struct work; 115 116 bool open; 116 117 char phys[32]; 117 118 struct wacom_led { ··· 122 121 u8 img_lum; /* OLED matrix display brightness */ 123 122 } led; 124 123 }; 124 + 125 + static inline void wacom_schedule_work(struct wacom_wac *wacom_wac) 126 + { 127 + struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); 128 + schedule_work(&wacom->work); 129 + } 125 130 126 131 extern const struct usb_device_id wacom_ids[]; 127 132
+82 -9
drivers/input/tablet/wacom_sys.c
··· 167 167 usb_autopm_put_interface(wacom->intf); 168 168 } 169 169 170 + /* 171 + * Static values for max X/Y and resolution of Pen interface is stored in 172 + * features. This mean physical size of active area can be computed. 173 + * This is useful to do when Pen and Touch have same active area of tablet. 174 + * This means for Touch device, we only need to find max X/Y value and we 175 + * have enough information to compute resolution of touch. 176 + */ 177 + static void wacom_set_phy_from_res(struct wacom_features *features) 178 + { 179 + features->x_phy = (features->x_max * 100) / features->x_resolution; 180 + features->y_phy = (features->y_max * 100) / features->y_resolution; 181 + } 182 + 170 183 static int wacom_parse_logical_collection(unsigned char *report, 171 184 struct wacom_features *features) 172 185 { ··· 191 178 features->pktlen = WACOM_PKGLEN_BBTOUCH3; 192 179 features->device_type = BTN_TOOL_FINGER; 193 180 194 - /* 195 - * Stylus and Touch have same active area 196 - * so compute physical size based on stylus 197 - * data before its overwritten. 198 - */ 199 - features->x_phy = 200 - (features->x_max * features->x_resolution) / 100; 201 - features->y_phy = 202 - (features->y_max * features->y_resolution) / 100; 181 + wacom_set_phy_from_res(features); 203 182 204 183 features->x_max = features->y_max = 205 184 get_unaligned_le16(&report[10]); ··· 874 869 return error; 875 870 } 876 871 872 + static void wacom_wireless_work(struct work_struct *work) 873 + { 874 + struct wacom *wacom = container_of(work, struct wacom, work); 875 + struct usb_device *usbdev = wacom->usbdev; 876 + struct wacom_wac *wacom_wac = &wacom->wacom_wac; 877 + 878 + /* 879 + * Regardless if this is a disconnect or a new tablet, 880 + * remove any existing input devices. 881 + */ 882 + 883 + /* Stylus interface */ 884 + wacom = usb_get_intfdata(usbdev->config->interface[1]); 885 + if (wacom->wacom_wac.input) 886 + input_unregister_device(wacom->wacom_wac.input); 887 + wacom->wacom_wac.input = 0; 888 + 889 + /* Touch interface */ 890 + wacom = usb_get_intfdata(usbdev->config->interface[2]); 891 + if (wacom->wacom_wac.input) 892 + input_unregister_device(wacom->wacom_wac.input); 893 + wacom->wacom_wac.input = 0; 894 + 895 + if (wacom_wac->pid == 0) { 896 + printk(KERN_INFO "wacom: wireless tablet disconnected\n"); 897 + } else { 898 + const struct usb_device_id *id = wacom_ids; 899 + 900 + printk(KERN_INFO 901 + "wacom: wireless tablet connected with PID %x\n", 902 + wacom_wac->pid); 903 + 904 + while (id->match_flags) { 905 + if (id->idVendor == USB_VENDOR_ID_WACOM && 906 + id->idProduct == wacom_wac->pid) 907 + break; 908 + id++; 909 + } 910 + 911 + if (!id->match_flags) { 912 + printk(KERN_INFO 913 + "wacom: ignorning unknown PID.\n"); 914 + return; 915 + } 916 + 917 + /* Stylus interface */ 918 + wacom = usb_get_intfdata(usbdev->config->interface[1]); 919 + wacom_wac = &wacom->wacom_wac; 920 + wacom_wac->features = 921 + *((struct wacom_features *)id->driver_info); 922 + wacom_wac->features.device_type = BTN_TOOL_PEN; 923 + wacom_register_input(wacom); 924 + 925 + /* Touch interface */ 926 + wacom = usb_get_intfdata(usbdev->config->interface[2]); 927 + wacom_wac = &wacom->wacom_wac; 928 + wacom_wac->features = 929 + *((struct wacom_features *)id->driver_info); 930 + wacom_wac->features.pktlen = WACOM_PKGLEN_BBTOUCH3; 931 + wacom_wac->features.device_type = BTN_TOOL_FINGER; 932 + wacom_set_phy_from_res(&wacom_wac->features); 933 + wacom_wac->features.x_max = wacom_wac->features.y_max = 4096; 934 + wacom_register_input(wacom); 935 + } 936 + } 937 + 877 938 static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) 878 939 { 879 940 struct usb_device *dev = interface_to_usbdev(intf); ··· 978 907 wacom->usbdev = dev; 979 908 wacom->intf = intf; 980 909 mutex_init(&wacom->lock); 910 + INIT_WORK(&wacom->work, wacom_wireless_work); 981 911 usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); 982 912 strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); 983 913 ··· 1049 977 usb_set_intfdata(intf, NULL); 1050 978 1051 979 usb_kill_urb(wacom->irq); 980 + cancel_work_sync(&wacom->work); 1052 981 if (wacom->wacom_wac.input) 1053 982 input_unregister_device(wacom->wacom_wac.input); 1054 983 wacom_destroy_leds(wacom);
+19 -1
drivers/input/tablet/wacom_wac.c
··· 1046 1046 1047 1047 static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len) 1048 1048 { 1049 - if (len != WACOM_PKGLEN_WIRELESS) 1049 + unsigned char *data = wacom->data; 1050 + int connected; 1051 + 1052 + if (len != WACOM_PKGLEN_WIRELESS || data[0] != 0x80) 1050 1053 return 0; 1054 + 1055 + connected = data[1] & 0x01; 1056 + if (connected) { 1057 + int pid; 1058 + 1059 + pid = get_unaligned_be16(&data[6]); 1060 + if (wacom->pid != pid) { 1061 + wacom->pid = pid; 1062 + wacom_schedule_work(wacom); 1063 + } 1064 + } else if (wacom->pid != 0) { 1065 + /* disconnected while previously connected */ 1066 + wacom->pid = 0; 1067 + wacom_schedule_work(wacom); 1068 + } 1051 1069 1052 1070 return 0; 1053 1071 }
+1
drivers/input/tablet/wacom_wac.h
··· 111 111 struct wacom_features features; 112 112 struct wacom_shared *shared; 113 113 struct input_dev *input; 114 + int pid; 114 115 }; 115 116 116 117 #endif