berry_charge.c 5.0 KB

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