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 " 12d36b6910SAl Viro * - tested with König Gaming gamepad 135f022298SJiri Slaby * 1427a9c179SAnssi Hannula * 0e8f:0003 "GASIA USB Gamepad" 15d36b6910SAl Viro * - another version of the König gamepad 1627a9c179SAnssi Hannula * 17aaca9cc0SMichael Karcher * 0f30:0111 "Saitek Color Rumble Pad" 18aaca9cc0SMichael Karcher * 1927a9c179SAnssi Hannula * Copyright (c) 2007, 2009 Anssi Hannula <anssi.hannula@gmail.com> 205f022298SJiri Slaby */ 215f022298SJiri Slaby 225f022298SJiri Slaby /* 235f022298SJiri Slaby * This program is free software; you can redistribute it and/or modify 245f022298SJiri Slaby * it under the terms of the GNU General Public License as published by 255f022298SJiri Slaby * the Free Software Foundation; either version 2 of the License, or 265f022298SJiri Slaby * (at your option) any later version. 275f022298SJiri Slaby * 285f022298SJiri Slaby * This program is distributed in the hope that it will be useful, 295f022298SJiri Slaby * but WITHOUT ANY WARRANTY; without even the implied warranty of 305f022298SJiri Slaby * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 315f022298SJiri Slaby * GNU General Public License for more details. 325f022298SJiri Slaby * 335f022298SJiri Slaby * You should have received a copy of the GNU General Public License 345f022298SJiri Slaby * along with this program; if not, write to the Free Software 355f022298SJiri Slaby * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 365f022298SJiri Slaby */ 375f022298SJiri Slaby 385f022298SJiri Slaby 395f022298SJiri Slaby /* #define DEBUG */ 405f022298SJiri Slaby 415f022298SJiri Slaby #define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg) 425f022298SJiri Slaby 435f022298SJiri Slaby #include <linux/input.h> 445a0e3ad6STejun Heo #include <linux/slab.h> 458f86a2c3SPaul Gortmaker #include <linux/module.h> 465f022298SJiri Slaby #include <linux/hid.h> 475f022298SJiri Slaby 485f022298SJiri Slaby #include "hid-ids.h" 495f022298SJiri Slaby 505f022298SJiri Slaby #ifdef CONFIG_PANTHERLORD_FF 515f022298SJiri Slaby 525f022298SJiri Slaby struct plff_device { 535f022298SJiri Slaby struct hid_report *report; 54aaca9cc0SMichael Karcher s32 maxval; 5527a9c179SAnssi Hannula s32 *strong; 5627a9c179SAnssi Hannula s32 *weak; 575f022298SJiri Slaby }; 585f022298SJiri Slaby 595f022298SJiri Slaby static int hid_plff_play(struct input_dev *dev, void *data, 605f022298SJiri Slaby struct ff_effect *effect) 615f022298SJiri Slaby { 625f022298SJiri Slaby struct hid_device *hid = input_get_drvdata(dev); 635f022298SJiri Slaby struct plff_device *plff = data; 645f022298SJiri Slaby int left, right; 655f022298SJiri Slaby 665f022298SJiri Slaby left = effect->u.rumble.strong_magnitude; 675f022298SJiri Slaby right = effect->u.rumble.weak_magnitude; 685f022298SJiri Slaby debug("called with 0x%04x 0x%04x", left, right); 695f022298SJiri Slaby 70aaca9cc0SMichael Karcher left = left * plff->maxval / 0xffff; 71aaca9cc0SMichael Karcher right = right * plff->maxval / 0xffff; 725f022298SJiri Slaby 7327a9c179SAnssi Hannula *plff->strong = left; 7427a9c179SAnssi Hannula *plff->weak = right; 755f022298SJiri Slaby debug("running with 0x%02x 0x%02x", left, right); 76d8814272SBenjamin Tissoires hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT); 775f022298SJiri Slaby 785f022298SJiri Slaby return 0; 795f022298SJiri Slaby } 805f022298SJiri Slaby 815f022298SJiri Slaby static int plff_init(struct hid_device *hid) 825f022298SJiri Slaby { 835f022298SJiri Slaby struct plff_device *plff; 845f022298SJiri Slaby struct hid_report *report; 855f022298SJiri Slaby struct hid_input *hidinput; 865f022298SJiri Slaby struct list_head *report_list = 875f022298SJiri Slaby &hid->report_enum[HID_OUTPUT_REPORT].report_list; 885f022298SJiri Slaby struct list_head *report_ptr = report_list; 895f022298SJiri Slaby struct input_dev *dev; 905f022298SJiri Slaby int error; 91aaca9cc0SMichael Karcher s32 maxval; 9227a9c179SAnssi Hannula s32 *strong; 9327a9c179SAnssi Hannula s32 *weak; 945f022298SJiri Slaby 955f022298SJiri Slaby /* The device contains one output report per physical device, all 965f022298SJiri Slaby containing 1 field, which contains 4 ff00.0002 usages and 4 16bit 975f022298SJiri Slaby absolute values. 985f022298SJiri Slaby 995f022298SJiri Slaby The input reports also contain a field which contains 1005f022298SJiri Slaby 8 ff00.0001 usages and 8 boolean values. Their meaning is 10127a9c179SAnssi Hannula currently unknown. 10227a9c179SAnssi Hannula 10327a9c179SAnssi Hannula A version of the 0e8f:0003 exists that has all the values in 10427a9c179SAnssi Hannula separate fields and misses the extra input field, thus resembling 10527a9c179SAnssi Hannula Zeroplus (hid-zpff) devices. 10627a9c179SAnssi Hannula */ 1075f022298SJiri Slaby 1085f022298SJiri Slaby if (list_empty(report_list)) { 1094291ee30SJoe Perches hid_err(hid, "no output reports found\n"); 1105f022298SJiri Slaby return -ENODEV; 1115f022298SJiri Slaby } 1125f022298SJiri Slaby 1135f022298SJiri Slaby list_for_each_entry(hidinput, &hid->inputs, list) { 1145f022298SJiri Slaby 1155f022298SJiri Slaby report_ptr = report_ptr->next; 1165f022298SJiri Slaby 1175f022298SJiri Slaby if (report_ptr == report_list) { 1184291ee30SJoe Perches hid_err(hid, "required output report is missing\n"); 1195f022298SJiri Slaby return -ENODEV; 1205f022298SJiri Slaby } 1215f022298SJiri Slaby 1225f022298SJiri Slaby report = list_entry(report_ptr, struct hid_report, list); 1235f022298SJiri Slaby if (report->maxfield < 1) { 1244291ee30SJoe Perches hid_err(hid, "no fields in the report\n"); 1255f022298SJiri Slaby return -ENODEV; 1265f022298SJiri Slaby } 1275f022298SJiri Slaby 128aaca9cc0SMichael Karcher maxval = 0x7f; 12927a9c179SAnssi Hannula if (report->field[0]->report_count >= 4) { 13027a9c179SAnssi Hannula report->field[0]->value[0] = 0x00; 13127a9c179SAnssi Hannula report->field[0]->value[1] = 0x00; 13227a9c179SAnssi Hannula strong = &report->field[0]->value[2]; 13327a9c179SAnssi Hannula weak = &report->field[0]->value[3]; 13427a9c179SAnssi Hannula debug("detected single-field device"); 13527a9c179SAnssi Hannula } else if (report->maxfield >= 4 && report->field[0]->maxusage == 1 && 13627a9c179SAnssi Hannula report->field[0]->usage[0].hid == (HID_UP_LED | 0x43)) { 13727a9c179SAnssi Hannula report->field[0]->value[0] = 0x00; 13827a9c179SAnssi Hannula report->field[1]->value[0] = 0x00; 13927a9c179SAnssi Hannula strong = &report->field[2]->value[0]; 14027a9c179SAnssi Hannula weak = &report->field[3]->value[0]; 141aaca9cc0SMichael Karcher if (hid->vendor == USB_VENDOR_ID_JESS2) 142aaca9cc0SMichael Karcher maxval = 0xff; 14327a9c179SAnssi Hannula debug("detected 4-field device"); 14427a9c179SAnssi Hannula } else { 1454291ee30SJoe Perches hid_err(hid, "not enough fields or values\n"); 1465f022298SJiri Slaby return -ENODEV; 1475f022298SJiri Slaby } 1485f022298SJiri Slaby 1495f022298SJiri Slaby plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL); 1505f022298SJiri Slaby if (!plff) 1515f022298SJiri Slaby return -ENOMEM; 1525f022298SJiri Slaby 1535f022298SJiri Slaby dev = hidinput->input; 1545f022298SJiri Slaby 1555f022298SJiri Slaby set_bit(FF_RUMBLE, dev->ffbit); 1565f022298SJiri Slaby 1575f022298SJiri Slaby error = input_ff_create_memless(dev, plff, hid_plff_play); 1585f022298SJiri Slaby if (error) { 1595f022298SJiri Slaby kfree(plff); 1605f022298SJiri Slaby return error; 1615f022298SJiri Slaby } 1625f022298SJiri Slaby 1635f022298SJiri Slaby plff->report = report; 16427a9c179SAnssi Hannula plff->strong = strong; 16527a9c179SAnssi Hannula plff->weak = weak; 166aaca9cc0SMichael Karcher plff->maxval = maxval; 16727a9c179SAnssi Hannula 16827a9c179SAnssi Hannula *strong = 0x00; 16927a9c179SAnssi Hannula *weak = 0x00; 170d8814272SBenjamin Tissoires hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT); 1715f022298SJiri Slaby } 1725f022298SJiri Slaby 1734291ee30SJoe Perches hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); 1745f022298SJiri Slaby 1755f022298SJiri Slaby return 0; 1765f022298SJiri Slaby } 1775f022298SJiri Slaby #else 1785f022298SJiri Slaby static inline int plff_init(struct hid_device *hid) 1795f022298SJiri Slaby { 1805f022298SJiri Slaby return 0; 1815f022298SJiri Slaby } 1825f022298SJiri Slaby #endif 1835f022298SJiri Slaby 1845f022298SJiri Slaby static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id) 1855f022298SJiri Slaby { 1865f022298SJiri Slaby int ret; 1875f022298SJiri Slaby 1885f022298SJiri Slaby if (id->driver_data) 1895f022298SJiri Slaby hdev->quirks |= HID_QUIRK_MULTI_INPUT; 1905f022298SJiri Slaby 1915f022298SJiri Slaby ret = hid_parse(hdev); 1925f022298SJiri Slaby if (ret) { 1934291ee30SJoe Perches hid_err(hdev, "parse failed\n"); 1945f022298SJiri Slaby goto err; 1955f022298SJiri Slaby } 1965f022298SJiri Slaby 1975f022298SJiri Slaby ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); 1985f022298SJiri Slaby if (ret) { 1994291ee30SJoe Perches hid_err(hdev, "hw start failed\n"); 2005f022298SJiri Slaby goto err; 2015f022298SJiri Slaby } 2025f022298SJiri Slaby 2035f022298SJiri Slaby plff_init(hdev); 2045f022298SJiri Slaby 2055f022298SJiri Slaby return 0; 2065f022298SJiri Slaby err: 2075f022298SJiri Slaby return ret; 2085f022298SJiri Slaby } 2095f022298SJiri Slaby 2105f022298SJiri Slaby static const struct hid_device_id pl_devices[] = { 2115f022298SJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR), 2125f022298SJiri Slaby .driver_data = 1 }, /* Twin USB Joystick */ 213578f3a35SJiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR), 214578f3a35SJiri Kosina .driver_data = 1 }, /* Twin USB Joystick */ 21527a9c179SAnssi Hannula { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), }, 216aaca9cc0SMichael Karcher { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD), }, 2175f022298SJiri Slaby { } 2185f022298SJiri Slaby }; 2195f022298SJiri Slaby MODULE_DEVICE_TABLE(hid, pl_devices); 2205f022298SJiri Slaby 2215f022298SJiri Slaby static struct hid_driver pl_driver = { 2225f022298SJiri Slaby .name = "pantherlord", 2235f022298SJiri Slaby .id_table = pl_devices, 2245f022298SJiri Slaby .probe = pl_probe, 2255f022298SJiri Slaby }; 226f425458eSH Hartley Sweeten module_hid_driver(pl_driver); 2275f022298SJiri Slaby 2285f022298SJiri Slaby MODULE_LICENSE("GPL"); 229