1bd28ce00SJiri Slaby /* 2bd28ce00SJiri Slaby * HID driver for some sony "special" devices 3bd28ce00SJiri Slaby * 4bd28ce00SJiri Slaby * Copyright (c) 1999 Andreas Gal 5bd28ce00SJiri Slaby * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 6bd28ce00SJiri Slaby * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 7bd28ce00SJiri Slaby * Copyright (c) 2007 Paul Walmsley 8bd28ce00SJiri Slaby * Copyright (c) 2008 Jiri Slaby 9cc6e0bbbSJiri Kosina * Copyright (c) 2006-2008 Jiri Kosina 10bd28ce00SJiri Slaby */ 11bd28ce00SJiri Slaby 12bd28ce00SJiri Slaby /* 13bd28ce00SJiri Slaby * This program is free software; you can redistribute it and/or modify it 14bd28ce00SJiri Slaby * under the terms of the GNU General Public License as published by the Free 15bd28ce00SJiri Slaby * Software Foundation; either version 2 of the License, or (at your option) 16bd28ce00SJiri Slaby * any later version. 17bd28ce00SJiri Slaby */ 18bd28ce00SJiri Slaby 19bd28ce00SJiri Slaby #include <linux/device.h> 20bd28ce00SJiri Slaby #include <linux/hid.h> 21bd28ce00SJiri Slaby #include <linux/module.h> 225a0e3ad6STejun Heo #include <linux/slab.h> 23bd28ce00SJiri Slaby #include <linux/usb.h> 24bd28ce00SJiri Slaby 25bd28ce00SJiri Slaby #include "hid-ids.h" 26bd28ce00SJiri Slaby 27cc6e0bbbSJiri Kosina #define VAIO_RDESC_CONSTANT 0x0001 28cc6e0bbbSJiri Kosina 29cc6e0bbbSJiri Kosina struct sony_sc { 30cc6e0bbbSJiri Kosina unsigned long quirks; 31cc6e0bbbSJiri Kosina }; 32cc6e0bbbSJiri Kosina 33cc6e0bbbSJiri Kosina /* Sony Vaio VGX has wrongly mouse pointer declared as constant */ 34cc6e0bbbSJiri Kosina static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, 35cc6e0bbbSJiri Kosina unsigned int rsize) 36cc6e0bbbSJiri Kosina { 37cc6e0bbbSJiri Kosina struct sony_sc *sc = hid_get_drvdata(hdev); 38cc6e0bbbSJiri Kosina 39cc6e0bbbSJiri Kosina if ((sc->quirks & VAIO_RDESC_CONSTANT) && 40cc6e0bbbSJiri Kosina rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { 41cc6e0bbbSJiri Kosina dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report " 42cc6e0bbbSJiri Kosina "descriptor\n"); 43cc6e0bbbSJiri Kosina rdesc[55] = 0x06; 44cc6e0bbbSJiri Kosina } 45cc6e0bbbSJiri Kosina } 46cc6e0bbbSJiri Kosina 47bd28ce00SJiri Slaby /* 48bd28ce00SJiri Slaby * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller 49bd28ce00SJiri Slaby * to "operational". Without this, the ps3 controller will not report any 50bd28ce00SJiri Slaby * events. 51bd28ce00SJiri Slaby */ 52f9ce7c28SBastien Nocera static int sony_set_operational_usb(struct hid_device *hdev) 53bd28ce00SJiri Slaby { 54bd28ce00SJiri Slaby struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 55bd28ce00SJiri Slaby struct usb_device *dev = interface_to_usbdev(intf); 56bd28ce00SJiri Slaby __u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber; 57bd28ce00SJiri Slaby int ret; 58bd28ce00SJiri Slaby char *buf = kmalloc(18, GFP_KERNEL); 59bd28ce00SJiri Slaby 60bd28ce00SJiri Slaby if (!buf) 61bd28ce00SJiri Slaby return -ENOMEM; 62bd28ce00SJiri Slaby 63bd28ce00SJiri Slaby ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 64bd28ce00SJiri Slaby HID_REQ_GET_REPORT, 65bd28ce00SJiri Slaby USB_DIR_IN | USB_TYPE_CLASS | 66bd28ce00SJiri Slaby USB_RECIP_INTERFACE, 67bd28ce00SJiri Slaby (3 << 8) | 0xf2, ifnum, buf, 17, 68bd28ce00SJiri Slaby USB_CTRL_GET_TIMEOUT); 69bd28ce00SJiri Slaby if (ret < 0) 70bd28ce00SJiri Slaby dev_err(&hdev->dev, "can't set operational mode\n"); 71bd28ce00SJiri Slaby 72bd28ce00SJiri Slaby kfree(buf); 73bd28ce00SJiri Slaby 74bd28ce00SJiri Slaby return ret; 75bd28ce00SJiri Slaby } 76bd28ce00SJiri Slaby 77f9ce7c28SBastien Nocera static int sony_set_operational_bt(struct hid_device *hdev) 78f9ce7c28SBastien Nocera { 79*fddb33f2SAntonio Ospite unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; 80f9ce7c28SBastien Nocera return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); 81f9ce7c28SBastien Nocera } 82f9ce7c28SBastien Nocera 83bd28ce00SJiri Slaby static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) 84bd28ce00SJiri Slaby { 85bd28ce00SJiri Slaby int ret; 86cc6e0bbbSJiri Kosina unsigned long quirks = id->driver_data; 87cc6e0bbbSJiri Kosina struct sony_sc *sc; 88cc6e0bbbSJiri Kosina 89cc6e0bbbSJiri Kosina sc = kzalloc(sizeof(*sc), GFP_KERNEL); 90cc6e0bbbSJiri Kosina if (sc == NULL) { 91eabe5c90SBastien Nocera dev_err(&hdev->dev, "can't alloc sony descriptor\n"); 92cc6e0bbbSJiri Kosina return -ENOMEM; 93cc6e0bbbSJiri Kosina } 94cc6e0bbbSJiri Kosina 95cc6e0bbbSJiri Kosina sc->quirks = quirks; 96cc6e0bbbSJiri Kosina hid_set_drvdata(hdev, sc); 97bd28ce00SJiri Slaby 98bd28ce00SJiri Slaby ret = hid_parse(hdev); 99bd28ce00SJiri Slaby if (ret) { 100bd28ce00SJiri Slaby dev_err(&hdev->dev, "parse failed\n"); 101bd28ce00SJiri Slaby goto err_free; 102bd28ce00SJiri Slaby } 103bd28ce00SJiri Slaby 10493c10132SJiri Slaby ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | 10593c10132SJiri Slaby HID_CONNECT_HIDDEV_FORCE); 106bd28ce00SJiri Slaby if (ret) { 107bd28ce00SJiri Slaby dev_err(&hdev->dev, "hw start failed\n"); 108bd28ce00SJiri Slaby goto err_free; 109bd28ce00SJiri Slaby } 110bd28ce00SJiri Slaby 111f9ce7c28SBastien Nocera switch (hdev->bus) { 112f9ce7c28SBastien Nocera case BUS_USB: 113f9ce7c28SBastien Nocera ret = sony_set_operational_usb(hdev); 114f9ce7c28SBastien Nocera break; 115f9ce7c28SBastien Nocera case BUS_BLUETOOTH: 116f9ce7c28SBastien Nocera ret = sony_set_operational_bt(hdev); 117f9ce7c28SBastien Nocera break; 118f9ce7c28SBastien Nocera default: 119f9ce7c28SBastien Nocera ret = 0; 120f9ce7c28SBastien Nocera } 121f9ce7c28SBastien Nocera 1224dfdc464SJiri Kosina if (ret < 0) 123bd28ce00SJiri Slaby goto err_stop; 124bd28ce00SJiri Slaby 125bd28ce00SJiri Slaby return 0; 126bd28ce00SJiri Slaby err_stop: 127bd28ce00SJiri Slaby hid_hw_stop(hdev); 128bd28ce00SJiri Slaby err_free: 129cc6e0bbbSJiri Kosina kfree(sc); 130bd28ce00SJiri Slaby return ret; 131bd28ce00SJiri Slaby } 132bd28ce00SJiri Slaby 133cc6e0bbbSJiri Kosina static void sony_remove(struct hid_device *hdev) 134cc6e0bbbSJiri Kosina { 135cc6e0bbbSJiri Kosina hid_hw_stop(hdev); 136cc6e0bbbSJiri Kosina kfree(hid_get_drvdata(hdev)); 137cc6e0bbbSJiri Kosina } 138cc6e0bbbSJiri Kosina 139bd28ce00SJiri Slaby static const struct hid_device_id sony_devices[] = { 140bd28ce00SJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, 141f9ce7c28SBastien Nocera { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, 142cc6e0bbbSJiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), 143cc6e0bbbSJiri Kosina .driver_data = VAIO_RDESC_CONSTANT }, 144bd28ce00SJiri Slaby { } 145bd28ce00SJiri Slaby }; 146bd28ce00SJiri Slaby MODULE_DEVICE_TABLE(hid, sony_devices); 147bd28ce00SJiri Slaby 148bd28ce00SJiri Slaby static struct hid_driver sony_driver = { 149bd28ce00SJiri Slaby .name = "sony", 150bd28ce00SJiri Slaby .id_table = sony_devices, 151bd28ce00SJiri Slaby .probe = sony_probe, 152cc6e0bbbSJiri Kosina .remove = sony_remove, 153cc6e0bbbSJiri Kosina .report_fixup = sony_report_fixup, 154bd28ce00SJiri Slaby }; 155bd28ce00SJiri Slaby 156a24f423bSPeter Huewe static int __init sony_init(void) 157bd28ce00SJiri Slaby { 158bd28ce00SJiri Slaby return hid_register_driver(&sony_driver); 159bd28ce00SJiri Slaby } 160bd28ce00SJiri Slaby 161a24f423bSPeter Huewe static void __exit sony_exit(void) 162bd28ce00SJiri Slaby { 163bd28ce00SJiri Slaby hid_unregister_driver(&sony_driver); 164bd28ce00SJiri Slaby } 165bd28ce00SJiri Slaby 166bd28ce00SJiri Slaby module_init(sony_init); 167bd28ce00SJiri Slaby module_exit(sony_exit); 168bd28ce00SJiri Slaby MODULE_LICENSE("GPL"); 169