| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * drivers/usb/input/wacom_sys.c | 
|  | 3 | * | 
|  | 4 | *  USB Wacom Graphire and Wacom Intuos tablet support - system specific code | 
|  | 5 | */ | 
|  | 6 |  | 
|  | 7 | /* | 
|  | 8 | * This program is free software; you can redistribute it and/or modify | 
|  | 9 | * it under the terms of the GNU General Public License as published by | 
|  | 10 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 11 | * (at your option) any later version. | 
|  | 12 | */ | 
|  | 13 |  | 
|  | 14 | #include "wacom.h" | 
|  | 15 | #include "wacom_wac.h" | 
|  | 16 |  | 
|  | 17 | #define USB_REQ_GET_REPORT	0x01 | 
|  | 18 | #define USB_REQ_SET_REPORT	0x09 | 
|  | 19 |  | 
|  | 20 | static int usb_get_report(struct usb_interface *intf, unsigned char type, | 
|  | 21 | unsigned char id, void *buf, int size) | 
|  | 22 | { | 
|  | 23 | return usb_control_msg(interface_to_usbdev(intf), | 
|  | 24 | usb_rcvctrlpipe(interface_to_usbdev(intf), 0), | 
|  | 25 | USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 
|  | 26 | (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, | 
|  | 27 | buf, size, 100); | 
|  | 28 | } | 
|  | 29 |  | 
|  | 30 | static int usb_set_report(struct usb_interface *intf, unsigned char type, | 
|  | 31 | unsigned char id, void *buf, int size) | 
|  | 32 | { | 
|  | 33 | return usb_control_msg(interface_to_usbdev(intf), | 
|  | 34 | usb_sndctrlpipe(interface_to_usbdev(intf), 0), | 
|  | 35 | USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 
|  | 36 | (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, | 
|  | 37 | buf, size, 1000); | 
|  | 38 | } | 
|  | 39 |  | 
|  | 40 | static struct input_dev * get_input_dev(struct wacom_combo *wcombo) | 
|  | 41 | { | 
|  | 42 | return wcombo->wacom->dev; | 
|  | 43 | } | 
|  | 44 |  | 
| Adrian Bunk | 54c9b226 | 2006-11-20 03:23:58 +0100 | [diff] [blame] | 45 | static void wacom_sys_irq(struct urb *urb) | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 46 | { | 
|  | 47 | struct wacom *wacom = urb->context; | 
|  | 48 | struct wacom_combo wcombo; | 
|  | 49 | int retval; | 
|  | 50 |  | 
|  | 51 | switch (urb->status) { | 
|  | 52 | case 0: | 
|  | 53 | /* success */ | 
|  | 54 | break; | 
|  | 55 | case -ECONNRESET: | 
|  | 56 | case -ENOENT: | 
|  | 57 | case -ESHUTDOWN: | 
|  | 58 | /* this urb is terminated, clean up */ | 
|  | 59 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); | 
|  | 60 | return; | 
|  | 61 | default: | 
|  | 62 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); | 
|  | 63 | goto exit; | 
|  | 64 | } | 
|  | 65 |  | 
|  | 66 | wcombo.wacom = wacom; | 
|  | 67 | wcombo.urb = urb; | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 68 |  | 
|  | 69 | if (wacom_wac_irq(wacom->wacom_wac, (void *)&wcombo)) | 
|  | 70 | input_sync(get_input_dev(&wcombo)); | 
|  | 71 |  | 
|  | 72 | exit: | 
|  | 73 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 
|  | 74 | if (retval) | 
|  | 75 | err ("%s - usb_submit_urb failed with result %d", | 
|  | 76 | __FUNCTION__, retval); | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | void wacom_report_key(void *wcombo, unsigned int key_type, int key_data) | 
|  | 80 | { | 
|  | 81 | input_report_key(get_input_dev((struct wacom_combo *)wcombo), key_type, key_data); | 
|  | 82 | return; | 
|  | 83 | } | 
|  | 84 |  | 
|  | 85 | void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data) | 
|  | 86 | { | 
|  | 87 | input_report_abs(get_input_dev((struct wacom_combo *)wcombo), abs_type, abs_data); | 
|  | 88 | return; | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data) | 
|  | 92 | { | 
|  | 93 | input_report_rel(get_input_dev((struct wacom_combo *)wcombo), rel_type, rel_data); | 
|  | 94 | return; | 
|  | 95 | } | 
|  | 96 |  | 
|  | 97 | void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value) | 
|  | 98 | { | 
|  | 99 | input_event(get_input_dev((struct wacom_combo *)wcombo), type, code, value); | 
|  | 100 | return; | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | __u16 wacom_be16_to_cpu(unsigned char *data) | 
|  | 104 | { | 
|  | 105 | __u16 value; | 
|  | 106 | value = be16_to_cpu(*(__be16 *) data); | 
|  | 107 | return value; | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | __u16 wacom_le16_to_cpu(unsigned char *data) | 
|  | 111 | { | 
|  | 112 | __u16 value; | 
| Ping Cheng | 8d32e3a | 2006-09-26 13:34:47 -0700 | [diff] [blame] | 113 | value = le16_to_cpu(*(__le16 *) data); | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 114 | return value; | 
|  | 115 | } | 
|  | 116 |  | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 117 | void wacom_input_sync(void *wcombo) | 
|  | 118 | { | 
|  | 119 | input_sync(get_input_dev((struct wacom_combo *)wcombo)); | 
|  | 120 | return; | 
|  | 121 | } | 
|  | 122 |  | 
|  | 123 | static int wacom_open(struct input_dev *dev) | 
|  | 124 | { | 
|  | 125 | struct wacom *wacom = dev->private; | 
|  | 126 |  | 
|  | 127 | wacom->irq->dev = wacom->usbdev; | 
|  | 128 | if (usb_submit_urb(wacom->irq, GFP_KERNEL)) | 
|  | 129 | return -EIO; | 
|  | 130 |  | 
|  | 131 | return 0; | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | static void wacom_close(struct input_dev *dev) | 
|  | 135 | { | 
|  | 136 | struct wacom *wacom = dev->private; | 
|  | 137 |  | 
|  | 138 | usb_kill_urb(wacom->irq); | 
|  | 139 | } | 
|  | 140 |  | 
|  | 141 | void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 
|  | 142 | { | 
|  | 143 | input_dev->evbit[0] |= BIT(EV_MSC); | 
|  | 144 | input_dev->mscbit[0] |= BIT(MSC_SERIAL); | 
|  | 145 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); | 
| Ping Cheng | 8d32e3a | 2006-09-26 13:34:47 -0700 | [diff] [blame] | 146 | input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4); | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 147 | } | 
|  | 148 |  | 
|  | 149 | void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 
|  | 150 | { | 
|  | 151 | input_dev->evbit[0] |= BIT(EV_REL); | 
|  | 152 | input_dev->relbit[0] |= BIT(REL_WHEEL); | 
|  | 153 | input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); | 
|  | 154 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2); | 
|  | 155 | input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0); | 
|  | 156 | } | 
|  | 157 |  | 
| Ping Cheng | 8d32e3a | 2006-09-26 13:34:47 -0700 | [diff] [blame] | 158 | void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 159 | { | 
|  | 160 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); | 
| Ping Cheng | 8d32e3a | 2006-09-26 13:34:47 -0700 | [diff] [blame] | 161 | input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3); | 
| Ping Cheng | 071e0a2 | 2006-12-05 17:09:51 -0800 | [diff] [blame] | 162 | input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); | 
| Ping Cheng | 8d32e3a | 2006-09-26 13:34:47 -0700 | [diff] [blame] | 163 | } | 
|  | 164 |  | 
|  | 165 | void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 
|  | 166 | { | 
|  | 167 | input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); | 
| Ping Cheng | 071e0a2 | 2006-12-05 17:09:51 -0800 | [diff] [blame] | 168 | input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 169 | } | 
|  | 170 |  | 
|  | 171 | void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 
|  | 172 | { | 
|  | 173 | input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL); | 
|  | 174 | input_dev->mscbit[0] |= BIT(MSC_SERIAL); | 
|  | 175 | input_dev->relbit[0] |= BIT(REL_WHEEL); | 
|  | 176 | input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA); | 
|  | 177 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE)	| BIT(BTN_TOOL_BRUSH) | 
|  | 178 | | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2); | 
|  | 179 | input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0); | 
|  | 180 | input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0); | 
|  | 181 | input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0); | 
|  | 182 | input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0); | 
|  | 183 | input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0); | 
|  | 184 | input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0); | 
|  | 185 | } | 
|  | 186 |  | 
|  | 187 | void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 
|  | 188 | { | 
|  | 189 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER); | 
|  | 190 | } | 
|  | 191 |  | 
|  | 192 | void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 
|  | 193 | { | 
|  | 194 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER); | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) | 
|  | 198 | { | 
|  | 199 | struct usb_device *dev = interface_to_usbdev(intf); | 
|  | 200 | struct usb_endpoint_descriptor *endpoint; | 
|  | 201 | struct wacom *wacom; | 
|  | 202 | struct wacom_wac *wacom_wac; | 
|  | 203 | struct input_dev *input_dev; | 
|  | 204 | char rep_data[2], limit = 0; | 
|  | 205 |  | 
|  | 206 | wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); | 
|  | 207 | wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL); | 
|  | 208 | input_dev = input_allocate_device(); | 
|  | 209 | if (!wacom || !input_dev || !wacom_wac) | 
|  | 210 | goto fail1; | 
|  | 211 |  | 
|  | 212 | wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma); | 
|  | 213 | if (!wacom_wac->data) | 
|  | 214 | goto fail1; | 
|  | 215 |  | 
|  | 216 | wacom->irq = usb_alloc_urb(0, GFP_KERNEL); | 
|  | 217 | if (!wacom->irq) | 
|  | 218 | goto fail2; | 
|  | 219 |  | 
|  | 220 | wacom->usbdev = dev; | 
|  | 221 | wacom->dev = input_dev; | 
|  | 222 | usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); | 
|  | 223 | strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); | 
|  | 224 |  | 
|  | 225 | wacom_wac->features = get_wacom_feature(id); | 
| Eric Sesterhenn | 2920349 | 2006-10-17 14:46:30 -0700 | [diff] [blame] | 226 | BUG_ON(wacom_wac->features->pktlen > 10); | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 227 |  | 
|  | 228 | input_dev->name = wacom_wac->features->name; | 
|  | 229 | wacom->wacom_wac = wacom_wac; | 
|  | 230 | usb_to_input_id(dev, &input_dev->id); | 
|  | 231 |  | 
|  | 232 | input_dev->cdev.dev = &intf->dev; | 
|  | 233 | input_dev->private = wacom; | 
|  | 234 | input_dev->open = wacom_open; | 
|  | 235 | input_dev->close = wacom_close; | 
|  | 236 |  | 
|  | 237 | input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS); | 
|  | 238 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS); | 
|  | 239 | input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0); | 
|  | 240 | input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0); | 
|  | 241 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0); | 
|  | 242 | input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC); | 
|  | 243 |  | 
|  | 244 | wacom_init_input_dev(input_dev, wacom_wac); | 
|  | 245 |  | 
|  | 246 | endpoint = &intf->cur_altsetting->endpoint[0].desc; | 
|  | 247 |  | 
|  | 248 | usb_fill_int_urb(wacom->irq, dev, | 
|  | 249 | usb_rcvintpipe(dev, endpoint->bEndpointAddress), | 
|  | 250 | wacom_wac->data, wacom_wac->features->pktlen, | 
| Ping Cheng | 8d32e3a | 2006-09-26 13:34:47 -0700 | [diff] [blame] | 251 | wacom_sys_irq, wacom, endpoint->bInterval); | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 252 | wacom->irq->transfer_dma = wacom->data_dma; | 
|  | 253 | wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 
|  | 254 |  | 
|  | 255 | input_register_device(wacom->dev); | 
|  | 256 |  | 
|  | 257 | /* Ask the tablet to report tablet data. Repeat until it succeeds */ | 
|  | 258 | do { | 
|  | 259 | rep_data[0] = 2; | 
|  | 260 | rep_data[1] = 2; | 
|  | 261 | usb_set_report(intf, 3, 2, rep_data, 2); | 
|  | 262 | usb_get_report(intf, 3, 2, rep_data, 2); | 
|  | 263 | } while (rep_data[1] != 2 && limit++ < 5); | 
|  | 264 |  | 
|  | 265 | usb_set_intfdata(intf, wacom); | 
|  | 266 | return 0; | 
|  | 267 |  | 
|  | 268 | fail2:	usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma); | 
|  | 269 | fail1:	input_free_device(input_dev); | 
|  | 270 | kfree(wacom); | 
|  | 271 | kfree(wacom_wac); | 
|  | 272 | return -ENOMEM; | 
|  | 273 | } | 
|  | 274 |  | 
|  | 275 | static void wacom_disconnect(struct usb_interface *intf) | 
|  | 276 | { | 
|  | 277 | struct wacom *wacom = usb_get_intfdata (intf); | 
|  | 278 |  | 
|  | 279 | usb_set_intfdata(intf, NULL); | 
|  | 280 | if (wacom) { | 
|  | 281 | usb_kill_urb(wacom->irq); | 
|  | 282 | input_unregister_device(wacom->dev); | 
|  | 283 | usb_free_urb(wacom->irq); | 
|  | 284 | usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma); | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 285 | kfree(wacom->wacom_wac); | 
| Eric Sesterhenn | 2daa487 | 2006-10-04 09:56:44 -0700 | [diff] [blame] | 286 | kfree(wacom); | 
| Ping Cheng | 3bea733 | 2006-07-13 18:01:36 -0700 | [diff] [blame] | 287 | } | 
|  | 288 | } | 
|  | 289 |  | 
|  | 290 | static struct usb_driver wacom_driver = { | 
|  | 291 | .name =		"wacom", | 
|  | 292 | .probe =	wacom_probe, | 
|  | 293 | .disconnect =	wacom_disconnect, | 
|  | 294 | }; | 
|  | 295 |  | 
|  | 296 | static int __init wacom_init(void) | 
|  | 297 | { | 
|  | 298 | int result; | 
|  | 299 | wacom_driver.id_table = get_device_table(); | 
|  | 300 | result = usb_register(&wacom_driver); | 
|  | 301 | if (result == 0) | 
|  | 302 | info(DRIVER_VERSION ":" DRIVER_DESC); | 
|  | 303 | return result; | 
|  | 304 | } | 
|  | 305 |  | 
|  | 306 | static void __exit wacom_exit(void) | 
|  | 307 | { | 
|  | 308 | usb_deregister(&wacom_driver); | 
|  | 309 | } | 
|  | 310 |  | 
|  | 311 | module_init(wacom_init); | 
|  | 312 | module_exit(wacom_exit); |