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> 22bd28ce00SJiri Slaby #include <linux/usb.h> 23bd28ce00SJiri Slaby 24bd28ce00SJiri Slaby #include "hid-ids.h" 25bd28ce00SJiri Slaby 26cc6e0bbbSJiri Kosina #define VAIO_RDESC_CONSTANT 0x0001 27cc6e0bbbSJiri Kosina 28cc6e0bbbSJiri Kosina struct sony_sc { 29cc6e0bbbSJiri Kosina unsigned long quirks; 30cc6e0bbbSJiri Kosina }; 31cc6e0bbbSJiri Kosina 32cc6e0bbbSJiri Kosina /* Sony Vaio VGX has wrongly mouse pointer declared as constant */ 33cc6e0bbbSJiri Kosina static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, 34cc6e0bbbSJiri Kosina unsigned int rsize) 35cc6e0bbbSJiri Kosina { 36cc6e0bbbSJiri Kosina struct sony_sc *sc = hid_get_drvdata(hdev); 37cc6e0bbbSJiri Kosina 38cc6e0bbbSJiri Kosina if ((sc->quirks & VAIO_RDESC_CONSTANT) && 39cc6e0bbbSJiri Kosina rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { 40cc6e0bbbSJiri Kosina dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report " 41cc6e0bbbSJiri Kosina "descriptor\n"); 42cc6e0bbbSJiri Kosina rdesc[55] = 0x06; 43cc6e0bbbSJiri Kosina } 44cc6e0bbbSJiri Kosina } 45cc6e0bbbSJiri Kosina 46bd28ce00SJiri Slaby /* 47bd28ce00SJiri Slaby * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller 48bd28ce00SJiri Slaby * to "operational". Without this, the ps3 controller will not report any 49bd28ce00SJiri Slaby * events. 50bd28ce00SJiri Slaby */ 51bd28ce00SJiri Slaby static int sony_set_operational(struct hid_device *hdev) 52bd28ce00SJiri Slaby { 53bd28ce00SJiri Slaby struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 54bd28ce00SJiri Slaby struct usb_device *dev = interface_to_usbdev(intf); 55bd28ce00SJiri Slaby __u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber; 56bd28ce00SJiri Slaby int ret; 57bd28ce00SJiri Slaby char *buf = kmalloc(18, GFP_KERNEL); 58bd28ce00SJiri Slaby 59bd28ce00SJiri Slaby if (!buf) 60bd28ce00SJiri Slaby return -ENOMEM; 61bd28ce00SJiri Slaby 62bd28ce00SJiri Slaby ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 63bd28ce00SJiri Slaby HID_REQ_GET_REPORT, 64bd28ce00SJiri Slaby USB_DIR_IN | USB_TYPE_CLASS | 65bd28ce00SJiri Slaby USB_RECIP_INTERFACE, 66bd28ce00SJiri Slaby (3 << 8) | 0xf2, ifnum, buf, 17, 67bd28ce00SJiri Slaby USB_CTRL_GET_TIMEOUT); 68bd28ce00SJiri Slaby if (ret < 0) 69bd28ce00SJiri Slaby dev_err(&hdev->dev, "can't set operational mode\n"); 70bd28ce00SJiri Slaby 71bd28ce00SJiri Slaby kfree(buf); 72bd28ce00SJiri Slaby 73bd28ce00SJiri Slaby return ret; 74bd28ce00SJiri Slaby } 75bd28ce00SJiri Slaby 76bd28ce00SJiri Slaby static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) 77bd28ce00SJiri Slaby { 78bd28ce00SJiri Slaby int ret; 79cc6e0bbbSJiri Kosina unsigned long quirks = id->driver_data; 80cc6e0bbbSJiri Kosina struct sony_sc *sc; 81cc6e0bbbSJiri Kosina 82cc6e0bbbSJiri Kosina sc = kzalloc(sizeof(*sc), GFP_KERNEL); 83cc6e0bbbSJiri Kosina if (sc == NULL) { 84cc6e0bbbSJiri Kosina dev_err(&hdev->dev, "can't alloc apple descriptor\n"); 85cc6e0bbbSJiri Kosina return -ENOMEM; 86cc6e0bbbSJiri Kosina } 87cc6e0bbbSJiri Kosina 88cc6e0bbbSJiri Kosina sc->quirks = quirks; 89cc6e0bbbSJiri Kosina hid_set_drvdata(hdev, sc); 90bd28ce00SJiri Slaby 91bd28ce00SJiri Slaby ret = hid_parse(hdev); 92bd28ce00SJiri Slaby if (ret) { 93bd28ce00SJiri Slaby dev_err(&hdev->dev, "parse failed\n"); 94bd28ce00SJiri Slaby goto err_free; 95bd28ce00SJiri Slaby } 96bd28ce00SJiri Slaby 9793c10132SJiri Slaby ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | 9893c10132SJiri Slaby HID_CONNECT_HIDDEV_FORCE); 99bd28ce00SJiri Slaby if (ret) { 100bd28ce00SJiri Slaby dev_err(&hdev->dev, "hw start failed\n"); 101bd28ce00SJiri Slaby goto err_free; 102bd28ce00SJiri Slaby } 103bd28ce00SJiri Slaby 104bd28ce00SJiri Slaby ret = sony_set_operational(hdev); 1054dfdc464SJiri Kosina if (ret < 0) 106bd28ce00SJiri Slaby goto err_stop; 107bd28ce00SJiri Slaby 108bd28ce00SJiri Slaby return 0; 109bd28ce00SJiri Slaby err_stop: 110bd28ce00SJiri Slaby hid_hw_stop(hdev); 111bd28ce00SJiri Slaby err_free: 112cc6e0bbbSJiri Kosina kfree(sc); 113bd28ce00SJiri Slaby return ret; 114bd28ce00SJiri Slaby } 115bd28ce00SJiri Slaby 116cc6e0bbbSJiri Kosina static void sony_remove(struct hid_device *hdev) 117cc6e0bbbSJiri Kosina { 118cc6e0bbbSJiri Kosina hid_hw_stop(hdev); 119cc6e0bbbSJiri Kosina kfree(hid_get_drvdata(hdev)); 120cc6e0bbbSJiri Kosina } 121cc6e0bbbSJiri Kosina 122bd28ce00SJiri Slaby static const struct hid_device_id sony_devices[] = { 123bd28ce00SJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, 124cc6e0bbbSJiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), 125cc6e0bbbSJiri Kosina .driver_data = VAIO_RDESC_CONSTANT }, 126bd28ce00SJiri Slaby { } 127bd28ce00SJiri Slaby }; 128bd28ce00SJiri Slaby MODULE_DEVICE_TABLE(hid, sony_devices); 129bd28ce00SJiri Slaby 130bd28ce00SJiri Slaby static struct hid_driver sony_driver = { 131bd28ce00SJiri Slaby .name = "sony", 132bd28ce00SJiri Slaby .id_table = sony_devices, 133bd28ce00SJiri Slaby .probe = sony_probe, 134cc6e0bbbSJiri Kosina .remove = sony_remove, 135cc6e0bbbSJiri Kosina .report_fixup = sony_report_fixup, 136bd28ce00SJiri Slaby }; 137bd28ce00SJiri Slaby 138*a24f423bSPeter Huewe static int __init sony_init(void) 139bd28ce00SJiri Slaby { 140bd28ce00SJiri Slaby return hid_register_driver(&sony_driver); 141bd28ce00SJiri Slaby } 142bd28ce00SJiri Slaby 143*a24f423bSPeter Huewe static void __exit sony_exit(void) 144bd28ce00SJiri Slaby { 145bd28ce00SJiri Slaby hid_unregister_driver(&sony_driver); 146bd28ce00SJiri Slaby } 147bd28ce00SJiri Slaby 148bd28ce00SJiri Slaby module_init(sony_init); 149bd28ce00SJiri Slaby module_exit(sony_exit); 150bd28ce00SJiri Slaby MODULE_LICENSE("GPL"); 151