Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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