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-chicony.c (4336B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  HID driver for some chicony "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) 2007 Paul Walmsley
     10 *  Copyright (c) 2008 Jiri Slaby
     11 */
     12
     13/*
     14 */
     15
     16#include <linux/device.h>
     17#include <linux/input.h>
     18#include <linux/hid.h>
     19#include <linux/module.h>
     20#include <linux/usb.h>
     21
     22#include "hid-ids.h"
     23
     24#define CH_WIRELESS_CTL_REPORT_ID	0x11
     25
     26static int ch_report_wireless(struct hid_report *report, u8 *data, int size)
     27{
     28	struct hid_device *hdev = report->device;
     29	struct input_dev *input;
     30
     31	if (report->id != CH_WIRELESS_CTL_REPORT_ID || report->maxfield != 1)
     32		return 0;
     33
     34	input = report->field[0]->hidinput->input;
     35	if (!input) {
     36		hid_warn(hdev, "can't find wireless radio control's input");
     37		return 0;
     38	}
     39
     40	input_report_key(input, KEY_RFKILL, 1);
     41	input_sync(input);
     42	input_report_key(input, KEY_RFKILL, 0);
     43	input_sync(input);
     44
     45	return 1;
     46}
     47
     48static int ch_raw_event(struct hid_device *hdev,
     49		struct hid_report *report, u8 *data, int size)
     50{
     51	if (report->application == HID_GD_WIRELESS_RADIO_CTLS)
     52		return ch_report_wireless(report, data, size);
     53
     54	return 0;
     55}
     56
     57#define ch_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
     58					EV_KEY, (c))
     59static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
     60		struct hid_field *field, struct hid_usage *usage,
     61		unsigned long **bit, int *max)
     62{
     63	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
     64		return 0;
     65
     66	set_bit(EV_REP, hi->input->evbit);
     67	switch (usage->hid & HID_USAGE) {
     68	case 0xff01: ch_map_key_clear(BTN_1);	break;
     69	case 0xff02: ch_map_key_clear(BTN_2);	break;
     70	case 0xff03: ch_map_key_clear(BTN_3);	break;
     71	case 0xff04: ch_map_key_clear(BTN_4);	break;
     72	case 0xff05: ch_map_key_clear(BTN_5);	break;
     73	case 0xff06: ch_map_key_clear(BTN_6);	break;
     74	case 0xff07: ch_map_key_clear(BTN_7);	break;
     75	case 0xff08: ch_map_key_clear(BTN_8);	break;
     76	case 0xff09: ch_map_key_clear(BTN_9);	break;
     77	case 0xff0a: ch_map_key_clear(BTN_A);	break;
     78	case 0xff0b: ch_map_key_clear(BTN_B);	break;
     79	case 0x00f1: ch_map_key_clear(KEY_WLAN);	break;
     80	case 0x00f2: ch_map_key_clear(KEY_BRIGHTNESSDOWN);	break;
     81	case 0x00f3: ch_map_key_clear(KEY_BRIGHTNESSUP);	break;
     82	case 0x00f4: ch_map_key_clear(KEY_DISPLAY_OFF);	break;
     83	case 0x00f7: ch_map_key_clear(KEY_CAMERA);	break;
     84	case 0x00f8: ch_map_key_clear(KEY_PROG1);	break;
     85	default:
     86		return 0;
     87	}
     88	return 1;
     89}
     90
     91static __u8 *ch_switch12_report_fixup(struct hid_device *hdev, __u8 *rdesc,
     92		unsigned int *rsize)
     93{
     94	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
     95	
     96	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
     97		/* Change usage maximum and logical maximum from 0x7fff to
     98		 * 0x2fff, so they don't exceed HID_MAX_USAGES */
     99		switch (hdev->product) {
    100		case USB_DEVICE_ID_CHICONY_ACER_SWITCH12:
    101			if (*rsize >= 128 && rdesc[64] == 0xff && rdesc[65] == 0x7f
    102					&& rdesc[69] == 0xff && rdesc[70] == 0x7f) {
    103				hid_info(hdev, "Fixing up report descriptor\n");
    104				rdesc[65] = rdesc[70] = 0x2f;
    105			}
    106			break;
    107		}
    108
    109	}
    110	return rdesc;
    111}
    112
    113static int ch_probe(struct hid_device *hdev, const struct hid_device_id *id)
    114{
    115	int ret;
    116
    117	if (!hid_is_usb(hdev))
    118		return -EINVAL;
    119
    120	hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
    121	ret = hid_parse(hdev);
    122	if (ret) {
    123		hid_err(hdev, "Chicony hid parse failed: %d\n", ret);
    124		return ret;
    125	}
    126
    127	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
    128	if (ret) {
    129		hid_err(hdev, "Chicony hw start failed: %d\n", ret);
    130		return ret;
    131	}
    132
    133	return 0;
    134}
    135
    136static const struct hid_device_id ch_devices[] = {
    137	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
    138	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
    139	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS3) },
    140	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
    141	{ }
    142};
    143MODULE_DEVICE_TABLE(hid, ch_devices);
    144
    145static struct hid_driver ch_driver = {
    146	.name = "chicony",
    147	.id_table = ch_devices,
    148	.report_fixup = ch_switch12_report_fixup,
    149	.input_mapping = ch_input_mapping,
    150	.probe = ch_probe,
    151	.raw_event = ch_raw_event,
    152};
    153module_hid_driver(ch_driver);
    154
    155MODULE_LICENSE("GPL");