USB: ps3 controller hid quirk
authorGeoff Levand <geoffrey.levand@am.sony.com>
Tue, 16 Jan 2007 04:11:52 +0000 (20:11 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 7 Feb 2007 23:44:36 +0000 (15:44 -0800)
Add the USB HID quirk HID_QUIRK_SONY_PS3_CONTROLLER.  This sends an
HID_REQ_GET_REPORT to the the PS3 controller to put the device into
'operational mode'.

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/input/hid-core.c
include/linux/hid.h

index e07a304907260c19df9688d32351a19b4df8cb8f..84983d1b71644a09ef3b7e7b5954f0e7b05968ae 100644 (file)
@@ -768,6 +768,9 @@ void usbhid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_PANTHERLORD      0x0810
 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK    0x0001
 
+#define USB_VENDOR_ID_SONY                     0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER      0x0268
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -949,6 +952,8 @@ static const struct hid_blacklist {
 
        { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 
+       { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
        { 0, 0 }
 };
 
@@ -1013,6 +1018,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
        }
 }
 
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+       int result;
+       char *buf = kmalloc(18, GFP_KERNEL);
+
+       if (!buf)
+               return;
+
+       result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                                HID_REQ_GET_REPORT,
+                                USB_DIR_IN | USB_TYPE_CLASS |
+                                USB_RECIP_INTERFACE,
+                                (3 << 8) | 0xf2, ifnum, buf, 17,
+                                USB_CTRL_GET_TIMEOUT);
+
+       if (result < 0)
+               err("%s failed: %d\n", __func__, result);
+
+       kfree(buf);
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
        struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1303,6 +1334,10 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
        if ((hid->claimed & HID_CLAIMED_INPUT))
                hid_ff_init(hid);
 
+       if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+               hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+                       intf->cur_altsetting->desc.bInterfaceNumber);
+
        printk(KERN_INFO);
 
        if (hid->claimed & HID_CLAIMED_INPUT)
index 93173fe4563461e4b7f0df57451eb89c56e60004..d26b08f461f2eeb2986f0ad1a7c30f62c61fdb5e 100644 (file)
@@ -266,6 +266,7 @@ struct hid_item {
 #define HID_QUIRK_BAD_RELATIVE_KEYS            0x00010000
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00020000
 #define HID_QUIRK_IGNORE_MOUSE                 0x00040000
+#define HID_QUIRK_SONY_PS3_CONTROLLER          0x00080000
 
 /*
  * This is the global environment of the parser. This information is