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-mf.c (4386B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Force feedback support for Mayflash game controller adapters.
      4 *
      5 * These devices are manufactured by Mayflash but identify themselves
      6 * using the vendor ID of DragonRise Inc.
      7 *
      8 * Tested with:
      9 * 0079:1801 "DragonRise Inc. Mayflash PS3 Game Controller Adapter"
     10 * 0079:1803 "DragonRise Inc. Mayflash Wireless Sensor DolphinBar"
     11 * 0079:1843 "DragonRise Inc. Mayflash GameCube Game Controller Adapter"
     12 * 0079:1844 "DragonRise Inc. Mayflash GameCube Game Controller Adapter (v04)"
     13 *
     14 * The following adapters probably work too, but need to be tested:
     15 * 0079:1800 "DragonRise Inc. Mayflash WIIU Game Controller Adapter"
     16 *
     17 * Copyright (c) 2016-2017 Marcel Hasler <mahasler@gmail.com>
     18 */
     19
     20/*
     21 */
     22
     23#include <linux/input.h>
     24#include <linux/slab.h>
     25#include <linux/hid.h>
     26#include <linux/module.h>
     27
     28#include "hid-ids.h"
     29
     30struct mf_device {
     31	struct hid_report *report;
     32};
     33
     34static int mf_play(struct input_dev *dev, void *data, struct ff_effect *effect)
     35{
     36	struct hid_device *hid = input_get_drvdata(dev);
     37	struct mf_device *mf = data;
     38	int strong, weak;
     39
     40	strong = effect->u.rumble.strong_magnitude;
     41	weak = effect->u.rumble.weak_magnitude;
     42
     43	dbg_hid("Called with 0x%04x 0x%04x.\n", strong, weak);
     44
     45	strong = strong * 0xff / 0xffff;
     46	weak = weak * 0xff / 0xffff;
     47
     48	dbg_hid("Running with 0x%02x 0x%02x.\n", strong, weak);
     49
     50	mf->report->field[0]->value[0] = weak;
     51	mf->report->field[0]->value[1] = strong;
     52	hid_hw_request(hid, mf->report, HID_REQ_SET_REPORT);
     53
     54	return 0;
     55}
     56
     57static int mf_init(struct hid_device *hid)
     58{
     59	struct mf_device *mf;
     60
     61	struct list_head *report_list =
     62			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
     63
     64	struct list_head *report_ptr;
     65	struct hid_report *report;
     66
     67	struct list_head *input_ptr = &hid->inputs;
     68	struct hid_input *input;
     69
     70	struct input_dev *dev;
     71
     72	int error;
     73
     74	/* Setup each of the four inputs */
     75	list_for_each(report_ptr, report_list) {
     76		report = list_entry(report_ptr, struct hid_report, list);
     77
     78		if (report->maxfield < 1 || report->field[0]->report_count < 2) {
     79			hid_err(hid, "Invalid report, this should never happen!\n");
     80			return -ENODEV;
     81		}
     82
     83		if (list_is_last(input_ptr, &hid->inputs)) {
     84			hid_err(hid, "Missing input, this should never happen!\n");
     85			return -ENODEV;
     86		}
     87
     88		input_ptr = input_ptr->next;
     89		input = list_entry(input_ptr, struct hid_input, list);
     90
     91		mf = kzalloc(sizeof(struct mf_device), GFP_KERNEL);
     92		if (!mf)
     93			return -ENOMEM;
     94
     95		dev = input->input;
     96		set_bit(FF_RUMBLE, dev->ffbit);
     97
     98		error = input_ff_create_memless(dev, mf, mf_play);
     99		if (error) {
    100			kfree(mf);
    101			return error;
    102		}
    103
    104		mf->report = report;
    105		mf->report->field[0]->value[0] = 0x00;
    106		mf->report->field[0]->value[1] = 0x00;
    107		hid_hw_request(hid, mf->report, HID_REQ_SET_REPORT);
    108	}
    109
    110	hid_info(hid, "Force feedback for HJZ Mayflash game controller "
    111		      "adapters by Marcel Hasler <mahasler@gmail.com>\n");
    112
    113	return 0;
    114}
    115
    116static int mf_probe(struct hid_device *hid, const struct hid_device_id *id)
    117{
    118	int error;
    119
    120	dev_dbg(&hid->dev, "Mayflash HID hardware probe...\n");
    121
    122	/* Apply quirks as needed */
    123	hid->quirks |= id->driver_data;
    124
    125	error = hid_parse(hid);
    126	if (error) {
    127		hid_err(hid, "HID parse failed.\n");
    128		return error;
    129	}
    130
    131	error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
    132	if (error) {
    133		hid_err(hid, "HID hw start failed\n");
    134		return error;
    135	}
    136
    137	error = mf_init(hid);
    138	if (error) {
    139		hid_err(hid, "Force feedback init failed.\n");
    140		hid_hw_stop(hid);
    141		return error;
    142	}
    143
    144	return 0;
    145}
    146
    147static const struct hid_device_id mf_devices[] = {
    148	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3),
    149		.driver_data = HID_QUIRK_MULTI_INPUT },
    150	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR),
    151		.driver_data = HID_QUIRK_MULTI_INPUT },
    152	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1),
    153		.driver_data = HID_QUIRK_MULTI_INPUT },
    154	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2),
    155		.driver_data = 0 }, /* No quirk required */
    156	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3),
    157		.driver_data = HID_QUIRK_MULTI_INPUT },
    158	{ }
    159};
    160MODULE_DEVICE_TABLE(hid, mf_devices);
    161
    162static struct hid_driver mf_driver = {
    163	.name = "hid_mf",
    164	.id_table = mf_devices,
    165	.probe = mf_probe,
    166};
    167module_hid_driver(mf_driver);
    168
    169MODULE_LICENSE("GPL");