1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) 2001-2005 Edouard TISSERANT <edouard.tisserant@wanadoo.fr> |
4 | * Copyright (c) 2004-2005 Stephane VOLTZ <svoltz@numericable.fr> |
5 | * |
6 | * USB Acecad "Acecad Flair" tablet support |
7 | * |
8 | * Changelog: |
9 | * v3.2 - Added sysfs support |
10 | */ |
11 | |
12 | #include <linux/kernel.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/module.h> |
15 | #include <linux/usb/input.h> |
16 | |
17 | MODULE_AUTHOR("Edouard TISSERANT <edouard.tisserant@wanadoo.fr>" ); |
18 | MODULE_DESCRIPTION("USB Acecad Flair tablet driver" ); |
19 | MODULE_LICENSE("GPL" ); |
20 | |
21 | #define USB_VENDOR_ID_ACECAD 0x0460 |
22 | #define USB_DEVICE_ID_FLAIR 0x0004 |
23 | #define USB_DEVICE_ID_302 0x0008 |
24 | |
25 | struct usb_acecad { |
26 | char name[128]; |
27 | char phys[64]; |
28 | struct usb_interface *intf; |
29 | struct input_dev *input; |
30 | struct urb *irq; |
31 | |
32 | unsigned char *data; |
33 | dma_addr_t data_dma; |
34 | }; |
35 | |
36 | static void usb_acecad_irq(struct urb *urb) |
37 | { |
38 | struct usb_acecad *acecad = urb->context; |
39 | unsigned char *data = acecad->data; |
40 | struct input_dev *dev = acecad->input; |
41 | struct usb_interface *intf = acecad->intf; |
42 | struct usb_device *udev = interface_to_usbdev(intf); |
43 | int prox, status; |
44 | |
45 | switch (urb->status) { |
46 | case 0: |
47 | /* success */ |
48 | break; |
49 | case -ECONNRESET: |
50 | case -ENOENT: |
51 | case -ESHUTDOWN: |
52 | /* this urb is terminated, clean up */ |
53 | dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n" , |
54 | __func__, urb->status); |
55 | return; |
56 | default: |
57 | dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n" , |
58 | __func__, urb->status); |
59 | goto resubmit; |
60 | } |
61 | |
62 | prox = (data[0] & 0x04) >> 2; |
63 | input_report_key(dev, BTN_TOOL_PEN, value: prox); |
64 | |
65 | if (prox) { |
66 | int x = data[1] | (data[2] << 8); |
67 | int y = data[3] | (data[4] << 8); |
68 | /* Pressure should compute the same way for flair and 302 */ |
69 | int pressure = data[5] | (data[6] << 8); |
70 | int touch = data[0] & 0x01; |
71 | int stylus = (data[0] & 0x10) >> 4; |
72 | int stylus2 = (data[0] & 0x20) >> 5; |
73 | input_report_abs(dev, ABS_X, value: x); |
74 | input_report_abs(dev, ABS_Y, value: y); |
75 | input_report_abs(dev, ABS_PRESSURE, value: pressure); |
76 | input_report_key(dev, BTN_TOUCH, value: touch); |
77 | input_report_key(dev, BTN_STYLUS, value: stylus); |
78 | input_report_key(dev, BTN_STYLUS2, value: stylus2); |
79 | } |
80 | |
81 | /* event termination */ |
82 | input_sync(dev); |
83 | |
84 | resubmit: |
85 | status = usb_submit_urb(urb, GFP_ATOMIC); |
86 | if (status) |
87 | dev_err(&intf->dev, |
88 | "can't resubmit intr, %s-%s/input0, status %d\n" , |
89 | udev->bus->bus_name, |
90 | udev->devpath, status); |
91 | } |
92 | |
93 | static int usb_acecad_open(struct input_dev *dev) |
94 | { |
95 | struct usb_acecad *acecad = input_get_drvdata(dev); |
96 | |
97 | acecad->irq->dev = interface_to_usbdev(acecad->intf); |
98 | if (usb_submit_urb(urb: acecad->irq, GFP_KERNEL)) |
99 | return -EIO; |
100 | |
101 | return 0; |
102 | } |
103 | |
104 | static void usb_acecad_close(struct input_dev *dev) |
105 | { |
106 | struct usb_acecad *acecad = input_get_drvdata(dev); |
107 | |
108 | usb_kill_urb(urb: acecad->irq); |
109 | } |
110 | |
111 | static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id) |
112 | { |
113 | struct usb_device *dev = interface_to_usbdev(intf); |
114 | struct usb_host_interface *interface = intf->cur_altsetting; |
115 | struct usb_endpoint_descriptor *endpoint; |
116 | struct usb_acecad *acecad; |
117 | struct input_dev *input_dev; |
118 | int pipe, maxp; |
119 | int err; |
120 | |
121 | if (interface->desc.bNumEndpoints != 1) |
122 | return -ENODEV; |
123 | |
124 | endpoint = &interface->endpoint[0].desc; |
125 | |
126 | if (!usb_endpoint_is_int_in(epd: endpoint)) |
127 | return -ENODEV; |
128 | |
129 | pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); |
130 | maxp = usb_maxpacket(udev: dev, pipe); |
131 | |
132 | acecad = kzalloc(size: sizeof(struct usb_acecad), GFP_KERNEL); |
133 | input_dev = input_allocate_device(); |
134 | if (!acecad || !input_dev) { |
135 | err = -ENOMEM; |
136 | goto fail1; |
137 | } |
138 | |
139 | acecad->data = usb_alloc_coherent(dev, size: 8, GFP_KERNEL, dma: &acecad->data_dma); |
140 | if (!acecad->data) { |
141 | err= -ENOMEM; |
142 | goto fail1; |
143 | } |
144 | |
145 | acecad->irq = usb_alloc_urb(iso_packets: 0, GFP_KERNEL); |
146 | if (!acecad->irq) { |
147 | err = -ENOMEM; |
148 | goto fail2; |
149 | } |
150 | |
151 | acecad->intf = intf; |
152 | acecad->input = input_dev; |
153 | |
154 | if (dev->manufacturer) |
155 | strscpy(p: acecad->name, q: dev->manufacturer, size: sizeof(acecad->name)); |
156 | |
157 | if (dev->product) { |
158 | if (dev->manufacturer) |
159 | strlcat(p: acecad->name, q: " " , avail: sizeof(acecad->name)); |
160 | strlcat(p: acecad->name, q: dev->product, avail: sizeof(acecad->name)); |
161 | } |
162 | |
163 | usb_make_path(dev, buf: acecad->phys, size: sizeof(acecad->phys)); |
164 | strlcat(p: acecad->phys, q: "/input0" , avail: sizeof(acecad->phys)); |
165 | |
166 | input_dev->name = acecad->name; |
167 | input_dev->phys = acecad->phys; |
168 | usb_to_input_id(dev, id: &input_dev->id); |
169 | input_dev->dev.parent = &intf->dev; |
170 | |
171 | input_set_drvdata(dev: input_dev, data: acecad); |
172 | |
173 | input_dev->open = usb_acecad_open; |
174 | input_dev->close = usb_acecad_close; |
175 | |
176 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
177 | input_dev->keybit[BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_TOOL_PEN) | |
178 | BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS) | |
179 | BIT_MASK(BTN_STYLUS2); |
180 | |
181 | switch (id->driver_info) { |
182 | case 0: |
183 | input_set_abs_params(dev: input_dev, ABS_X, min: 0, max: 5000, fuzz: 4, flat: 0); |
184 | input_set_abs_params(dev: input_dev, ABS_Y, min: 0, max: 3750, fuzz: 4, flat: 0); |
185 | input_set_abs_params(dev: input_dev, ABS_PRESSURE, min: 0, max: 512, fuzz: 0, flat: 0); |
186 | if (!strlen(acecad->name)) |
187 | snprintf(buf: acecad->name, size: sizeof(acecad->name), |
188 | fmt: "USB Acecad Flair Tablet %04x:%04x" , |
189 | le16_to_cpu(dev->descriptor.idVendor), |
190 | le16_to_cpu(dev->descriptor.idProduct)); |
191 | break; |
192 | |
193 | case 1: |
194 | input_set_abs_params(dev: input_dev, ABS_X, min: 0, max: 53000, fuzz: 4, flat: 0); |
195 | input_set_abs_params(dev: input_dev, ABS_Y, min: 0, max: 2250, fuzz: 4, flat: 0); |
196 | input_set_abs_params(dev: input_dev, ABS_PRESSURE, min: 0, max: 1024, fuzz: 0, flat: 0); |
197 | if (!strlen(acecad->name)) |
198 | snprintf(buf: acecad->name, size: sizeof(acecad->name), |
199 | fmt: "USB Acecad 302 Tablet %04x:%04x" , |
200 | le16_to_cpu(dev->descriptor.idVendor), |
201 | le16_to_cpu(dev->descriptor.idProduct)); |
202 | break; |
203 | } |
204 | |
205 | usb_fill_int_urb(urb: acecad->irq, dev, pipe, |
206 | transfer_buffer: acecad->data, buffer_length: maxp > 8 ? 8 : maxp, |
207 | complete_fn: usb_acecad_irq, context: acecad, interval: endpoint->bInterval); |
208 | acecad->irq->transfer_dma = acecad->data_dma; |
209 | acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
210 | |
211 | err = input_register_device(acecad->input); |
212 | if (err) |
213 | goto fail3; |
214 | |
215 | usb_set_intfdata(intf, data: acecad); |
216 | |
217 | return 0; |
218 | |
219 | fail3: usb_free_urb(urb: acecad->irq); |
220 | fail2: usb_free_coherent(dev, size: 8, addr: acecad->data, dma: acecad->data_dma); |
221 | fail1: input_free_device(dev: input_dev); |
222 | kfree(objp: acecad); |
223 | return err; |
224 | } |
225 | |
226 | static void usb_acecad_disconnect(struct usb_interface *intf) |
227 | { |
228 | struct usb_acecad *acecad = usb_get_intfdata(intf); |
229 | struct usb_device *udev = interface_to_usbdev(intf); |
230 | |
231 | usb_set_intfdata(intf, NULL); |
232 | |
233 | input_unregister_device(acecad->input); |
234 | usb_free_urb(urb: acecad->irq); |
235 | usb_free_coherent(dev: udev, size: 8, addr: acecad->data, dma: acecad->data_dma); |
236 | kfree(objp: acecad); |
237 | } |
238 | |
239 | static const struct usb_device_id usb_acecad_id_table[] = { |
240 | { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 }, |
241 | { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302), .driver_info = 1 }, |
242 | { } |
243 | }; |
244 | |
245 | MODULE_DEVICE_TABLE(usb, usb_acecad_id_table); |
246 | |
247 | static struct usb_driver usb_acecad_driver = { |
248 | .name = "usb_acecad" , |
249 | .probe = usb_acecad_probe, |
250 | .disconnect = usb_acecad_disconnect, |
251 | .id_table = usb_acecad_id_table, |
252 | }; |
253 | |
254 | module_usb_driver(usb_acecad_driver); |
255 | |