我下载的是barry-0.11的源代码,其main函数位于/barry-0.11/tools/bcharge.cc中,主函数基本逻辑如下:
int main(int argc, char *argv[])
{
struct usb_bus *busses;
...
usb_init();
...
busses = usb_get_busses();
...
for( bus = busses; bus; bus = bus->next ) {
...
for (dev = bus->devices; dev; dev = dev->next) {
// Is this a blackberry?
if( dev->descriptor.idVendor == VENDOR_RIM ) {
switch(dev->descriptor.idProduct)
{
case PRODUCT_RIM_BLACKBERRY:
if( !process(dev, false) )
resume();
break;
case PRODUCT_RIM_PEARL_DUAL:
case PRODUCT_RIM_PEARL:
if( !process(dev, true) )
resume();
break;
}
}
}
}
}
很显然我们关注的东西都在process函数里面:
bool process(struct usb_device *dev, bool is_pearl)
{
...
// open
usb_dev_handle *handle = usb_open(dev);
 
// adjust power
if( dev->config &&
dev->descriptor.bNumConfigurations >= 1 &&
dev->config[0].MaxPower < 250 )
{
charge(handle);
apply = true;
}
 
...
// apply changes
if( apply ) {
if( usb_set_configuration(handle, BLACKBERRY_CONFIGURATION) < 0 )
driver_conflict(handle);
...
}
// cleanup
usb_close(handle);
...
}
 int main(int argc, char *argv[])
{
struct usb_bus *busses;
...
usb_init();
...
busses = usb_get_busses();
...
for( bus = busses; bus; bus = bus->next ) {
...
for (dev = bus->devices; dev; dev = dev->next) {
// Is this a blackberry?
if( dev->descriptor.idVendor == VENDOR_RIM ) {
switch(dev->descriptor.idProduct)
{
case PRODUCT_RIM_BLACKBERRY:
if( !process(dev, false) )
resume();
break;
case PRODUCT_RIM_PEARL_DUAL:
case PRODUCT_RIM_PEARL:
if( !process(dev, true) )
resume();
break;
}
}
}
}
}
很显然我们关注的东西都在process函数里面:
bool process(struct usb_device *dev, bool is_pearl)
{
...
// open
usb_dev_handle *handle = usb_open(dev);
// adjust power
if( dev->config &&
dev->descriptor.bNumConfigurations >= 1 &&
dev->config[0].MaxPower < 250 )
{
charge(handle);
apply = true;
}
...
// apply changes
if( apply ) {
if( usb_set_configuration(handle, BLACKBERRY_CONFIGURATION) < 0 )
driver_conflict(handle);
...
}
// cleanup
usb_close(handle);
...
}
Sending two magic commands and then set the configuration. The device will then reset itself with the new power usage and should start charging.
charge函数看起来是向USB那头的Blackberry设备发去了一些特殊指令,这是导致充电的关键指令。
void charge(struct usb_dev_handle *handle)
{
// the special sauce... these steps seem to do the trick
// for the 7750 series... needs testing on others
char buffer[2];
control(handle, 0xc0, 0xa5, 0, 1, buffer, 2, 100);
control(handle, 0x40, 0xa2, 0, 1, buffer, 0, 100);
}
control是 usb_control_msg的简单封装(在这个case中看起来没有必要),其函数原型如下:
usb_control_msg
Name
usb_control_msg -- Send a control message to a device
Description
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
usb_control_msg performs a control request to the default control pipe on a device. The parameters mirror the types of the same name in the USB specification. Returns number of bytes written/read or < 0 on error.
 
 void charge(struct usb_dev_handle *handle)
{
// the special sauce... these steps seem to do the trick
// for the 7750 series... needs testing on others
char buffer[2];
control(handle, 0xc0, 0xa5, 0, 1, buffer, 2, 100);
control(handle, 0x40, 0xa2, 0, 1, buffer, 0, 100);
}
control是 usb_control_msg的简单封装(在这个case中看起来没有必要),其函数原型如下:
usb_control_msg
Name
usb_control_msg -- Send a control message to a device
Description
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
usb_control_msg performs a control request to the default control pipe on a device. The parameters mirror the types of the same name in the USB specification. Returns number of bytes written/read or < 0 on error.
该函数的参数和USB  Specification是一一对应的:
 USB  Spec                BCharge               Meaning
 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 bmRequestType       requesttype           determine  the direction of the request, type of request and designated  recipient.
 bRequest                  request                  determine the request being made
 wValue                    bytes                    ...
 wIndex                      index                    The  wValue and wIndex fields allow parameters to be passed with the  request
 wLength                    size                       wLength is used the specify the number of bytes to be transferred should there  be a data phase
                                timeout                  time to wait for the message to complete before timing out (if 0 the wait is  forever)
 按照USB 2.0 Specification(Chapter 9 USB Device Framework,->9.3 USB Device Requests),bmRequestType的各个bit意义如下:
D7 Data Phase  Transfer Direction
0 = Host to Device
1 = Device to Host
D6..5 Type
0 = Standard
1 = Class
2 = Vendor
3 = Reserved
D4..0 Recipient
0 = Device
1 = Interface
2 = Endpoint
3 = Other
4..31 = Reserved
 0 = Host to Device
1 = Device to Host
D6..5 Type
0 = Standard
1 = Class
2 = Vendor
3 = Reserved
D4..0 Recipient
0 = Device
1 = Interface
2 = Endpoint
3 = Other
4..31 = Reserved
0xc0就是1100,0000 - Device to  host,也就是读,Type是Vendor,Recipient是Device
 0x40就是0100,0000 - Host to  device,也就是写,Type是Vendor,Recipient是Device
 bRequest(0xa5,0xa2)看起来是Blackberry特有的命令了,我花了半天时间也没查到关于这两个命令的、有用的线索。悬念依旧......
 ==================================================================
 Reference:
 uberry:  The uberry driver first appeared in  OpenBSD 4.1. It provides the most minimal support for the  USB-connected Research In Motion Blackberry devices, permitting them to be  charged and powered from a USB port.
  
 
