root/drivers/hid/hid-mf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mf_play
  2. mf_init
  3. mf_probe

   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 
  30 struct mf_device {
  31         struct hid_report *report;
  32 };
  33 
  34 static 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 
  57 static 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 
 116 static 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 
 147 static 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         { }
 157 };
 158 MODULE_DEVICE_TABLE(hid, mf_devices);
 159 
 160 static struct hid_driver mf_driver = {
 161         .name = "hid_mf",
 162         .id_table = mf_devices,
 163         .probe = mf_probe,
 164 };
 165 module_hid_driver(mf_driver);
 166 
 167 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */