Hi this is my first kernel patch.
I have a ps3 controller clone that dmesg calls "Gasia Co.,Ltd PS(R)
Gamepad." When I plugged it in it was recognized but did not send any
output. After some searching I found
http://www.spinics.net/lists/linux-input/msg18172.html and changed my
kernel according to the patch on that email which didn't fix the
problem. I installed wireshark and connected the controller to
Windows(VirtualBox) and came up with the solution in the attached patch.
My controller needed the additional
hdev->hid_get_raw_report(hdev, 0xf5, buf, 64, HID_FEATURE_REPORT)
and an interrupt set.
I tried to use the newer hdev->hid_output_raw_report rather than calling
usb_interrupt_msg but I think usbhid->urbout is null in
usbhid_output_raw_report since it gets sent as a SET_REPORT instead of
URB_INTERRUPT out.
I did a little testing and running testrumble just after the controller
is attached does initialize the controller so that the buttons send
output. (Only with the additional hid_get_raw_report(hdev, 0xf5...)
I'm completely new to the kernel and have no idea how to allocate
urbout. I did some searching but I'm not sure where to look.
Regards,
Andrew Haines
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 098af2f8..c2bab2b 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -426,16 +426,46 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
*/
static int sixaxis_set_operational_usb(struct hid_device *hdev)
{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *dev = interface_to_usbdev(intf);
+ //struct usbhid_device *usbhid = hdev->driver_data;
int ret;
- char *buf = kmalloc(18, GFP_KERNEL);
+ int transfered;
+ char *buf = kmalloc(65, GFP_KERNEL);
+ unsigned char buf2[] = {
+ 0x01,
+ 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1e, // led flags 1e = all
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+ };
if (!buf)
return -ENOMEM;
ret = hdev->hid_get_raw_report(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT);
-
+
if (ret < 0)
hid_err(hdev, "can't set operational mode\n");
+ else {
+ /* Some compatible controllers like the Speedlink Strike FX and
+ * Gasia need a write to the Interrupt EP to get operational */
+ hdev->hid_get_raw_report(hdev, 0xf5, buf, 64, HID_FEATURE_REPORT);
+
+ // doesn't work. gets sent as a SET_REPORT Request intstead of a
+ // URB_INTERRUPT out. I guess usbhid->urbout is null
+ //if ( hdev->hid_output_raw_report(hdev, buf2, sizeof(buf2),
+ // HID_OUTPUT_REPORT) < 0 )
+ // hid_err(hdev, "can't set initial interrupt. Cloned controllers may not operate\n");
+
+ if ( usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x02),
+ buf2, sizeof(buf2),
+ &transfered, USB_CTRL_SET_TIMEOUT))
+ hid_err(hdev, "can't set initial interrupt. Cloned controllers may not operate\n");
+ }
kfree(buf);