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-cypress.c (4714B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  HID driver for some cypress "special" devices
      4 *
      5 *  Copyright (c) 1999 Andreas Gal
      6 *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
      7 *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
      8 *  Copyright (c) 2006-2007 Jiri Kosina
      9 *  Copyright (c) 2008 Jiri Slaby
     10 */
     11
     12/*
     13 */
     14
     15#include <linux/device.h>
     16#include <linux/hid.h>
     17#include <linux/input.h>
     18#include <linux/module.h>
     19
     20#include "hid-ids.h"
     21
     22#define CP_RDESC_SWAPPED_MIN_MAX	0x01
     23#define CP_2WHEEL_MOUSE_HACK		0x02
     24#define CP_2WHEEL_MOUSE_HACK_ON		0x04
     25
     26#define VA_INVAL_LOGICAL_BOUNDARY	0x08
     27
     28/*
     29 * Some USB barcode readers from cypress have usage min and usage max in
     30 * the wrong order
     31 */
     32static __u8 *cp_rdesc_fixup(struct hid_device *hdev, __u8 *rdesc,
     33		unsigned int *rsize)
     34{
     35	unsigned int i;
     36
     37	if (*rsize < 4)
     38		return rdesc;
     39
     40	for (i = 0; i < *rsize - 4; i++)
     41		if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
     42			rdesc[i] = 0x19;
     43			rdesc[i + 2] = 0x29;
     44			swap(rdesc[i + 3], rdesc[i + 1]);
     45		}
     46	return rdesc;
     47}
     48
     49static __u8 *va_logical_boundary_fixup(struct hid_device *hdev, __u8 *rdesc,
     50		unsigned int *rsize)
     51{
     52	/*
     53	 * Varmilo VA104M (with VID Cypress and device ID 07B1) incorrectly
     54	 * reports Logical Minimum of its Consumer Control device as 572
     55	 * (0x02 0x3c). Fix this by setting its Logical Minimum to zero.
     56	 */
     57	if (*rsize == 25 &&
     58			rdesc[0] == 0x05 && rdesc[1] == 0x0c &&
     59			rdesc[2] == 0x09 && rdesc[3] == 0x01 &&
     60			rdesc[6] == 0x19 && rdesc[7] == 0x00 &&
     61			rdesc[11] == 0x16 && rdesc[12] == 0x3c && rdesc[13] == 0x02) {
     62		hid_info(hdev,
     63			 "fixing up varmilo VA104M consumer control report descriptor\n");
     64		rdesc[12] = 0x00;
     65		rdesc[13] = 0x00;
     66	}
     67	return rdesc;
     68}
     69
     70static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
     71		unsigned int *rsize)
     72{
     73	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
     74
     75	if (quirks & CP_RDESC_SWAPPED_MIN_MAX)
     76		rdesc = cp_rdesc_fixup(hdev, rdesc, rsize);
     77	if (quirks & VA_INVAL_LOGICAL_BOUNDARY)
     78		rdesc = va_logical_boundary_fixup(hdev, rdesc, rsize);
     79
     80	return rdesc;
     81}
     82
     83static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
     84		struct hid_field *field, struct hid_usage *usage,
     85		unsigned long **bit, int *max)
     86{
     87	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
     88
     89	if (!(quirks & CP_2WHEEL_MOUSE_HACK))
     90		return 0;
     91
     92	if (usage->type == EV_REL && usage->code == REL_WHEEL)
     93		set_bit(REL_HWHEEL, *bit);
     94	if (usage->hid == 0x00090005)
     95		return -1;
     96
     97	return 0;
     98}
     99
    100static int cp_event(struct hid_device *hdev, struct hid_field *field,
    101		struct hid_usage *usage, __s32 value)
    102{
    103	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
    104
    105	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
    106			!usage->type || !(quirks & CP_2WHEEL_MOUSE_HACK))
    107		return 0;
    108
    109	if (usage->hid == 0x00090005) {
    110		if (value)
    111			quirks |=  CP_2WHEEL_MOUSE_HACK_ON;
    112		else
    113			quirks &= ~CP_2WHEEL_MOUSE_HACK_ON;
    114		hid_set_drvdata(hdev, (void *)quirks);
    115		return 1;
    116	}
    117
    118	if (usage->code == REL_WHEEL && (quirks & CP_2WHEEL_MOUSE_HACK_ON)) {
    119		struct input_dev *input = field->hidinput->input;
    120
    121		input_event(input, usage->type, REL_HWHEEL, value);
    122		return 1;
    123	}
    124
    125	return 0;
    126}
    127
    128static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
    129{
    130	unsigned long quirks = id->driver_data;
    131	int ret;
    132
    133	hid_set_drvdata(hdev, (void *)quirks);
    134
    135	ret = hid_parse(hdev);
    136	if (ret) {
    137		hid_err(hdev, "parse failed\n");
    138		goto err_free;
    139	}
    140
    141	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
    142	if (ret) {
    143		hid_err(hdev, "hw start failed\n");
    144		goto err_free;
    145	}
    146
    147	return 0;
    148err_free:
    149	return ret;
    150}
    151
    152static const struct hid_device_id cp_devices[] = {
    153	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1),
    154		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
    155	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2),
    156		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
    157	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3),
    158		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
    159	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4),
    160		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
    161	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
    162		.driver_data = CP_2WHEEL_MOUSE_HACK },
    163	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1),
    164		.driver_data = VA_INVAL_LOGICAL_BOUNDARY },
    165	{ }
    166};
    167MODULE_DEVICE_TABLE(hid, cp_devices);
    168
    169static struct hid_driver cp_driver = {
    170	.name = "cypress",
    171	.id_table = cp_devices,
    172	.report_fixup = cp_report_fixup,
    173	.input_mapped = cp_input_mapped,
    174	.event = cp_event,
    175	.probe = cp_probe,
    176};
    177module_hid_driver(cp_driver);
    178
    179MODULE_LICENSE("GPL");