Commit | Line | Data |
---|---|---|
df23fa01 GKH |
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 | ||
30 | static int debug; | |
31 | ||
32 | #ifdef dbg | |
33 | #undef dbg | |
34 | #endif | |
35 | #define dbg(dev, format, arg...) \ | |
36 | if (debug) \ | |
37 | dev_printk(KERN_DEBUG , dev , format , ## arg) | |
38 | ||
39 | static struct usb_device_id id_table [] = { | |
40 | { USB_DEVICE(RIM_VENDOR, BLACKBERRY) }, | |
41 | { }, /* Terminating entry */ | |
42 | }; | |
43 | MODULE_DEVICE_TABLE(usb, id_table); | |
44 | ||
45 | static int magic_charge(struct usb_device *udev) | |
46 | { | |
47 | char *dummy_buffer = kzalloc(2, GFP_KERNEL); | |
48 | int retval; | |
49 | ||
50 | if (!dummy_buffer) | |
51 | return -ENOMEM; | |
52 | ||
53 | /* send two magic commands and then set the configuration. The device | |
54 | * will then reset itself with the new power usage and should start | |
55 | * charging. */ | |
56 | ||
57 | /* Note, with testing, it only seems that the first message is really | |
58 | * needed (at least for the 8700c), but to be safe, we emulate what | |
59 | * other operating systems seem to be sending to their device. We | |
60 | * really need to get some specs for this device to be sure about what | |
61 | * is going on here. | |
62 | */ | |
63 | dbg(&udev->dev, "Sending first magic command\n"); | |
64 | retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | |
65 | 0xa5, 0xc0, 0, 1, dummy_buffer, 2, 100); | |
66 | if (retval != 2) { | |
67 | dev_err(&udev->dev, "First magic command failed: %d.\n", | |
68 | retval); | |
69 | return retval; | |
70 | } | |
71 | ||
774f78cf | 72 | dbg(&udev->dev, "Sending second magic command\n"); |
df23fa01 GKH |
73 | retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), |
74 | 0xa2, 0x40, 0, 1, dummy_buffer, 0, 100); | |
75 | if (retval != 0) { | |
76 | dev_err(&udev->dev, "Second magic command failed: %d.\n", | |
77 | retval); | |
78 | return retval; | |
79 | } | |
80 | ||
81 | dbg(&udev->dev, "Calling set_configuration\n"); | |
82 | retval = usb_driver_set_configuration(udev, 1); | |
83 | if (retval) | |
84 | dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); | |
85 | ||
86 | return retval; | |
87 | } | |
88 | ||
89 | static int berry_probe(struct usb_interface *intf, | |
90 | const struct usb_device_id *id) | |
91 | { | |
92 | struct usb_device *udev = interface_to_usbdev(intf); | |
93 | ||
94 | dbg(&udev->dev, "Power is set to %dmA\n", | |
95 | udev->actconfig->desc.bMaxPower * 2); | |
96 | ||
97 | /* check the power usage so we don't try to enable something that is | |
98 | * already enabled */ | |
99 | if ((udev->actconfig->desc.bMaxPower * 2) == 500) { | |
100 | dbg(&udev->dev, "device is already charging, power is " | |
101 | "set to %dmA\n", udev->actconfig->desc.bMaxPower * 2); | |
102 | return -ENODEV; | |
103 | } | |
104 | ||
105 | /* turn the power on */ | |
106 | magic_charge(udev); | |
107 | ||
108 | /* we don't really want to bind to the device, userspace programs can | |
109 | * handle the syncing just fine, so get outta here. */ | |
110 | return -ENODEV; | |
111 | } | |
112 | ||
113 | static void berry_disconnect(struct usb_interface *intf) | |
114 | { | |
115 | } | |
116 | ||
117 | static struct usb_driver berry_driver = { | |
118 | .name = "berry_charge", | |
119 | .probe = berry_probe, | |
120 | .disconnect = berry_disconnect, | |
121 | .id_table = id_table, | |
122 | }; | |
123 | ||
124 | static int __init berry_init(void) | |
125 | { | |
126 | return usb_register(&berry_driver); | |
127 | } | |
128 | ||
129 | static void __exit berry_exit(void) | |
130 | { | |
131 | usb_deregister(&berry_driver); | |
132 | } | |
133 | ||
134 | module_init(berry_init); | |
135 | module_exit(berry_exit); | |
136 | ||
137 | MODULE_LICENSE("GPL"); | |
138 | MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>"); | |
139 | module_param(debug, bool, S_IRUGO | S_IWUSR); | |
140 | MODULE_PARM_DESC(debug, "Debug enabled or not"); |