18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * USB Hanwang tablet support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010 Xing Wei <weixing@hanwang.com.cn> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/usb/input.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xing Wei <weixing@hanwang.com.cn>"); 188c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("USB Hanwang tablet driver"); 198c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define USB_VENDOR_ID_HANWANG 0x0b57 228c2ecf20Sopenharmony_ci#define HANWANG_TABLET_INT_CLASS 0x0003 238c2ecf20Sopenharmony_ci#define HANWANG_TABLET_INT_SUB_CLASS 0x0001 248c2ecf20Sopenharmony_ci#define HANWANG_TABLET_INT_PROTOCOL 0x0002 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define ART_MASTER_PKGLEN_MAX 10 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* device IDs */ 298c2ecf20Sopenharmony_ci#define STYLUS_DEVICE_ID 0x02 308c2ecf20Sopenharmony_ci#define TOUCH_DEVICE_ID 0x03 318c2ecf20Sopenharmony_ci#define CURSOR_DEVICE_ID 0x06 328c2ecf20Sopenharmony_ci#define ERASER_DEVICE_ID 0x0A 338c2ecf20Sopenharmony_ci#define PAD_DEVICE_ID 0x0F 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* match vendor and interface info */ 368c2ecf20Sopenharmony_ci#define HANWANG_TABLET_DEVICE(vend, cl, sc, pr) \ 378c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_VENDOR \ 388c2ecf20Sopenharmony_ci | USB_DEVICE_ID_MATCH_INT_INFO, \ 398c2ecf20Sopenharmony_ci .idVendor = (vend), \ 408c2ecf20Sopenharmony_ci .bInterfaceClass = (cl), \ 418c2ecf20Sopenharmony_ci .bInterfaceSubClass = (sc), \ 428c2ecf20Sopenharmony_ci .bInterfaceProtocol = (pr) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cienum hanwang_tablet_type { 458c2ecf20Sopenharmony_ci HANWANG_ART_MASTER_III, 468c2ecf20Sopenharmony_ci HANWANG_ART_MASTER_HD, 478c2ecf20Sopenharmony_ci HANWANG_ART_MASTER_II, 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct hanwang { 518c2ecf20Sopenharmony_ci unsigned char *data; 528c2ecf20Sopenharmony_ci dma_addr_t data_dma; 538c2ecf20Sopenharmony_ci struct input_dev *dev; 548c2ecf20Sopenharmony_ci struct usb_device *usbdev; 558c2ecf20Sopenharmony_ci struct urb *irq; 568c2ecf20Sopenharmony_ci const struct hanwang_features *features; 578c2ecf20Sopenharmony_ci unsigned int current_tool; 588c2ecf20Sopenharmony_ci unsigned int current_id; 598c2ecf20Sopenharmony_ci char name[64]; 608c2ecf20Sopenharmony_ci char phys[32]; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistruct hanwang_features { 648c2ecf20Sopenharmony_ci unsigned short pid; 658c2ecf20Sopenharmony_ci char *name; 668c2ecf20Sopenharmony_ci enum hanwang_tablet_type type; 678c2ecf20Sopenharmony_ci int pkg_len; 688c2ecf20Sopenharmony_ci int max_x; 698c2ecf20Sopenharmony_ci int max_y; 708c2ecf20Sopenharmony_ci int max_tilt_x; 718c2ecf20Sopenharmony_ci int max_tilt_y; 728c2ecf20Sopenharmony_ci int max_pressure; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const struct hanwang_features features_array[] = { 768c2ecf20Sopenharmony_ci { 0x8528, "Hanwang Art Master III 0906", HANWANG_ART_MASTER_III, 778c2ecf20Sopenharmony_ci ART_MASTER_PKGLEN_MAX, 0x5757, 0x3692, 0x3f, 0x7f, 2048 }, 788c2ecf20Sopenharmony_ci { 0x8529, "Hanwang Art Master III 0604", HANWANG_ART_MASTER_III, 798c2ecf20Sopenharmony_ci ART_MASTER_PKGLEN_MAX, 0x3d84, 0x2672, 0x3f, 0x7f, 2048 }, 808c2ecf20Sopenharmony_ci { 0x852a, "Hanwang Art Master III 1308", HANWANG_ART_MASTER_III, 818c2ecf20Sopenharmony_ci ART_MASTER_PKGLEN_MAX, 0x7f00, 0x4f60, 0x3f, 0x7f, 2048 }, 828c2ecf20Sopenharmony_ci { 0x8401, "Hanwang Art Master HD 5012", HANWANG_ART_MASTER_HD, 838c2ecf20Sopenharmony_ci ART_MASTER_PKGLEN_MAX, 0x678e, 0x4150, 0x3f, 0x7f, 1024 }, 848c2ecf20Sopenharmony_ci { 0x8503, "Hanwang Art Master II", HANWANG_ART_MASTER_II, 858c2ecf20Sopenharmony_ci ART_MASTER_PKGLEN_MAX, 0x27de, 0x1cfe, 0x3f, 0x7f, 1024 }, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const int hw_eventtypes[] = { 898c2ecf20Sopenharmony_ci EV_KEY, EV_ABS, EV_MSC, 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic const int hw_absevents[] = { 938c2ecf20Sopenharmony_ci ABS_X, ABS_Y, ABS_TILT_X, ABS_TILT_Y, ABS_WHEEL, 948c2ecf20Sopenharmony_ci ABS_RX, ABS_RY, ABS_PRESSURE, ABS_MISC, 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const int hw_btnevents[] = { 988c2ecf20Sopenharmony_ci BTN_STYLUS, BTN_STYLUS2, BTN_TOOL_PEN, BTN_TOOL_RUBBER, 998c2ecf20Sopenharmony_ci BTN_TOOL_MOUSE, BTN_TOOL_FINGER, 1008c2ecf20Sopenharmony_ci BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8, 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic const int hw_mscevents[] = { 1048c2ecf20Sopenharmony_ci MSC_SERIAL, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic void hanwang_parse_packet(struct hanwang *hanwang) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci unsigned char *data = hanwang->data; 1108c2ecf20Sopenharmony_ci struct input_dev *input_dev = hanwang->dev; 1118c2ecf20Sopenharmony_ci struct usb_device *dev = hanwang->usbdev; 1128c2ecf20Sopenharmony_ci enum hanwang_tablet_type type = hanwang->features->type; 1138c2ecf20Sopenharmony_ci int i; 1148c2ecf20Sopenharmony_ci u16 p; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (type == HANWANG_ART_MASTER_II) { 1178c2ecf20Sopenharmony_ci hanwang->current_tool = BTN_TOOL_PEN; 1188c2ecf20Sopenharmony_ci hanwang->current_id = STYLUS_DEVICE_ID; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci switch (data[0]) { 1228c2ecf20Sopenharmony_ci case 0x02: /* data packet */ 1238c2ecf20Sopenharmony_ci switch (data[1]) { 1248c2ecf20Sopenharmony_ci case 0x80: /* tool prox out */ 1258c2ecf20Sopenharmony_ci if (type != HANWANG_ART_MASTER_II) { 1268c2ecf20Sopenharmony_ci hanwang->current_id = 0; 1278c2ecf20Sopenharmony_ci input_report_key(input_dev, 1288c2ecf20Sopenharmony_ci hanwang->current_tool, 0); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci case 0x00: /* artmaster ii pen leave */ 1338c2ecf20Sopenharmony_ci if (type == HANWANG_ART_MASTER_II) { 1348c2ecf20Sopenharmony_ci hanwang->current_id = 0; 1358c2ecf20Sopenharmony_ci input_report_key(input_dev, 1368c2ecf20Sopenharmony_ci hanwang->current_tool, 0); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci case 0xc2: /* first time tool prox in */ 1418c2ecf20Sopenharmony_ci switch (data[3] & 0xf0) { 1428c2ecf20Sopenharmony_ci case 0x20: /* art_master III */ 1438c2ecf20Sopenharmony_ci case 0x30: /* art_master_HD */ 1448c2ecf20Sopenharmony_ci hanwang->current_id = STYLUS_DEVICE_ID; 1458c2ecf20Sopenharmony_ci hanwang->current_tool = BTN_TOOL_PEN; 1468c2ecf20Sopenharmony_ci input_report_key(input_dev, BTN_TOOL_PEN, 1); 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci case 0xa0: /* art_master III */ 1498c2ecf20Sopenharmony_ci case 0xb0: /* art_master_HD */ 1508c2ecf20Sopenharmony_ci hanwang->current_id = ERASER_DEVICE_ID; 1518c2ecf20Sopenharmony_ci hanwang->current_tool = BTN_TOOL_RUBBER; 1528c2ecf20Sopenharmony_ci input_report_key(input_dev, BTN_TOOL_RUBBER, 1); 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci default: 1558c2ecf20Sopenharmony_ci hanwang->current_id = 0; 1568c2ecf20Sopenharmony_ci dev_dbg(&dev->dev, 1578c2ecf20Sopenharmony_ci "unknown tablet tool %02x\n", data[0]); 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci default: /* tool data packet */ 1638c2ecf20Sopenharmony_ci switch (type) { 1648c2ecf20Sopenharmony_ci case HANWANG_ART_MASTER_III: 1658c2ecf20Sopenharmony_ci p = (data[6] << 3) | 1668c2ecf20Sopenharmony_ci ((data[7] & 0xc0) >> 5) | 1678c2ecf20Sopenharmony_ci (data[1] & 0x01); 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci case HANWANG_ART_MASTER_HD: 1718c2ecf20Sopenharmony_ci case HANWANG_ART_MASTER_II: 1728c2ecf20Sopenharmony_ci p = (data[7] >> 6) | (data[6] << 2); 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci default: 1768c2ecf20Sopenharmony_ci p = 0; 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_X, 1818c2ecf20Sopenharmony_ci be16_to_cpup((__be16 *)&data[2])); 1828c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_Y, 1838c2ecf20Sopenharmony_ci be16_to_cpup((__be16 *)&data[4])); 1848c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_PRESSURE, p); 1858c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_TILT_X, data[7] & 0x3f); 1868c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_TILT_Y, data[8] & 0x7f); 1878c2ecf20Sopenharmony_ci input_report_key(input_dev, BTN_STYLUS, data[1] & 0x02); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (type != HANWANG_ART_MASTER_II) 1908c2ecf20Sopenharmony_ci input_report_key(input_dev, BTN_STYLUS2, 1918c2ecf20Sopenharmony_ci data[1] & 0x04); 1928c2ecf20Sopenharmony_ci else 1938c2ecf20Sopenharmony_ci input_report_key(input_dev, BTN_TOOL_PEN, 1); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_MISC, hanwang->current_id); 1998c2ecf20Sopenharmony_ci input_event(input_dev, EV_MSC, MSC_SERIAL, 2008c2ecf20Sopenharmony_ci hanwang->features->pid); 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci case 0x0c: 2048c2ecf20Sopenharmony_ci /* roll wheel */ 2058c2ecf20Sopenharmony_ci hanwang->current_id = PAD_DEVICE_ID; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci switch (type) { 2088c2ecf20Sopenharmony_ci case HANWANG_ART_MASTER_III: 2098c2ecf20Sopenharmony_ci input_report_key(input_dev, BTN_TOOL_FINGER, 2108c2ecf20Sopenharmony_ci data[1] || data[2] || data[3]); 2118c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_WHEEL, data[1]); 2128c2ecf20Sopenharmony_ci input_report_key(input_dev, BTN_0, data[2]); 2138c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 2148c2ecf20Sopenharmony_ci input_report_key(input_dev, 2158c2ecf20Sopenharmony_ci BTN_1 + i, data[3] & (1 << i)); 2168c2ecf20Sopenharmony_ci break; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci case HANWANG_ART_MASTER_HD: 2198c2ecf20Sopenharmony_ci input_report_key(input_dev, BTN_TOOL_FINGER, data[1] || 2208c2ecf20Sopenharmony_ci data[2] || data[3] || data[4] || 2218c2ecf20Sopenharmony_ci data[5] || data[6]); 2228c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_RX, 2238c2ecf20Sopenharmony_ci ((data[1] & 0x1f) << 8) | data[2]); 2248c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_RY, 2258c2ecf20Sopenharmony_ci ((data[3] & 0x1f) << 8) | data[4]); 2268c2ecf20Sopenharmony_ci input_report_key(input_dev, BTN_0, data[5] & 0x01); 2278c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 2288c2ecf20Sopenharmony_ci input_report_key(input_dev, 2298c2ecf20Sopenharmony_ci BTN_1 + i, data[5] & (1 << i)); 2308c2ecf20Sopenharmony_ci input_report_key(input_dev, 2318c2ecf20Sopenharmony_ci BTN_5 + i, data[6] & (1 << i)); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci case HANWANG_ART_MASTER_II: 2368c2ecf20Sopenharmony_ci dev_dbg(&dev->dev, "error packet %02x\n", data[0]); 2378c2ecf20Sopenharmony_ci return; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_MISC, hanwang->current_id); 2418c2ecf20Sopenharmony_ci input_event(input_dev, EV_MSC, MSC_SERIAL, 0xffffffff); 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci default: 2458c2ecf20Sopenharmony_ci dev_dbg(&dev->dev, "error packet %02x\n", data[0]); 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci input_sync(input_dev); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic void hanwang_irq(struct urb *urb) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct hanwang *hanwang = urb->context; 2558c2ecf20Sopenharmony_ci struct usb_device *dev = hanwang->usbdev; 2568c2ecf20Sopenharmony_ci int retval; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci switch (urb->status) { 2598c2ecf20Sopenharmony_ci case 0: 2608c2ecf20Sopenharmony_ci /* success */; 2618c2ecf20Sopenharmony_ci hanwang_parse_packet(hanwang); 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci case -ECONNRESET: 2648c2ecf20Sopenharmony_ci case -ENOENT: 2658c2ecf20Sopenharmony_ci case -ESHUTDOWN: 2668c2ecf20Sopenharmony_ci /* this urb is terminated, clean up */ 2678c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%s - urb shutting down with status: %d", 2688c2ecf20Sopenharmony_ci __func__, urb->status); 2698c2ecf20Sopenharmony_ci return; 2708c2ecf20Sopenharmony_ci default: 2718c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%s - nonzero urb status received: %d", 2728c2ecf20Sopenharmony_ci __func__, urb->status); 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 2778c2ecf20Sopenharmony_ci if (retval) 2788c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%s - usb_submit_urb failed with result %d", 2798c2ecf20Sopenharmony_ci __func__, retval); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int hanwang_open(struct input_dev *dev) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct hanwang *hanwang = input_get_drvdata(dev); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci hanwang->irq->dev = hanwang->usbdev; 2878c2ecf20Sopenharmony_ci if (usb_submit_urb(hanwang->irq, GFP_KERNEL)) 2888c2ecf20Sopenharmony_ci return -EIO; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void hanwang_close(struct input_dev *dev) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct hanwang *hanwang = input_get_drvdata(dev); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci usb_kill_urb(hanwang->irq); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic bool get_features(struct usb_device *dev, struct hanwang *hanwang) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci int i; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(features_array); i++) { 3058c2ecf20Sopenharmony_ci if (le16_to_cpu(dev->descriptor.idProduct) == 3068c2ecf20Sopenharmony_ci features_array[i].pid) { 3078c2ecf20Sopenharmony_ci hanwang->features = &features_array[i]; 3088c2ecf20Sopenharmony_ci return true; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return false; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int hanwang_probe(struct usb_interface *intf, const struct usb_device_id *id) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct usb_device *dev = interface_to_usbdev(intf); 3198c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 3208c2ecf20Sopenharmony_ci struct hanwang *hanwang; 3218c2ecf20Sopenharmony_ci struct input_dev *input_dev; 3228c2ecf20Sopenharmony_ci int error; 3238c2ecf20Sopenharmony_ci int i; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (intf->cur_altsetting->desc.bNumEndpoints < 1) 3268c2ecf20Sopenharmony_ci return -ENODEV; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci hanwang = kzalloc(sizeof(struct hanwang), GFP_KERNEL); 3298c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 3308c2ecf20Sopenharmony_ci if (!hanwang || !input_dev) { 3318c2ecf20Sopenharmony_ci error = -ENOMEM; 3328c2ecf20Sopenharmony_ci goto fail1; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (!get_features(dev, hanwang)) { 3368c2ecf20Sopenharmony_ci error = -ENXIO; 3378c2ecf20Sopenharmony_ci goto fail1; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci hanwang->data = usb_alloc_coherent(dev, hanwang->features->pkg_len, 3418c2ecf20Sopenharmony_ci GFP_KERNEL, &hanwang->data_dma); 3428c2ecf20Sopenharmony_ci if (!hanwang->data) { 3438c2ecf20Sopenharmony_ci error = -ENOMEM; 3448c2ecf20Sopenharmony_ci goto fail1; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci hanwang->irq = usb_alloc_urb(0, GFP_KERNEL); 3488c2ecf20Sopenharmony_ci if (!hanwang->irq) { 3498c2ecf20Sopenharmony_ci error = -ENOMEM; 3508c2ecf20Sopenharmony_ci goto fail2; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci hanwang->usbdev = dev; 3548c2ecf20Sopenharmony_ci hanwang->dev = input_dev; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci usb_make_path(dev, hanwang->phys, sizeof(hanwang->phys)); 3578c2ecf20Sopenharmony_ci strlcat(hanwang->phys, "/input0", sizeof(hanwang->phys)); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci strlcpy(hanwang->name, hanwang->features->name, sizeof(hanwang->name)); 3608c2ecf20Sopenharmony_ci input_dev->name = hanwang->name; 3618c2ecf20Sopenharmony_ci input_dev->phys = hanwang->phys; 3628c2ecf20Sopenharmony_ci usb_to_input_id(dev, &input_dev->id); 3638c2ecf20Sopenharmony_ci input_dev->dev.parent = &intf->dev; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci input_set_drvdata(input_dev, hanwang); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci input_dev->open = hanwang_open; 3688c2ecf20Sopenharmony_ci input_dev->close = hanwang_close; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hw_eventtypes); ++i) 3718c2ecf20Sopenharmony_ci __set_bit(hw_eventtypes[i], input_dev->evbit); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hw_absevents); ++i) 3748c2ecf20Sopenharmony_ci __set_bit(hw_absevents[i], input_dev->absbit); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hw_btnevents); ++i) 3778c2ecf20Sopenharmony_ci __set_bit(hw_btnevents[i], input_dev->keybit); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hw_mscevents); ++i) 3808c2ecf20Sopenharmony_ci __set_bit(hw_mscevents[i], input_dev->mscbit); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_X, 3838c2ecf20Sopenharmony_ci 0, hanwang->features->max_x, 4, 0); 3848c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_Y, 3858c2ecf20Sopenharmony_ci 0, hanwang->features->max_y, 4, 0); 3868c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_TILT_X, 3878c2ecf20Sopenharmony_ci 0, hanwang->features->max_tilt_x, 0, 0); 3888c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_TILT_Y, 3898c2ecf20Sopenharmony_ci 0, hanwang->features->max_tilt_y, 0, 0); 3908c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_PRESSURE, 3918c2ecf20Sopenharmony_ci 0, hanwang->features->max_pressure, 0, 0); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci endpoint = &intf->cur_altsetting->endpoint[0].desc; 3948c2ecf20Sopenharmony_ci usb_fill_int_urb(hanwang->irq, dev, 3958c2ecf20Sopenharmony_ci usb_rcvintpipe(dev, endpoint->bEndpointAddress), 3968c2ecf20Sopenharmony_ci hanwang->data, hanwang->features->pkg_len, 3978c2ecf20Sopenharmony_ci hanwang_irq, hanwang, endpoint->bInterval); 3988c2ecf20Sopenharmony_ci hanwang->irq->transfer_dma = hanwang->data_dma; 3998c2ecf20Sopenharmony_ci hanwang->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci error = input_register_device(hanwang->dev); 4028c2ecf20Sopenharmony_ci if (error) 4038c2ecf20Sopenharmony_ci goto fail3; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci usb_set_intfdata(intf, hanwang); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci fail3: usb_free_urb(hanwang->irq); 4108c2ecf20Sopenharmony_ci fail2: usb_free_coherent(dev, hanwang->features->pkg_len, 4118c2ecf20Sopenharmony_ci hanwang->data, hanwang->data_dma); 4128c2ecf20Sopenharmony_ci fail1: input_free_device(input_dev); 4138c2ecf20Sopenharmony_ci kfree(hanwang); 4148c2ecf20Sopenharmony_ci return error; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic void hanwang_disconnect(struct usb_interface *intf) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct hanwang *hanwang = usb_get_intfdata(intf); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci input_unregister_device(hanwang->dev); 4238c2ecf20Sopenharmony_ci usb_free_urb(hanwang->irq); 4248c2ecf20Sopenharmony_ci usb_free_coherent(interface_to_usbdev(intf), 4258c2ecf20Sopenharmony_ci hanwang->features->pkg_len, hanwang->data, 4268c2ecf20Sopenharmony_ci hanwang->data_dma); 4278c2ecf20Sopenharmony_ci kfree(hanwang); 4288c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic const struct usb_device_id hanwang_ids[] = { 4328c2ecf20Sopenharmony_ci { HANWANG_TABLET_DEVICE(USB_VENDOR_ID_HANWANG, HANWANG_TABLET_INT_CLASS, 4338c2ecf20Sopenharmony_ci HANWANG_TABLET_INT_SUB_CLASS, HANWANG_TABLET_INT_PROTOCOL) }, 4348c2ecf20Sopenharmony_ci {} 4358c2ecf20Sopenharmony_ci}; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, hanwang_ids); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic struct usb_driver hanwang_driver = { 4408c2ecf20Sopenharmony_ci .name = "hanwang", 4418c2ecf20Sopenharmony_ci .probe = hanwang_probe, 4428c2ecf20Sopenharmony_ci .disconnect = hanwang_disconnect, 4438c2ecf20Sopenharmony_ci .id_table = hanwang_ids, 4448c2ecf20Sopenharmony_ci}; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cimodule_usb_driver(hanwang_driver); 447