Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a786e83c authored by Nikolai Kondrashov's avatar Nikolai Kondrashov Committed by Jiri Kosina
Browse files

HID: waltop: Add support for tablet with PID 0038



Add support for unknown Waltop tablet with product ID 0x0038.
This tablet is sold as Genius G-Pen F509.

Signed-off-by: default avatarNikolai Kondrashov <spbnick@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 56d27dd6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1566,6 +1566,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_XAT, USB_DEVICE_ID_XAT_CSR) },
+1 −0
Original line number Diff line number Diff line
@@ -713,6 +713,7 @@
#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH	0x0032
#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH	0x0034
#define USB_DEVICE_ID_WALTOP_Q_PAD			0x0037
#define USB_DEVICE_ID_WALTOP_PID_0038			0x0038
#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH	0x0501
#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH	0x0500

+148 −0
Original line number Diff line number Diff line
@@ -210,6 +210,64 @@ static __u8 q_pad_rdesc_fixed[] = {
	0xC0                /*  End Collection                      */
};

/*
 * See description, device and HID report descriptors of tablet with PID 0038 at
 * http://sf.net/apps/mediawiki/digimend/?title=Waltop_PID_0038
 */

/* Size of the original report descriptor of tablet with PID 0038 */
#define PID_0038_RDESC_ORIG_SIZE	241

/*
 * Fixed report descriptor for tablet with PID 0038.
 */
static __u8 pid_0038_rdesc_fixed[] = {
	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
	0x09, 0x02,         /*  Usage (Pen),                        */
	0xA1, 0x01,         /*  Collection (Application),           */
	0x85, 0x10,         /*      Report ID (16),                 */
	0x09, 0x20,         /*      Usage (Stylus),                 */
	0xA0,               /*      Collection (Physical),          */
	0x09, 0x42,         /*          Usage (Tip Switch),         */
	0x09, 0x44,         /*          Usage (Barrel Switch),      */
	0x09, 0x46,         /*          Usage (Tablet Pick),        */
	0x15, 0x01,         /*          Logical Minimum (1),        */
	0x25, 0x03,         /*          Logical Maximum (3),        */
	0x75, 0x04,         /*          Report Size (4),            */
	0x95, 0x01,         /*          Report Count (1),           */
	0x80,               /*          Input,                      */
	0x09, 0x32,         /*          Usage (In Range),           */
	0x14,               /*          Logical Minimum (0),        */
	0x25, 0x01,         /*          Logical Maximum (1),        */
	0x75, 0x01,         /*          Report Size (1),            */
	0x95, 0x01,         /*          Report Count (1),           */
	0x81, 0x02,         /*          Input (Variable),           */
	0x95, 0x03,         /*          Report Count (3),           */
	0x81, 0x03,         /*          Input (Constant, Variable), */
	0x75, 0x10,         /*          Report Size (16),           */
	0x95, 0x01,         /*          Report Count (1),           */
	0x14,               /*          Logical Minimum (0),        */
	0xA4,               /*          Push,                       */
	0x05, 0x01,         /*          Usage Page (Desktop),       */
	0x65, 0x13,         /*          Unit (Inch),                */
	0x55, 0xFD,         /*          Unit Exponent (-3),         */
	0x34,               /*          Physical Minimum (0),       */
	0x09, 0x30,         /*          Usage (X),                  */
	0x46, 0x2E, 0x22,   /*          Physical Maximum (8750),    */
	0x26, 0x00, 0x46,   /*          Logical Maximum (17920),    */
	0x81, 0x02,         /*          Input (Variable),           */
	0x09, 0x31,         /*          Usage (Y),                  */
	0x46, 0x82, 0x14,   /*          Physical Maximum (5250),    */
	0x26, 0x00, 0x2A,   /*          Logical Maximum (10752),    */
	0x81, 0x02,         /*          Input (Variable),           */
	0xB4,               /*          Pop,                        */
	0x09, 0x30,         /*          Usage (Tip Pressure),       */
	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
	0x81, 0x02,         /*          Input (Variable),           */
	0xC0,               /*      End Collection,                 */
	0xC0                /*  End Collection                      */
};

/*
 * See Media Tablet 10.6 inch description, device and HID report descriptors at
 * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Media_Tablet_10.6%22
@@ -444,6 +502,47 @@ static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
	0xC0                /*  End Collection                      */
};

struct waltop_state {
	u8 pressure0;
	u8 pressure1;
};

static int waltop_probe(struct hid_device *hdev,
			const struct hid_device_id *id)
{
	int ret;
	struct waltop_state *s;

	s = kzalloc(sizeof(*s), GFP_KERNEL);
	if (s == NULL) {
		hid_err(hdev, "can't allocate device state\n");
		ret = -ENOMEM;
		goto err;
	}

	s->pressure0 = 0;
	s->pressure1 = 0;

	hid_set_drvdata(hdev, s);

	ret = hid_parse(hdev);
	if (ret) {
		hid_err(hdev, "parse failed\n");
		goto err;
	}

	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
	if (ret) {
		hid_err(hdev, "hw start failed\n");
		goto err;
	}

	return 0;
err:
	kfree(s);
	return ret;
}

static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
@@ -466,6 +565,12 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
			*rsize = sizeof(q_pad_rdesc_fixed);
		}
		break;
	case USB_DEVICE_ID_WALTOP_PID_0038:
		if (*rsize == PID_0038_RDESC_ORIG_SIZE) {
			rdesc = pid_0038_rdesc_fixed;
			*rsize = sizeof(pid_0038_rdesc_fixed);
		}
		break;
	case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH:
		if (*rsize == MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE) {
			rdesc = media_tablet_10_6_inch_rdesc_fixed;
@@ -482,6 +587,44 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
	return rdesc;
}

static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
		     u8 *data, int size)
{
	/* If this is a pen input report of a tablet with PID 0038 */
	if (hdev->product == USB_DEVICE_ID_WALTOP_PID_0038 &&
	    report->type == HID_INPUT_REPORT &&
	    report->id == 16 &&
	    size == 8) {
		struct waltop_state *s = hid_get_drvdata(hdev);

		/*
		 * Ignore maximum pressure reported when a barrel button is
		 * pressed.
		 */

		/* If a barrel button is pressed */
		if ((data[1] & 0xF) > 1) {
			/* Use the last known pressure */
			data[6] = s->pressure0;
			data[7] = s->pressure1;
		} else {
			/* Remember reported pressure */
			s->pressure0 = data[6];
			s->pressure1 = data[7];
		}
	}

	return 0;
}

static void waltop_remove(struct hid_device *hdev)
{
	struct waltop_state *s = hid_get_drvdata(hdev);

	hid_hw_stop(hdev);
	kfree(s);
}

static const struct hid_device_id waltop_devices[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
				USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
@@ -489,6 +632,8 @@ static const struct hid_device_id waltop_devices[] = {
				USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
				USB_DEVICE_ID_WALTOP_Q_PAD) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
				USB_DEVICE_ID_WALTOP_PID_0038) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
@@ -500,7 +645,10 @@ MODULE_DEVICE_TABLE(hid, waltop_devices);
static struct hid_driver waltop_driver = {
	.name = "waltop",
	.id_table = waltop_devices,
	.probe = waltop_probe,
	.report_fixup = waltop_report_fixup,
	.raw_event = waltop_raw_event,
	.remove = waltop_remove,
};

static int __init waltop_init(void)