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  * USB BlackBerry charging module
  3  *
  4  * Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.de>
  5  *
  6  *      This program is free software; you can redistribute it and/or
  7  *      modify it under the terms of the GNU General Public License as
  8  *      published by the Free Software Foundation, version 2.
  9  *
 10  * Information on how to switch configs was taken by the bcharge.cc file
 11  * created by the barry.sf.net project.
 12  *
 13  * bcharge.cc has the following copyright:
 14  *      Copyright (C) 2006, Net Direct Inc. (http://www.netdirect.ca/)
 15  * and is released under the GPLv2.
 16  *
 17  *
 18  */
 19 
 20 #include <linux/kernel.h>
 21 #include <linux/errno.h>
 22 #include <linux/init.h>
 23 #include <linux/slab.h>
 24 #include <linux/module.h>
 25 #include <linux/usb.h>
 26 
 27 #define RIM_VENDOR              0x0fca
 28 #define BLACKBERRY              0x0001
 29 #define BLACKBERRY_PEARL_DUAL   0x0004
 30 #define BLACKBERRY_PEARL        0x0006
 31 
 32 static int debug;
 33 static int pearl_dual_mode = 1;
 34 
 35 #ifdef dbg
 36 #undef dbg
 37 #endif
 38 #define dbg(dev, format, arg...)                                \
 39         if (debug)                                              \
 40                 dev_printk(KERN_DEBUG , dev , format , ## arg)
 41 
 42 static struct usb_device_id id_table [] = {
 43         { USB_DEVICE(RIM_VENDOR, BLACKBERRY) },
 44         { USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL) },
 45         { USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL_DUAL) },
 46         { },                                    /* Terminating entry */
 47 };
 48 MODULE_DEVICE_TABLE(usb, id_table);
 49 
 50 static int magic_charge(struct usb_device *udev)
 51 {
 52         char *dummy_buffer = kzalloc(2, GFP_KERNEL);
 53         int retval;
 54 
 55         if (!dummy_buffer)
 56                 return -ENOMEM;
 57 
 58         /* send two magic commands and then set the configuration.  The device
 59          * will then reset itself with the new power usage and should start
 60          * charging. */
 61 
 62         /* Note, with testing, it only seems that the first message is really
 63          * needed (at least for the 8700c), but to be safe, we emulate what
 64          * other operating systems seem to be sending to their device.  We
 65          * really need to get some specs for this device to be sure about what
 66          * is going on here.
 67          */
 68         dbg(&udev->dev, "Sending first magic command\n");
 69         retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 70                                  0xa5, 0xc0, 0, 1, dummy_buffer, 2, 100);
 71         if (retval != 2) {
 72                 dev_err(&udev->dev, "First magic command failed: %d.\n",
 73                         retval);
 74                 goto exit;
 75         }
 76 
 77         dbg(&udev->dev, "Sending second magic command\n");
 78         retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 79                                  0xa2, 0x40, 0, 1, dummy_buffer, 0, 100);
 80         if (retval != 0) {
 81                 dev_err(&udev->dev, "Second magic command failed: %d.\n",
 82                         retval);
 83                 goto exit;
 84         }
 85 
 86         dbg(&udev->dev, "Calling set_configuration\n");
 87         retval = usb_driver_set_configuration(udev, 1);
 88         if (retval)
 89                 dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 90 
 91 exit:
 92         kfree(dummy_buffer);
 93         return retval;
 94 }
 95 
 96 static int magic_dual_mode(struct usb_device *udev)
 97 {
 98         char *dummy_buffer = kzalloc(2, GFP_KERNEL);
 99         int retval;
100 
101         if (!dummy_buffer)
102                 return -ENOMEM;
103 
104         /* send magic command so that the Blackberry Pearl device exposes
105          * two interfaces: both the USB mass-storage one and one which can
106          * be used for database access. */
107         dbg(&udev->dev, "Sending magic pearl command\n");
108         retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
109                                  0xa9, 0xc0, 1, 1, dummy_buffer, 2, 100);
110         dbg(&udev->dev, "Magic pearl command returned %d\n", retval);
111 
112         dbg(&udev->dev, "Calling set_configuration\n");
113         retval = usb_driver_set_configuration(udev, 1);
114         if (retval)
115                 dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
116 
117         kfree(dummy_buffer);
118         return retval;
119 }
120 
121 static int berry_probe(struct usb_interface *intf,
122                        const struct usb_device_id *id)
123 {
124         struct usb_device *udev = interface_to_usbdev(intf);
125 
126         if (udev->bus_mA < 500) {
127                 dbg(&udev->dev, "Not enough power to charge available\n");
128                 return -ENODEV;
129         }
130 
131         dbg(&udev->dev, "Power is set to %dmA\n",
132             udev->actconfig->desc.bMaxPower * 2);
133 
134         /* check the power usage so we don't try to enable something that is
135          * already enabled */
136         if ((udev->actconfig->desc.bMaxPower * 2) == 500) {
137                 dbg(&udev->dev, "device is already charging, power is "
138                     "set to %dmA\n", udev->actconfig->desc.bMaxPower * 2);
139                 return -ENODEV;
140         }
141 
142         /* turn the power on */
143         magic_charge(udev);
144 
145         if ((le16_to_cpu(udev->descriptor.idProduct) == BLACKBERRY_PEARL) &&
146             (pearl_dual_mode))
147                 magic_dual_mode(udev);
148 
149         /* we don't really want to bind to the device, userspace programs can
150          * handle the syncing just fine, so get outta here. */
151         return -ENODEV;
152 }
153 
154 static void berry_disconnect(struct usb_interface *intf)
155 {
156 }
157 
158 static struct usb_driver berry_driver = {
159         .name =         "berry_charge",
160         .probe =        berry_probe,
161         .disconnect =   berry_disconnect,
162         .id_table =     id_table,
163 };
164 
165 static int __init berry_init(void)
166 {
167         return usb_register(&berry_driver);
168 }
169 
170 static void __exit berry_exit(void)
171 {
172         usb_deregister(&berry_driver);
173 }
174 
175 module_init(berry_init);
176 module_exit(berry_exit);
177 
178 MODULE_LICENSE("GPL");
179 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
180 module_param(debug, bool, S_IRUGO | S_IWUSR);
181 MODULE_PARM_DESC(debug, "Debug enabled or not");
182 module_param(pearl_dual_mode, bool, S_IRUGO | S_IWUSR);
183 MODULE_PARM_DESC(pearl_dual_mode, "Change Blackberry Pearl to run in dual mode");
184 
  This page was automatically generated by the LXR engine.