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