Commit | Line | Data |
---|---|---|
09c434b8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
1da177e4 LT |
2 | #include <linux/kernel.h> |
3 | #include <linux/slab.h> | |
1da177e4 | 4 | #include <linux/module.h> |
ae0dadcf | 5 | #include <linux/usb/input.h> |
5f60d5f6 | 6 | #include <linux/unaligned.h> |
1da177e4 LT |
7 | |
8 | /* | |
698c03b4 | 9 | * Pressure-threshold modules param code from Alex Perry <alex.perry@ieee.org> |
1da177e4 LT |
10 | */ |
11 | ||
698c03b4 JL |
12 | MODULE_AUTHOR("Josh Myer <josh@joshisanerd.com>"); |
13 | MODULE_DESCRIPTION("USB KB Gear JamStudio Tablet driver"); | |
9f1d1ea3 | 14 | MODULE_LICENSE("GPL"); |
1da177e4 LT |
15 | |
16 | #define USB_VENDOR_ID_KBGEAR 0x084e | |
17 | ||
18 | static int kb_pressure_click = 0x10; | |
19 | module_param(kb_pressure_click, int, 0); | |
20 | MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks"); | |
21 | ||
22 | struct kbtab { | |
4ee1fc8e | 23 | unsigned char *data; |
1da177e4 | 24 | dma_addr_t data_dma; |
c5b7c7c3 | 25 | struct input_dev *dev; |
ed2b2f2d | 26 | struct usb_interface *intf; |
1da177e4 | 27 | struct urb *irq; |
1da177e4 LT |
28 | char phys[32]; |
29 | }; | |
30 | ||
7d12e780 | 31 | static void kbtab_irq(struct urb *urb) |
1da177e4 LT |
32 | { |
33 | struct kbtab *kbtab = urb->context; | |
34 | unsigned char *data = kbtab->data; | |
c5b7c7c3 | 35 | struct input_dev *dev = kbtab->dev; |
f3192090 | 36 | int pressure; |
1da177e4 LT |
37 | int retval; |
38 | ||
39 | switch (urb->status) { | |
40 | case 0: | |
41 | /* success */ | |
42 | break; | |
43 | case -ECONNRESET: | |
44 | case -ENOENT: | |
45 | case -ESHUTDOWN: | |
46 | /* this urb is terminated, clean up */ | |
ed2b2f2d GKH |
47 | dev_dbg(&kbtab->intf->dev, |
48 | "%s - urb shutting down with status: %d\n", | |
6d0f7dcb | 49 | __func__, urb->status); |
1da177e4 LT |
50 | return; |
51 | default: | |
ed2b2f2d GKH |
52 | dev_dbg(&kbtab->intf->dev, |
53 | "%s - nonzero urb status received: %d\n", | |
6d0f7dcb | 54 | __func__, urb->status); |
1da177e4 LT |
55 | goto exit; |
56 | } | |
57 | ||
1da177e4 LT |
58 | |
59 | input_report_key(dev, BTN_TOOL_PEN, 1); | |
60 | ||
f3192090 DT |
61 | input_report_abs(dev, ABS_X, get_unaligned_le16(&data[1])); |
62 | input_report_abs(dev, ABS_Y, get_unaligned_le16(&data[3])); | |
1da177e4 LT |
63 | |
64 | /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ | |
65 | input_report_key(dev, BTN_RIGHT, data[0] & 0x02); | |
66 | ||
f3192090 DT |
67 | pressure = data[5]; |
68 | if (kb_pressure_click == -1) | |
69 | input_report_abs(dev, ABS_PRESSURE, pressure); | |
70 | else | |
71 | input_report_key(dev, BTN_LEFT, pressure > kb_pressure_click ? 1 : 0); | |
05f091ab | 72 | |
1da177e4 LT |
73 | input_sync(dev); |
74 | ||
75 | exit: | |
f3192090 | 76 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
1da177e4 | 77 | if (retval) |
ed2b2f2d | 78 | dev_err(&kbtab->intf->dev, |
202712c2 GKH |
79 | "%s - usb_submit_urb failed with result %d\n", |
80 | __func__, retval); | |
1da177e4 LT |
81 | } |
82 | ||
95ac4cb0 | 83 | static const struct usb_device_id kbtab_ids[] = { |
1da177e4 LT |
84 | { USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), .driver_info = 0 }, |
85 | { } | |
86 | }; | |
87 | ||
88 | MODULE_DEVICE_TABLE(usb, kbtab_ids); | |
89 | ||
90 | static int kbtab_open(struct input_dev *dev) | |
91 | { | |
7791bdae | 92 | struct kbtab *kbtab = input_get_drvdata(dev); |
8f7292ed | 93 | struct usb_device *udev = interface_to_usbdev(kbtab->intf); |
1da177e4 | 94 | |
8f7292ed | 95 | kbtab->irq->dev = udev; |
65cde54b | 96 | if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) |
1da177e4 | 97 | return -EIO; |
1da177e4 LT |
98 | |
99 | return 0; | |
100 | } | |
101 | ||
102 | static void kbtab_close(struct input_dev *dev) | |
103 | { | |
7791bdae | 104 | struct kbtab *kbtab = input_get_drvdata(dev); |
1da177e4 | 105 | |
65cde54b | 106 | usb_kill_urb(kbtab->irq); |
1da177e4 LT |
107 | } |
108 | ||
109 | static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id) | |
110 | { | |
111 | struct usb_device *dev = interface_to_usbdev(intf); | |
112 | struct usb_endpoint_descriptor *endpoint; | |
113 | struct kbtab *kbtab; | |
c5b7c7c3 | 114 | struct input_dev *input_dev; |
5014186d | 115 | int error = -ENOMEM; |
1da177e4 | 116 | |
cb1b4946 JH |
117 | if (intf->cur_altsetting->desc.bNumEndpoints < 1) |
118 | return -ENODEV; | |
119 | ||
c88090df ON |
120 | endpoint = &intf->cur_altsetting->endpoint[0].desc; |
121 | if (!usb_endpoint_is_int_in(endpoint)) | |
122 | return -ENODEV; | |
123 | ||
2960d4c8 | 124 | kbtab = kzalloc(sizeof(*kbtab), GFP_KERNEL); |
c5b7c7c3 DT |
125 | input_dev = input_allocate_device(); |
126 | if (!kbtab || !input_dev) | |
127 | goto fail1; | |
1da177e4 | 128 | |
997ea58e | 129 | kbtab->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &kbtab->data_dma); |
c5b7c7c3 DT |
130 | if (!kbtab->data) |
131 | goto fail1; | |
1da177e4 LT |
132 | |
133 | kbtab->irq = usb_alloc_urb(0, GFP_KERNEL); | |
c5b7c7c3 DT |
134 | if (!kbtab->irq) |
135 | goto fail2; | |
1da177e4 | 136 | |
ed2b2f2d | 137 | kbtab->intf = intf; |
c5b7c7c3 | 138 | kbtab->dev = input_dev; |
05f091ab | 139 | |
c5b7c7c3 DT |
140 | usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys)); |
141 | strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys)); | |
1da177e4 | 142 | |
c5b7c7c3 DT |
143 | input_dev->name = "KB Gear Tablet"; |
144 | input_dev->phys = kbtab->phys; | |
145 | usb_to_input_id(dev, &input_dev->id); | |
c0f82d57 | 146 | input_dev->dev.parent = &intf->dev; |
7791bdae DT |
147 | |
148 | input_set_drvdata(input_dev, kbtab); | |
1da177e4 | 149 | |
c5b7c7c3 DT |
150 | input_dev->open = kbtab_open; |
151 | input_dev->close = kbtab_close; | |
1da177e4 | 152 | |
f3192090 DT |
153 | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
154 | input_dev->keybit[BIT_WORD(BTN_LEFT)] |= | |
155 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); | |
156 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= | |
157 | BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH); | |
c5b7c7c3 | 158 | input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0); |
19947544 | 159 | input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0); |
c5b7c7c3 | 160 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0); |
1da177e4 | 161 | |
1da177e4 LT |
162 | usb_fill_int_urb(kbtab->irq, dev, |
163 | usb_rcvintpipe(dev, endpoint->bEndpointAddress), | |
164 | kbtab->data, 8, | |
165 | kbtab_irq, kbtab, endpoint->bInterval); | |
166 | kbtab->irq->transfer_dma = kbtab->data_dma; | |
167 | kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | |
168 | ||
5014186d DT |
169 | error = input_register_device(kbtab->dev); |
170 | if (error) | |
171 | goto fail3; | |
1da177e4 LT |
172 | |
173 | usb_set_intfdata(intf, kbtab); | |
5014186d | 174 | |
1da177e4 | 175 | return 0; |
c5b7c7c3 | 176 | |
5014186d | 177 | fail3: usb_free_urb(kbtab->irq); |
7a9b1492 | 178 | fail2: usb_free_coherent(dev, 8, kbtab->data, kbtab->data_dma); |
5014186d | 179 | fail1: input_free_device(input_dev); |
c5b7c7c3 | 180 | kfree(kbtab); |
5014186d | 181 | return error; |
1da177e4 LT |
182 | } |
183 | ||
184 | static void kbtab_disconnect(struct usb_interface *intf) | |
185 | { | |
c5b7c7c3 | 186 | struct kbtab *kbtab = usb_get_intfdata(intf); |
8f7292ed | 187 | struct usb_device *udev = interface_to_usbdev(intf); |
1da177e4 LT |
188 | |
189 | usb_set_intfdata(intf, NULL); | |
331cb022 DT |
190 | |
191 | input_unregister_device(kbtab->dev); | |
192 | usb_free_urb(kbtab->irq); | |
8f7292ed | 193 | usb_free_coherent(udev, 8, kbtab->data, kbtab->data_dma); |
331cb022 | 194 | kfree(kbtab); |
1da177e4 LT |
195 | } |
196 | ||
197 | static struct usb_driver kbtab_driver = { | |
1da177e4 LT |
198 | .name = "kbtab", |
199 | .probe = kbtab_probe, | |
200 | .disconnect = kbtab_disconnect, | |
201 | .id_table = kbtab_ids, | |
202 | }; | |
203 | ||
08642e7c | 204 | module_usb_driver(kbtab_driver); |