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
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
72	dbg(&udev->dev, "Sending second magic command\n");
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
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");
141