// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2021 Hans de Goede <[email protected]> * * Driver for the LetSketch / VSON WP9620N drawing tablet. * This drawing tablet is also sold under other brand names such as Case U, * presumably this driver will work for all of them. But it has only been * tested with a LetSketch WP9620N model. * * These tablets also work without a special HID driver, but then only part * of the active area works and both the pad and stylus buttons are hardwired * to special key-combos. E.g. the 2 stylus buttons send right mouse clicks / * resp. "e" key presses. * * This device has 4 USB interfaces: * * Interface 0 EP 0x81 bootclass mouse, rdesc len 18, report id 0x08, * Application(ff00.0001) * This interface sends raw event input reports in a custom format, but only * after doing the special dance from letsketch_probe(). After enabling this * interface the other 3 interfaces are disabled. * * Interface 1 EP 0x82 bootclass mouse, rdesc len 83, report id 0x0a, Tablet * This interface sends absolute events for the pen, including pressure, * but only for some part of the active area due to special "aspect ratio" * correction and only half by default since it assumes it will be used * with a phone in portraid mode, while using the tablet in landscape mode. * Also stylus + pad button events are not reported here. * * Interface 2 EP 0x83 bootclass keybd, rdesc len 64, report id none, Std Kbd * This interfaces send various hard-coded key-combos for the pad buttons * and "e" keypresses for the 2nd stylus button * * Interface 3 EP 0x84 bootclass mouse, rdesc len 75, report id 0x01, Std Mouse * This reports right-click mouse-button events for the 1st stylus button */ #include <linux/device.h> #include <linux/input.h> #include <linux/hid.h> #include <linux/module.h> #include <linux/timer.h> #include <linux/usb.h> #include <asm/unaligned.h> #include "hid-ids.h" #define LETSKETCH_RAW_IF … #define LETSKETCH_RAW_DATA_LEN … #define LETSKETCH_RAW_REPORT_ID … #define LETSKETCH_PAD_BUTTONS … #define LETSKETCH_INFO_STR_IDX_BEGIN … #define LETSKETCH_INFO_STR_IDX_END … #define LETSKETCH_GET_STRING_RETRIES … struct letsketch_data { … }; static int letsketch_open(struct input_dev *dev) { … } static void letsketch_close(struct input_dev *dev) { … } static struct input_dev *letsketch_alloc_input_dev(struct letsketch_data *data) { … } static int letsketch_setup_input_tablet(struct letsketch_data *data) { … } static int letsketch_setup_input_tablet_pad(struct letsketch_data *data) { … } static void letsketch_inrange_timeout(struct timer_list *t) { … } static int letsketch_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *raw_data, int size) { … } /* * The tablets magic handshake to put it in raw mode relies on getting * string descriptors. But the firmware is buggy and does not like it if * we do this too fast. Even if we go slow sometimes the usb_string() call * fails. Ignore errors and retry it a couple of times if necessary. */ static int letsketch_get_string(struct usb_device *udev, int index, char *buf, int size) { … } static int letsketch_probe(struct hid_device *hdev, const struct hid_device_id *id) { … } static const struct hid_device_id letsketch_devices[] = …; MODULE_DEVICE_TABLE(hid, letsketch_devices); static struct hid_driver letsketch_driver = …; module_hid_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;