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