diff options
Diffstat (limited to 'drivers/hid/hid-sony.c')
-rw-r--r-- | drivers/hid/hid-sony.c | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 402d5574b57..677bb3da10e 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -24,24 +24,46 @@ #include "hid-ids.h" -#define VAIO_RDESC_CONSTANT 0x0001 +#define VAIO_RDESC_CONSTANT (1 << 0) +#define SIXAXIS_CONTROLLER_USB (1 << 1) +#define SIXAXIS_CONTROLLER_BT (1 << 2) struct sony_sc { unsigned long quirks; }; /* Sony Vaio VGX has wrongly mouse pointer declared as constant */ -static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int rsize) +static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) { struct sony_sc *sc = hid_get_drvdata(hdev); if ((sc->quirks & VAIO_RDESC_CONSTANT) && - rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { + *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report " "descriptor\n"); rdesc[55] = 0x06; } + return rdesc; +} + +static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf, + size_t count, unsigned char report_type) +{ + struct usb_interface *intf = to_usb_interface(hid->dev.parent); + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *interface = intf->cur_altsetting; + int report_id = buf[0]; + int ret; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + HID_REQ_SET_REPORT, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + ((report_type + 1) << 8) | report_id, + interface->desc.bInterfaceNumber, buf, count, + USB_CTRL_SET_TIMEOUT); + + return ret; } /* @@ -49,7 +71,7 @@ static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, * to "operational". Without this, the ps3 controller will not report any * events. */ -static int sony_set_operational_usb(struct hid_device *hdev) +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); @@ -74,7 +96,7 @@ static int sony_set_operational_usb(struct hid_device *hdev) return ret; } -static int sony_set_operational_bt(struct hid_device *hdev) +static int sixaxis_set_operational_bt(struct hid_device *hdev) { unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); @@ -108,16 +130,14 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - switch (hdev->bus) { - case BUS_USB: - ret = sony_set_operational_usb(hdev); - break; - case BUS_BLUETOOTH: - ret = sony_set_operational_bt(hdev); - break; - default: - ret = 0; + if (sc->quirks & SIXAXIS_CONTROLLER_USB) { + hdev->hid_output_raw_report = sixaxis_usb_output_raw_report; + ret = sixaxis_set_operational_usb(hdev); } + else if (sc->quirks & SIXAXIS_CONTROLLER_BT) + ret = sixaxis_set_operational_bt(hdev); + else + ret = 0; if (ret < 0) goto err_stop; @@ -137,8 +157,10 @@ static void sony_remove(struct hid_device *hdev) } static const struct hid_device_id sony_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), + .driver_data = SIXAXIS_CONTROLLER_USB }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), + .driver_data = SIXAXIS_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), .driver_data = VAIO_RDESC_CONSTANT }, { } |