1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Force feedback support for Zeroplus based devices 4 * 5 * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com> 6 */ 7 8 /* 9 */ 10 11 12 #include <linux/hid.h> 13 #include <linux/input.h> 14 #include <linux/slab.h> 15 #include <linux/module.h> 16 17 #include "hid-ids.h" 18 19 #ifdef CONFIG_ZEROPLUS_FF 20 21 struct zpff_device { 22 struct hid_report *report; 23 }; 24 25 static int zpff_play(struct input_dev *dev, void *data, 26 struct ff_effect *effect) 27 { 28 struct hid_device *hid = input_get_drvdata(dev); 29 struct zpff_device *zpff = data; 30 int left, right; 31 32 /* 33 * The following is specified the other way around in the Zeroplus 34 * datasheet but the order below is correct for the XFX Executioner; 35 * however it is possible that the XFX Executioner is an exception 36 */ 37 38 left = effect->u.rumble.strong_magnitude; 39 right = effect->u.rumble.weak_magnitude; 40 dbg_hid("called with 0x%04x 0x%04x\n", left, right); 41 42 left = left * 0x7f / 0xffff; 43 right = right * 0x7f / 0xffff; 44 45 zpff->report->field[2]->value[0] = left; 46 zpff->report->field[3]->value[0] = right; 47 dbg_hid("running with 0x%02x 0x%02x\n", left, right); 48 hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT); 49 50 return 0; 51 } 52 53 static int zpff_init(struct hid_device *hid) 54 { 55 struct zpff_device *zpff; 56 struct hid_report *report; 57 struct hid_input *hidinput = list_entry(hid->inputs.next, 58 struct hid_input, list); 59 struct input_dev *dev = hidinput->input; 60 int i, error; 61 62 for (i = 0; i < 4; i++) { 63 report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1); 64 if (!report) 65 return -ENODEV; 66 } 67 68 zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); 69 if (!zpff) 70 return -ENOMEM; 71 72 set_bit(FF_RUMBLE, dev->ffbit); 73 74 error = input_ff_create_memless(dev, zpff, zpff_play); 75 if (error) { 76 kfree(zpff); 77 return error; 78 } 79 80 zpff->report = report; 81 zpff->report->field[0]->value[0] = 0x00; 82 zpff->report->field[1]->value[0] = 0x02; 83 zpff->report->field[2]->value[0] = 0x00; 84 zpff->report->field[3]->value[0] = 0x00; 85 hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT); 86 87 hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); 88 89 return 0; 90 } 91 #else 92 static inline int zpff_init(struct hid_device *hid) 93 { 94 return 0; 95 } 96 #endif 97 98 static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id) 99 { 100 int ret; 101 102 ret = hid_parse(hdev); 103 if (ret) { 104 hid_err(hdev, "parse failed\n"); 105 goto err; 106 } 107 108 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); 109 if (ret) { 110 hid_err(hdev, "hw start failed\n"); 111 goto err; 112 } 113 114 zpff_init(hdev); 115 116 return 0; 117 err: 118 return ret; 119 } 120 121 static const struct hid_device_id zp_devices[] = { 122 { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, 123 { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, 124 { } 125 }; 126 MODULE_DEVICE_TABLE(hid, zp_devices); 127 128 static struct hid_driver zp_driver = { 129 .name = "zeroplus", 130 .id_table = zp_devices, 131 .probe = zp_probe, 132 }; 133 module_hid_driver(zp_driver); 134 135 MODULE_LICENSE("GPL"); 136