15f022298SJiri Slaby /* 25f022298SJiri Slaby * Force feedback support for PantherLord/GreenAsia based devices 35f022298SJiri Slaby * 45f022298SJiri Slaby * The devices are distributed under various names and the same USB device ID 55f022298SJiri Slaby * can be used in both adapters and actual game controllers. 65f022298SJiri Slaby * 75f022298SJiri Slaby * 0810:0001 "Twin USB Joystick" 85f022298SJiri Slaby * - tested with PantherLord USB/PS2 2in1 Adapter 95f022298SJiri Slaby * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT) 105f022298SJiri Slaby * 115f022298SJiri Slaby * 0e8f:0003 "GreenAsia Inc. USB Joystick " 12*27a9c179SAnssi Hannula * - tested with K�nig Gaming gamepad 135f022298SJiri Slaby * 14*27a9c179SAnssi Hannula * 0e8f:0003 "GASIA USB Gamepad" 15*27a9c179SAnssi Hannula * - another version of the K�nig gamepad 16*27a9c179SAnssi Hannula * 17*27a9c179SAnssi Hannula * Copyright (c) 2007, 2009 Anssi Hannula <anssi.hannula@gmail.com> 185f022298SJiri Slaby */ 195f022298SJiri Slaby 205f022298SJiri Slaby /* 215f022298SJiri Slaby * This program is free software; you can redistribute it and/or modify 225f022298SJiri Slaby * it under the terms of the GNU General Public License as published by 235f022298SJiri Slaby * the Free Software Foundation; either version 2 of the License, or 245f022298SJiri Slaby * (at your option) any later version. 255f022298SJiri Slaby * 265f022298SJiri Slaby * This program is distributed in the hope that it will be useful, 275f022298SJiri Slaby * but WITHOUT ANY WARRANTY; without even the implied warranty of 285f022298SJiri Slaby * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 295f022298SJiri Slaby * GNU General Public License for more details. 305f022298SJiri Slaby * 315f022298SJiri Slaby * You should have received a copy of the GNU General Public License 325f022298SJiri Slaby * along with this program; if not, write to the Free Software 335f022298SJiri Slaby * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 345f022298SJiri Slaby */ 355f022298SJiri Slaby 365f022298SJiri Slaby 375f022298SJiri Slaby /* #define DEBUG */ 385f022298SJiri Slaby 395f022298SJiri Slaby #define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg) 405f022298SJiri Slaby 415f022298SJiri Slaby #include <linux/input.h> 425f022298SJiri Slaby #include <linux/usb.h> 435f022298SJiri Slaby #include <linux/hid.h> 445f022298SJiri Slaby 455f022298SJiri Slaby #include "hid-ids.h" 465f022298SJiri Slaby 475f022298SJiri Slaby #ifdef CONFIG_PANTHERLORD_FF 485f022298SJiri Slaby #include "usbhid/usbhid.h" 495f022298SJiri Slaby 505f022298SJiri Slaby struct plff_device { 515f022298SJiri Slaby struct hid_report *report; 52*27a9c179SAnssi Hannula s32 *strong; 53*27a9c179SAnssi Hannula s32 *weak; 545f022298SJiri Slaby }; 555f022298SJiri Slaby 565f022298SJiri Slaby static int hid_plff_play(struct input_dev *dev, void *data, 575f022298SJiri Slaby struct ff_effect *effect) 585f022298SJiri Slaby { 595f022298SJiri Slaby struct hid_device *hid = input_get_drvdata(dev); 605f022298SJiri Slaby struct plff_device *plff = data; 615f022298SJiri Slaby int left, right; 625f022298SJiri Slaby 635f022298SJiri Slaby left = effect->u.rumble.strong_magnitude; 645f022298SJiri Slaby right = effect->u.rumble.weak_magnitude; 655f022298SJiri Slaby debug("called with 0x%04x 0x%04x", left, right); 665f022298SJiri Slaby 675f022298SJiri Slaby left = left * 0x7f / 0xffff; 685f022298SJiri Slaby right = right * 0x7f / 0xffff; 695f022298SJiri Slaby 70*27a9c179SAnssi Hannula *plff->strong = left; 71*27a9c179SAnssi Hannula *plff->weak = right; 725f022298SJiri Slaby debug("running with 0x%02x 0x%02x", left, right); 735f022298SJiri Slaby usbhid_submit_report(hid, plff->report, USB_DIR_OUT); 745f022298SJiri Slaby 755f022298SJiri Slaby return 0; 765f022298SJiri Slaby } 775f022298SJiri Slaby 785f022298SJiri Slaby static int plff_init(struct hid_device *hid) 795f022298SJiri Slaby { 805f022298SJiri Slaby struct plff_device *plff; 815f022298SJiri Slaby struct hid_report *report; 825f022298SJiri Slaby struct hid_input *hidinput; 835f022298SJiri Slaby struct list_head *report_list = 845f022298SJiri Slaby &hid->report_enum[HID_OUTPUT_REPORT].report_list; 855f022298SJiri Slaby struct list_head *report_ptr = report_list; 865f022298SJiri Slaby struct input_dev *dev; 875f022298SJiri Slaby int error; 88*27a9c179SAnssi Hannula s32 *strong; 89*27a9c179SAnssi Hannula s32 *weak; 905f022298SJiri Slaby 915f022298SJiri Slaby /* The device contains one output report per physical device, all 925f022298SJiri Slaby containing 1 field, which contains 4 ff00.0002 usages and 4 16bit 935f022298SJiri Slaby absolute values. 945f022298SJiri Slaby 955f022298SJiri Slaby The input reports also contain a field which contains 965f022298SJiri Slaby 8 ff00.0001 usages and 8 boolean values. Their meaning is 97*27a9c179SAnssi Hannula currently unknown. 98*27a9c179SAnssi Hannula 99*27a9c179SAnssi Hannula A version of the 0e8f:0003 exists that has all the values in 100*27a9c179SAnssi Hannula separate fields and misses the extra input field, thus resembling 101*27a9c179SAnssi Hannula Zeroplus (hid-zpff) devices. 102*27a9c179SAnssi Hannula */ 1035f022298SJiri Slaby 1045f022298SJiri Slaby if (list_empty(report_list)) { 10579575019SJiri Slaby dev_err(&hid->dev, "no output reports found\n"); 1065f022298SJiri Slaby return -ENODEV; 1075f022298SJiri Slaby } 1085f022298SJiri Slaby 1095f022298SJiri Slaby list_for_each_entry(hidinput, &hid->inputs, list) { 1105f022298SJiri Slaby 1115f022298SJiri Slaby report_ptr = report_ptr->next; 1125f022298SJiri Slaby 1135f022298SJiri Slaby if (report_ptr == report_list) { 11479575019SJiri Slaby dev_err(&hid->dev, "required output report is " 11579575019SJiri Slaby "missing\n"); 1165f022298SJiri Slaby return -ENODEV; 1175f022298SJiri Slaby } 1185f022298SJiri Slaby 1195f022298SJiri Slaby report = list_entry(report_ptr, struct hid_report, list); 1205f022298SJiri Slaby if (report->maxfield < 1) { 12179575019SJiri Slaby dev_err(&hid->dev, "no fields in the report\n"); 1225f022298SJiri Slaby return -ENODEV; 1235f022298SJiri Slaby } 1245f022298SJiri Slaby 125*27a9c179SAnssi Hannula if (report->field[0]->report_count >= 4) { 126*27a9c179SAnssi Hannula report->field[0]->value[0] = 0x00; 127*27a9c179SAnssi Hannula report->field[0]->value[1] = 0x00; 128*27a9c179SAnssi Hannula strong = &report->field[0]->value[2]; 129*27a9c179SAnssi Hannula weak = &report->field[0]->value[3]; 130*27a9c179SAnssi Hannula debug("detected single-field device"); 131*27a9c179SAnssi Hannula } else if (report->maxfield >= 4 && report->field[0]->maxusage == 1 && 132*27a9c179SAnssi Hannula report->field[0]->usage[0].hid == (HID_UP_LED | 0x43)) { 133*27a9c179SAnssi Hannula report->field[0]->value[0] = 0x00; 134*27a9c179SAnssi Hannula report->field[1]->value[0] = 0x00; 135*27a9c179SAnssi Hannula strong = &report->field[2]->value[0]; 136*27a9c179SAnssi Hannula weak = &report->field[3]->value[0]; 137*27a9c179SAnssi Hannula debug("detected 4-field device"); 138*27a9c179SAnssi Hannula } else { 139*27a9c179SAnssi Hannula dev_err(&hid->dev, "not enough fields or values\n"); 1405f022298SJiri Slaby return -ENODEV; 1415f022298SJiri Slaby } 1425f022298SJiri Slaby 1435f022298SJiri Slaby plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL); 1445f022298SJiri Slaby if (!plff) 1455f022298SJiri Slaby return -ENOMEM; 1465f022298SJiri Slaby 1475f022298SJiri Slaby dev = hidinput->input; 1485f022298SJiri Slaby 1495f022298SJiri Slaby set_bit(FF_RUMBLE, dev->ffbit); 1505f022298SJiri Slaby 1515f022298SJiri Slaby error = input_ff_create_memless(dev, plff, hid_plff_play); 1525f022298SJiri Slaby if (error) { 1535f022298SJiri Slaby kfree(plff); 1545f022298SJiri Slaby return error; 1555f022298SJiri Slaby } 1565f022298SJiri Slaby 1575f022298SJiri Slaby plff->report = report; 158*27a9c179SAnssi Hannula plff->strong = strong; 159*27a9c179SAnssi Hannula plff->weak = weak; 160*27a9c179SAnssi Hannula 161*27a9c179SAnssi Hannula *strong = 0x00; 162*27a9c179SAnssi Hannula *weak = 0x00; 1635f022298SJiri Slaby usbhid_submit_report(hid, plff->report, USB_DIR_OUT); 1645f022298SJiri Slaby } 1655f022298SJiri Slaby 16679575019SJiri Slaby dev_info(&hid->dev, "Force feedback for PantherLord/GreenAsia " 1675f022298SJiri Slaby "devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); 1685f022298SJiri Slaby 1695f022298SJiri Slaby return 0; 1705f022298SJiri Slaby } 1715f022298SJiri Slaby #else 1725f022298SJiri Slaby static inline int plff_init(struct hid_device *hid) 1735f022298SJiri Slaby { 1745f022298SJiri Slaby return 0; 1755f022298SJiri Slaby } 1765f022298SJiri Slaby #endif 1775f022298SJiri Slaby 1785f022298SJiri Slaby static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id) 1795f022298SJiri Slaby { 1805f022298SJiri Slaby int ret; 1815f022298SJiri Slaby 1825f022298SJiri Slaby if (id->driver_data) 1835f022298SJiri Slaby hdev->quirks |= HID_QUIRK_MULTI_INPUT; 1845f022298SJiri Slaby 1855f022298SJiri Slaby ret = hid_parse(hdev); 1865f022298SJiri Slaby if (ret) { 1875f022298SJiri Slaby dev_err(&hdev->dev, "parse failed\n"); 1885f022298SJiri Slaby goto err; 1895f022298SJiri Slaby } 1905f022298SJiri Slaby 1915f022298SJiri Slaby ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); 1925f022298SJiri Slaby if (ret) { 1935f022298SJiri Slaby dev_err(&hdev->dev, "hw start failed\n"); 1945f022298SJiri Slaby goto err; 1955f022298SJiri Slaby } 1965f022298SJiri Slaby 1975f022298SJiri Slaby plff_init(hdev); 1985f022298SJiri Slaby 1995f022298SJiri Slaby return 0; 2005f022298SJiri Slaby err: 2015f022298SJiri Slaby return ret; 2025f022298SJiri Slaby } 2035f022298SJiri Slaby 2045f022298SJiri Slaby static const struct hid_device_id pl_devices[] = { 2055f022298SJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR), 2065f022298SJiri Slaby .driver_data = 1 }, /* Twin USB Joystick */ 207578f3a35SJiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR), 208578f3a35SJiri Kosina .driver_data = 1 }, /* Twin USB Joystick */ 209*27a9c179SAnssi Hannula { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), }, 2105f022298SJiri Slaby { } 2115f022298SJiri Slaby }; 2125f022298SJiri Slaby MODULE_DEVICE_TABLE(hid, pl_devices); 2135f022298SJiri Slaby 2145f022298SJiri Slaby static struct hid_driver pl_driver = { 2155f022298SJiri Slaby .name = "pantherlord", 2165f022298SJiri Slaby .id_table = pl_devices, 2175f022298SJiri Slaby .probe = pl_probe, 2185f022298SJiri Slaby }; 2195f022298SJiri Slaby 2205f022298SJiri Slaby static int pl_init(void) 2215f022298SJiri Slaby { 2225f022298SJiri Slaby return hid_register_driver(&pl_driver); 2235f022298SJiri Slaby } 2245f022298SJiri Slaby 2255f022298SJiri Slaby static void pl_exit(void) 2265f022298SJiri Slaby { 2275f022298SJiri Slaby hid_unregister_driver(&pl_driver); 2285f022298SJiri Slaby } 2295f022298SJiri Slaby 2305f022298SJiri Slaby module_init(pl_init); 2315f022298SJiri Slaby module_exit(pl_exit); 2325f022298SJiri Slaby MODULE_LICENSE("GPL"); 2335f022298SJiri Slaby 2345f022298SJiri Slaby HID_COMPAT_LOAD_DRIVER(pantherlord); 235