cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hid-uclogic-core.c (14876B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *  HID driver for UC-Logic devices not fully compliant with HID standard
      4 *
      5 *  Copyright (c) 2010-2014 Nikolai Kondrashov
      6 *  Copyright (c) 2013 Martin Rusko
      7 */
      8
      9/*
     10 * This program is free software; you can redistribute it and/or modify it
     11 * under the terms of the GNU General Public License as published by the Free
     12 * Software Foundation; either version 2 of the License, or (at your option)
     13 * any later version.
     14 */
     15
     16#include <linux/device.h>
     17#include <linux/hid.h>
     18#include <linux/module.h>
     19#include <linux/timer.h>
     20#include "usbhid/usbhid.h"
     21#include "hid-uclogic-params.h"
     22
     23#include "hid-ids.h"
     24
     25/* Driver data */
     26struct uclogic_drvdata {
     27	/* Interface parameters */
     28	struct uclogic_params params;
     29	/* Pointer to the replacement report descriptor. NULL if none. */
     30	__u8 *desc_ptr;
     31	/*
     32	 * Size of the replacement report descriptor.
     33	 * Only valid if desc_ptr is not NULL
     34	 */
     35	unsigned int desc_size;
     36	/* Pen input device */
     37	struct input_dev *pen_input;
     38	/* In-range timer */
     39	struct timer_list inrange_timer;
     40	/* Last rotary encoder state, or U8_MAX for none */
     41	u8 re_state;
     42};
     43
     44/**
     45 * uclogic_inrange_timeout - handle pen in-range state timeout.
     46 * Emulate input events normally generated when pen goes out of range for
     47 * tablets which don't report that.
     48 *
     49 * @t:	The timer the timeout handler is attached to, stored in a struct
     50 *	uclogic_drvdata.
     51 */
     52static void uclogic_inrange_timeout(struct timer_list *t)
     53{
     54	struct uclogic_drvdata *drvdata = from_timer(drvdata, t,
     55							inrange_timer);
     56	struct input_dev *input = drvdata->pen_input;
     57
     58	if (input == NULL)
     59		return;
     60	input_report_abs(input, ABS_PRESSURE, 0);
     61	/* If BTN_TOUCH state is changing */
     62	if (test_bit(BTN_TOUCH, input->key)) {
     63		input_event(input, EV_MSC, MSC_SCAN,
     64				/* Digitizer Tip Switch usage */
     65				0xd0042);
     66		input_report_key(input, BTN_TOUCH, 0);
     67	}
     68	input_report_key(input, BTN_TOOL_PEN, 0);
     69	input_sync(input);
     70}
     71
     72static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
     73					unsigned int *rsize)
     74{
     75	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
     76
     77	if (drvdata->desc_ptr != NULL) {
     78		rdesc = drvdata->desc_ptr;
     79		*rsize = drvdata->desc_size;
     80	}
     81	return rdesc;
     82}
     83
     84static int uclogic_input_mapping(struct hid_device *hdev,
     85				 struct hid_input *hi,
     86				 struct hid_field *field,
     87				 struct hid_usage *usage,
     88				 unsigned long **bit,
     89				 int *max)
     90{
     91	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
     92	struct uclogic_params *params = &drvdata->params;
     93
     94	/* Discard invalid pen usages */
     95	if (params->pen.usage_invalid && (field->application == HID_DG_PEN))
     96		return -1;
     97
     98	/* Let hid-core decide what to do */
     99	return 0;
    100}
    101
    102static int uclogic_input_configured(struct hid_device *hdev,
    103		struct hid_input *hi)
    104{
    105	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
    106	struct uclogic_params *params = &drvdata->params;
    107	char *name;
    108	const char *suffix = NULL;
    109	struct hid_field *field;
    110	size_t len;
    111	size_t i;
    112	const struct uclogic_params_frame *frame;
    113
    114	/* no report associated (HID_QUIRK_MULTI_INPUT not set) */
    115	if (!hi->report)
    116		return 0;
    117
    118	/*
    119	 * If this is the input corresponding to the pen report
    120	 * in need of tweaking.
    121	 */
    122	if (hi->report->id == params->pen.id) {
    123		/* Remember the input device so we can simulate events */
    124		drvdata->pen_input = hi->input;
    125	}
    126
    127	/* If it's one of the frame devices */
    128	for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
    129		frame = &params->frame_list[i];
    130		if (hi->report->id == frame->id) {
    131			/* Assign custom suffix, if any */
    132			suffix = frame->suffix;
    133			/*
    134			 * Disable EV_MSC reports for touch ring interfaces to
    135			 * make the Wacom driver pickup touch ring extents
    136			 */
    137			if (frame->touch_byte > 0)
    138				__clear_bit(EV_MSC, hi->input->evbit);
    139		}
    140	}
    141
    142	if (!suffix) {
    143		field = hi->report->field[0];
    144
    145		switch (field->application) {
    146		case HID_GD_KEYBOARD:
    147			suffix = "Keyboard";
    148			break;
    149		case HID_GD_MOUSE:
    150			suffix = "Mouse";
    151			break;
    152		case HID_GD_KEYPAD:
    153			suffix = "Pad";
    154			break;
    155		case HID_DG_PEN:
    156			suffix = "Pen";
    157			break;
    158		case HID_CP_CONSUMER_CONTROL:
    159			suffix = "Consumer Control";
    160			break;
    161		case HID_GD_SYSTEM_CONTROL:
    162			suffix = "System Control";
    163			break;
    164		}
    165	}
    166
    167	if (suffix) {
    168		len = strlen(hdev->name) + 2 + strlen(suffix);
    169		name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL);
    170		if (name) {
    171			snprintf(name, len, "%s %s", hdev->name, suffix);
    172			hi->input->name = name;
    173		}
    174	}
    175
    176	return 0;
    177}
    178
    179static int uclogic_probe(struct hid_device *hdev,
    180		const struct hid_device_id *id)
    181{
    182	int rc;
    183	struct uclogic_drvdata *drvdata = NULL;
    184	bool params_initialized = false;
    185
    186	if (!hid_is_usb(hdev))
    187		return -EINVAL;
    188
    189	/*
    190	 * libinput requires the pad interface to be on a different node
    191	 * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
    192	 */
    193	hdev->quirks |= HID_QUIRK_MULTI_INPUT;
    194
    195	/* Allocate and assign driver data */
    196	drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
    197	if (drvdata == NULL) {
    198		rc = -ENOMEM;
    199		goto failure;
    200	}
    201	timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0);
    202	drvdata->re_state = U8_MAX;
    203	hid_set_drvdata(hdev, drvdata);
    204
    205	/* Initialize the device and retrieve interface parameters */
    206	rc = uclogic_params_init(&drvdata->params, hdev);
    207	if (rc != 0) {
    208		hid_err(hdev, "failed probing parameters: %d\n", rc);
    209		goto failure;
    210	}
    211	params_initialized = true;
    212	hid_dbg(hdev, "parameters:\n");
    213	uclogic_params_hid_dbg(hdev, &drvdata->params);
    214	if (drvdata->params.invalid) {
    215		hid_info(hdev, "interface is invalid, ignoring\n");
    216		rc = -ENODEV;
    217		goto failure;
    218	}
    219
    220	/* Generate replacement report descriptor */
    221	rc = uclogic_params_get_desc(&drvdata->params,
    222				     &drvdata->desc_ptr,
    223				     &drvdata->desc_size);
    224	if (rc) {
    225		hid_err(hdev,
    226			"failed generating replacement report descriptor: %d\n",
    227			rc);
    228		goto failure;
    229	}
    230
    231	rc = hid_parse(hdev);
    232	if (rc) {
    233		hid_err(hdev, "parse failed\n");
    234		goto failure;
    235	}
    236
    237	rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
    238	if (rc) {
    239		hid_err(hdev, "hw start failed\n");
    240		goto failure;
    241	}
    242
    243	return 0;
    244failure:
    245	/* Assume "remove" might not be called if "probe" failed */
    246	if (params_initialized)
    247		uclogic_params_cleanup(&drvdata->params);
    248	return rc;
    249}
    250
    251#ifdef CONFIG_PM
    252static int uclogic_resume(struct hid_device *hdev)
    253{
    254	int rc;
    255	struct uclogic_params params;
    256
    257	/* Re-initialize the device, but discard parameters */
    258	rc = uclogic_params_init(&params, hdev);
    259	if (rc != 0)
    260		hid_err(hdev, "failed to re-initialize the device\n");
    261	else
    262		uclogic_params_cleanup(&params);
    263
    264	return rc;
    265}
    266#endif
    267
    268/**
    269 * uclogic_raw_event_pen - handle raw pen events (pen HID reports).
    270 *
    271 * @drvdata:	Driver data.
    272 * @data:	Report data buffer, can be modified.
    273 * @size:	Report data size, bytes.
    274 *
    275 * Returns:
    276 *	Negative value on error (stops event delivery), zero for success.
    277 */
    278static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata,
    279					u8 *data, int size)
    280{
    281	struct uclogic_params_pen *pen = &drvdata->params.pen;
    282
    283	WARN_ON(drvdata == NULL);
    284	WARN_ON(data == NULL && size != 0);
    285
    286	/* If in-range reports are inverted */
    287	if (pen->inrange ==
    288		UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
    289		/* Invert the in-range bit */
    290		data[1] ^= 0x40;
    291	}
    292	/*
    293	 * If report contains fragmented high-resolution pen
    294	 * coordinates
    295	 */
    296	if (size >= 10 && pen->fragmented_hires) {
    297		u8 pressure_low_byte;
    298		u8 pressure_high_byte;
    299
    300		/* Lift pressure bytes */
    301		pressure_low_byte = data[6];
    302		pressure_high_byte = data[7];
    303		/*
    304		 * Move Y coord to make space for high-order X
    305		 * coord byte
    306		 */
    307		data[6] = data[5];
    308		data[5] = data[4];
    309		/* Move high-order X coord byte */
    310		data[4] = data[8];
    311		/* Move high-order Y coord byte */
    312		data[7] = data[9];
    313		/* Place pressure bytes */
    314		data[8] = pressure_low_byte;
    315		data[9] = pressure_high_byte;
    316	}
    317	/* If we need to emulate in-range detection */
    318	if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
    319		/* Set in-range bit */
    320		data[1] |= 0x40;
    321		/* (Re-)start in-range timeout */
    322		mod_timer(&drvdata->inrange_timer,
    323				jiffies + msecs_to_jiffies(100));
    324	}
    325	/* If we report tilt and Y direction is flipped */
    326	if (size >= 12 && pen->tilt_y_flipped)
    327		data[11] = -data[11];
    328
    329	return 0;
    330}
    331
    332/**
    333 * uclogic_raw_event_frame - handle raw frame events (frame HID reports).
    334 *
    335 * @drvdata:	Driver data.
    336 * @frame:	The parameters of the frame controls to handle.
    337 * @data:	Report data buffer, can be modified.
    338 * @size:	Report data size, bytes.
    339 *
    340 * Returns:
    341 *	Negative value on error (stops event delivery), zero for success.
    342 */
    343static int uclogic_raw_event_frame(
    344		struct uclogic_drvdata *drvdata,
    345		const struct uclogic_params_frame *frame,
    346		u8 *data, int size)
    347{
    348	WARN_ON(drvdata == NULL);
    349	WARN_ON(data == NULL && size != 0);
    350
    351	/* If need to, and can, set pad device ID for Wacom drivers */
    352	if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) {
    353		/* If we also have a touch ring and the finger left it */
    354		if (frame->touch_byte > 0 && frame->touch_byte < size &&
    355		    data[frame->touch_byte] == 0) {
    356			data[frame->dev_id_byte] = 0;
    357		} else {
    358			data[frame->dev_id_byte] = 0xf;
    359		}
    360	}
    361
    362	/* If need to, and can, read rotary encoder state change */
    363	if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) {
    364		unsigned int byte = frame->re_lsb / 8;
    365		unsigned int bit = frame->re_lsb % 8;
    366
    367		u8 change;
    368		u8 prev_state = drvdata->re_state;
    369		/* Read Gray-coded state */
    370		u8 state = (data[byte] >> bit) & 0x3;
    371		/* Encode state change into 2-bit signed integer */
    372		if ((prev_state == 1 && state == 0) ||
    373		    (prev_state == 2 && state == 3)) {
    374			change = 1;
    375		} else if ((prev_state == 2 && state == 0) ||
    376			   (prev_state == 1 && state == 3)) {
    377			change = 3;
    378		} else {
    379			change = 0;
    380		}
    381		/* Write change */
    382		data[byte] = (data[byte] & ~((u8)3 << bit)) |
    383				(change << bit);
    384		/* Remember state */
    385		drvdata->re_state = state;
    386	}
    387
    388	/* If need to, and can, transform the touch ring reports */
    389	if (frame->touch_byte > 0 && frame->touch_byte < size) {
    390		__s8 value = data[frame->touch_byte];
    391
    392		if (value != 0) {
    393			if (frame->touch_flip_at != 0) {
    394				value = frame->touch_flip_at - value;
    395				if (value <= 0)
    396					value = frame->touch_max + value;
    397			}
    398			data[frame->touch_byte] = value - 1;
    399		}
    400	}
    401
    402	/* If need to, and can, transform the bitmap dial reports */
    403	if (frame->bitmap_dial_byte > 0 && frame->bitmap_dial_byte < size) {
    404		if (data[frame->bitmap_dial_byte] == 2)
    405			data[frame->bitmap_dial_byte] = -1;
    406	}
    407
    408	return 0;
    409}
    410
    411static int uclogic_raw_event(struct hid_device *hdev,
    412				struct hid_report *report,
    413				u8 *data, int size)
    414{
    415	unsigned int report_id = report->id;
    416	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
    417	struct uclogic_params *params = &drvdata->params;
    418	struct uclogic_params_pen_subreport *subreport;
    419	struct uclogic_params_pen_subreport *subreport_list_end;
    420	size_t i;
    421
    422	/* Do not handle anything but input reports */
    423	if (report->type != HID_INPUT_REPORT)
    424		return 0;
    425
    426	while (true) {
    427		/* Tweak pen reports, if necessary */
    428		if ((report_id == params->pen.id) && (size >= 2)) {
    429			subreport_list_end =
    430				params->pen.subreport_list +
    431				ARRAY_SIZE(params->pen.subreport_list);
    432			/* Try to match a subreport */
    433			for (subreport = params->pen.subreport_list;
    434			     subreport < subreport_list_end; subreport++) {
    435				if (subreport->value != 0 &&
    436				    subreport->value == data[1]) {
    437					break;
    438				}
    439			}
    440			/* If a subreport matched */
    441			if (subreport < subreport_list_end) {
    442				/* Change to subreport ID, and restart */
    443				report_id = data[0] = subreport->id;
    444				continue;
    445			} else {
    446				return uclogic_raw_event_pen(drvdata, data, size);
    447			}
    448		}
    449
    450		/* Tweak frame control reports, if necessary */
    451		for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
    452			if (report_id == params->frame_list[i].id) {
    453				return uclogic_raw_event_frame(
    454					drvdata, &params->frame_list[i],
    455					data, size);
    456			}
    457		}
    458
    459		break;
    460	}
    461
    462	return 0;
    463}
    464
    465static void uclogic_remove(struct hid_device *hdev)
    466{
    467	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
    468
    469	del_timer_sync(&drvdata->inrange_timer);
    470	hid_hw_stop(hdev);
    471	kfree(drvdata->desc_ptr);
    472	uclogic_params_cleanup(&drvdata->params);
    473}
    474
    475static const struct hid_device_id uclogic_devices[] = {
    476	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    477				USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
    478	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    479				USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
    480	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    481				USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
    482	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    483				USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
    484	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    485				USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
    486	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    487				USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
    488	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    489				USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
    490	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
    491				USB_DEVICE_ID_HUION_TABLET) },
    492	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
    493				USB_DEVICE_ID_HUION_TABLET2) },
    494	{ HID_USB_DEVICE(USB_VENDOR_ID_TRUST,
    495				USB_DEVICE_ID_TRUST_PANORA_TABLET) },
    496	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    497				USB_DEVICE_ID_HUION_TABLET) },
    498	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    499				USB_DEVICE_ID_YIYNOVA_TABLET) },
    500	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    501				USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81) },
    502	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    503				USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45) },
    504	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    505				USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47) },
    506	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
    507				USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
    508	{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
    509				USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
    510	{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
    511				USB_DEVICE_ID_UGTIZER_TABLET_GT5040) },
    512	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
    513				USB_DEVICE_ID_UGEE_TABLET_G5) },
    514	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
    515				USB_DEVICE_ID_UGEE_TABLET_EX07S) },
    516	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
    517				USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720) },
    518	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
    519				USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540) },
    520	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
    521				USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
    522	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
    523				USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
    524	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
    525				USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
    526	{ }
    527};
    528MODULE_DEVICE_TABLE(hid, uclogic_devices);
    529
    530static struct hid_driver uclogic_driver = {
    531	.name = "uclogic",
    532	.id_table = uclogic_devices,
    533	.probe = uclogic_probe,
    534	.remove = uclogic_remove,
    535	.report_fixup = uclogic_report_fixup,
    536	.raw_event = uclogic_raw_event,
    537	.input_mapping = uclogic_input_mapping,
    538	.input_configured = uclogic_input_configured,
    539#ifdef CONFIG_PM
    540	.resume	          = uclogic_resume,
    541	.reset_resume     = uclogic_resume,
    542#endif
    543};
    544module_hid_driver(uclogic_driver);
    545
    546MODULE_AUTHOR("Martin Rusko");
    547MODULE_AUTHOR("Nikolai Kondrashov");
    548MODULE_LICENSE("GPL");