blob: b15f2fd8dab459b7ef4ea581f4192e7aae4c5c75 [file] [log] [blame]
Greg Kroah-Hartmandf23fa02007-01-13 10:57:42 -08001/*
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
30static 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
39static struct usb_device_id id_table [] = {
40 { USB_DEVICE(RIM_VENDOR, BLACKBERRY) },
41 { }, /* Terminating entry */
42};
43MODULE_DEVICE_TABLE(usb, id_table);
44
45static 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
Ken L Johnson774f78c2007-03-16 10:17:31 -060072 dbg(&udev->dev, "Sending second magic command\n");
Greg Kroah-Hartmandf23fa02007-01-13 10:57:42 -080073 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
89static 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
113static void berry_disconnect(struct usb_interface *intf)
114{
115}
116
117static struct usb_driver berry_driver = {
118 .name = "berry_charge",
119 .probe = berry_probe,
120 .disconnect = berry_disconnect,
121 .id_table = id_table,
122};
123
124static int __init berry_init(void)
125{
126 return usb_register(&berry_driver);
127}
128
129static void __exit berry_exit(void)
130{
131 usb_deregister(&berry_driver);
132}
133
134module_init(berry_init);
135module_exit(berry_exit);
136
137MODULE_LICENSE("GPL");
138MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
139module_param(debug, bool, S_IRUGO | S_IWUSR);
140MODULE_PARM_DESC(debug, "Debug enabled or not");