diff options
-rw-r--r-- | drivers/input/tablet/wacom.h | 7 | ||||
-rw-r--r-- | drivers/input/tablet/wacom_sys.c | 91 | ||||
-rw-r--r-- | drivers/input/tablet/wacom_wac.c | 20 | ||||
-rw-r--r-- | 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 { | |||
112 | struct urb *irq; | 112 | struct urb *irq; |
113 | struct wacom_wac wacom_wac; | 113 | struct wacom_wac wacom_wac; |
114 | struct mutex lock; | 114 | struct mutex lock; |
115 | struct work_struct work; | ||
115 | bool open; | 116 | bool open; |
116 | char phys[32]; | 117 | char phys[32]; |
117 | struct wacom_led { | 118 | struct wacom_led { |
@@ -122,6 +123,12 @@ struct wacom { | |||
122 | } led; | 123 | } led; |
123 | }; | 124 | }; |
124 | 125 | ||
126 | static inline void wacom_schedule_work(struct wacom_wac *wacom_wac) | ||
127 | { | ||
128 | struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); | ||
129 | schedule_work(&wacom->work); | ||
130 | } | ||
131 | |||
125 | extern const struct usb_device_id wacom_ids[]; | 132 | extern const struct usb_device_id wacom_ids[]; |
126 | 133 | ||
127 | void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); | 134 | 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 d8cc9ce165ff..2fc77053960f 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) | |||
167 | usb_autopm_put_interface(wacom->intf); | 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 | static int wacom_parse_logical_collection(unsigned char *report, | 183 | static int wacom_parse_logical_collection(unsigned char *report, |
171 | struct wacom_features *features) | 184 | struct wacom_features *features) |
172 | { | 185 | { |
@@ -178,15 +191,7 @@ static int wacom_parse_logical_collection(unsigned char *report, | |||
178 | features->pktlen = WACOM_PKGLEN_BBTOUCH3; | 191 | features->pktlen = WACOM_PKGLEN_BBTOUCH3; |
179 | features->device_type = BTN_TOOL_FINGER; | 192 | features->device_type = BTN_TOOL_FINGER; |
180 | 193 | ||
181 | /* | 194 | wacom_set_phy_from_res(features); |
182 | * Stylus and Touch have same active area | ||
183 | * so compute physical size based on stylus | ||
184 | * data before its overwritten. | ||
185 | */ | ||
186 | features->x_phy = | ||
187 | (features->x_max * features->x_resolution) / 100; | ||
188 | features->y_phy = | ||
189 | (features->y_max * features->y_resolution) / 100; | ||
190 | 195 | ||
191 | features->x_max = features->y_max = | 196 | features->x_max = features->y_max = |
192 | get_unaligned_le16(&report[10]); | 197 | get_unaligned_le16(&report[10]); |
@@ -869,6 +874,72 @@ static int wacom_register_input(struct wacom *wacom) | |||
869 | return error; | 874 | return error; |
870 | } | 875 | } |
871 | 876 | ||
877 | static void wacom_wireless_work(struct work_struct *work) | ||
878 | { | ||
879 | struct wacom *wacom = container_of(work, struct wacom, work); | ||
880 | struct usb_device *usbdev = wacom->usbdev; | ||
881 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | ||
882 | |||
883 | /* | ||
884 | * Regardless if this is a disconnect or a new tablet, | ||
885 | * remove any existing input devices. | ||
886 | */ | ||
887 | |||
888 | /* Stylus interface */ | ||
889 | wacom = usb_get_intfdata(usbdev->config->interface[1]); | ||
890 | if (wacom->wacom_wac.input) | ||
891 | input_unregister_device(wacom->wacom_wac.input); | ||
892 | wacom->wacom_wac.input = 0; | ||
893 | |||
894 | /* Touch interface */ | ||
895 | wacom = usb_get_intfdata(usbdev->config->interface[2]); | ||
896 | if (wacom->wacom_wac.input) | ||
897 | input_unregister_device(wacom->wacom_wac.input); | ||
898 | wacom->wacom_wac.input = 0; | ||
899 | |||
900 | if (wacom_wac->pid == 0) { | ||
901 | printk(KERN_INFO "wacom: wireless tablet disconnected\n"); | ||
902 | } else { | ||
903 | const struct usb_device_id *id = wacom_ids; | ||
904 | |||
905 | printk(KERN_INFO | ||
906 | "wacom: wireless tablet connected with PID %x\n", | ||
907 | wacom_wac->pid); | ||
908 | |||
909 | while (id->match_flags) { | ||
910 | if (id->idVendor == USB_VENDOR_ID_WACOM && | ||
911 | id->idProduct == wacom_wac->pid) | ||
912 | break; | ||
913 | id++; | ||
914 | } | ||
915 | |||
916 | if (!id->match_flags) { | ||
917 | printk(KERN_INFO | ||
918 | "wacom: ignorning unknown PID.\n"); | ||
919 | return; | ||
920 | } | ||
921 | |||
922 | /* Stylus interface */ | ||
923 | wacom = usb_get_intfdata(usbdev->config->interface[1]); | ||
924 | wacom_wac = &wacom->wacom_wac; | ||
925 | wacom_wac->features = | ||
926 | *((struct wacom_features *)id->driver_info); | ||
927 | wacom_wac->features.device_type = BTN_TOOL_PEN; | ||
928 | wacom_register_input(wacom); | ||
929 | |||
930 | /* Touch interface */ | ||
931 | wacom = usb_get_intfdata(usbdev->config->interface[2]); | ||
932 | wacom_wac = &wacom->wacom_wac; | ||
933 | wacom_wac->features = | ||
934 | *((struct wacom_features *)id->driver_info); | ||
935 | wacom_wac->features.pktlen = WACOM_PKGLEN_BBTOUCH3; | ||
936 | wacom_wac->features.device_type = BTN_TOOL_FINGER; | ||
937 | wacom_set_phy_from_res(&wacom_wac->features); | ||
938 | wacom_wac->features.x_max = wacom_wac->features.y_max = 4096; | ||
939 | wacom_register_input(wacom); | ||
940 | } | ||
941 | } | ||
942 | |||
872 | static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) | 943 | static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) |
873 | { | 944 | { |
874 | struct usb_device *dev = interface_to_usbdev(intf); | 945 | 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 | |||
907 | wacom->usbdev = dev; | 978 | wacom->usbdev = dev; |
908 | wacom->intf = intf; | 979 | wacom->intf = intf; |
909 | mutex_init(&wacom->lock); | 980 | mutex_init(&wacom->lock); |
981 | INIT_WORK(&wacom->work, wacom_wireless_work); | ||
910 | usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); | 982 | usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); |
911 | strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); | 983 | strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); |
912 | 984 | ||
@@ -977,6 +1049,7 @@ static void wacom_disconnect(struct usb_interface *intf) | |||
977 | usb_set_intfdata(intf, NULL); | 1049 | usb_set_intfdata(intf, NULL); |
978 | 1050 | ||
979 | usb_kill_urb(wacom->irq); | 1051 | usb_kill_urb(wacom->irq); |
1052 | cancel_work_sync(&wacom->work); | ||
980 | if (wacom->wacom_wac.input) | 1053 | if (wacom->wacom_wac.input) |
981 | input_unregister_device(wacom->wacom_wac.input); | 1054 | input_unregister_device(wacom->wacom_wac.input); |
982 | wacom_destroy_leds(wacom); | 1055 | wacom_destroy_leds(wacom); |
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 6264e6a8d513..fce7a09fb5db 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) | |||
1046 | 1046 | ||
1047 | static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len) | 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 | return 0; | 1053 | return 0; |
1051 | 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 | } | ||
1069 | |||
1052 | return 0; | 1070 | return 0; |
1053 | } | 1071 | } |
1054 | 1072 | ||
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 { | |||
111 | struct wacom_features features; | 111 | struct wacom_features features; |
112 | struct wacom_shared *shared; | 112 | struct wacom_shared *shared; |
113 | struct input_dev *input; | 113 | struct input_dev *input; |
114 | int pid; | ||
114 | }; | 115 | }; |
115 | 116 | ||
116 | #endif | 117 | #endif |