3 /// Talk to the Blackberry just enough to change the Max Power
4 /// to 500mA. Cycles through all devices attached to USB,
5 /// attempting to set all matching Blackberry devices to charge.
7 /// This file is part of the Barry project:
9 /// http://www.netdirect.ca/software/packages/barry
10 /// http://sourceforge.net/projects/barry
12 /// Compile with the following command (needs libusb):
14 /// g++ -o bcharge bcharge.cc -lusb
18 Copyright (C) 2006-2010, Net Direct Inc. (http://www.netdirect.ca/)
20 This program is free software; you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation; either version 2 of the License, or
23 (at your option) any later version.
25 This program is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
29 See the GNU General Public License in the COPYING file at the
30 root directory of this project for more details.
38 #include <sys/types.h>
42 #include <barry/common.h>
45 bool old_style_pearl
= false;
46 bool force_dual
= false;
47 std::string udev_devpath
;
48 std::string sysfs_path
= "/sys";
53 "bcharge - Adjust Blackberry charging modes\n"
54 " Copyright 2006-2010, Net Direct Inc. (http://www.netdirect.ca/)\n"
56 " -d Dual mode (mode 0004) (default)\n"
57 " -o Set a Pearl to old Blackberry mode (0001)\n"
59 " -h This help message\n"
60 " -p devpath The devpath argument from udev. If specified, will attempt\n"
61 " to adjust USB suspend settings to keep the device charging.\n"
62 " -s path The path where sysfs is mounted. Defaults to '/sys'\n"
67 void control(usb_dev_handle
*dev
, int requesttype
, int request
, int value
,
68 int index
, char *bytes
, int size
, int timeout
)
70 int result
= usb_control_msg(dev
, requesttype
, request
, value
, index
,
71 bytes
, size
, timeout
);
73 printf("\nusb_control_msg failed: code: %d, %s\n", result
,
78 void charge(struct usb_dev_handle
*handle
)
80 // the special sauce... these steps seem to do the trick
81 // for the 7750 series... needs testing on others
83 control(handle
, 0xc0, 0xa5, 0, 1, buffer
, 2, 100);
84 control(handle
, 0x40, 0xa2, 0, 1, buffer
, 0, 100);
87 void pearl_mode(struct usb_dev_handle
*handle
)
90 if( old_style_pearl
) {
91 // use this for "old style" interface: product ID 0001
92 control(handle
, 0xc0, 0xa9, 0, 1, buffer
, 2, 100);
96 control(handle
, 0xc0, 0xa9, 1, 1, buffer
, 2, 100);
100 int find_mass_storage_interface(struct usb_dev_handle
*handle
)
102 // search the configuration descriptor for a Mass Storage
103 // interface (class 8)
104 struct usb_device
*dev
= usb_device(handle
);
105 struct usb_config_descriptor
*cfg
= dev
? dev
->config
: 0;
109 for( unsigned i
= 0; cfg
->interface
&& i
< cfg
->bNumInterfaces
; i
++ ) {
110 struct usb_interface
*iface
= &cfg
->interface
[i
];
111 for( int a
= 0; iface
->altsetting
&& a
< iface
->num_altsetting
; a
++ ) {
112 struct usb_interface_descriptor
*id
= &iface
->altsetting
[a
];
113 if( id
->bInterfaceClass
== USB_CLASS_MASS_STORAGE
)
114 return id
->bInterfaceNumber
;
119 // if we get here, then we didn't find the Mass Storage interface
120 // ... this should never happen, but if it does, assume
121 // the device is s showing product ID 0006, and the Mass Storage
122 // interface is interface #0
123 printf("Can't find Mass Storage interface, assuming 0.\n");
127 void driver_conflict(struct usb_dev_handle
*handle
)
129 // this is called if the first usb_set_configuration()
130 // failed... this most probably means that usb_storage
131 // has already claimed the Mass Storage interface,
132 // in which case we politely tell it to away.
134 #if LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
135 printf("Detecting possible kernel driver conflict, trying to resolve...\n");
137 int iface
= find_mass_storage_interface(handle
);
138 if( usb_detach_kernel_driver_np(handle
, iface
) < 0 )
139 printf("usb_detach_kernel_driver_np() failed: %s\n", usb_strerror());
141 if( usb_set_configuration(handle
, BLACKBERRY_CONFIGURATION
) < 0 )
142 printf("usb_set_configuration() failed: %s\n", usb_strerror());
146 // returns true if device mode was modified, false otherwise
147 bool process(struct usb_device
*dev
, bool is_pearl
)
150 printf("Found device #%s...", dev
->filename
);
153 usb_dev_handle
*handle
= usb_open(dev
);
155 printf("unable to open device\n");
161 dev
->descriptor
.bNumConfigurations
>= 1 &&
162 dev
->config
[0].MaxPower
< 250 ) {
163 printf("adjusting charge setting");
168 printf("already at 500mA");
172 if( is_pearl
|| force_dual
) {
173 int desired_mode
= old_style_pearl
174 ? PRODUCT_RIM_BLACKBERRY
: PRODUCT_RIM_PEARL_DUAL
;
176 if( desired_mode
!= dev
->descriptor
.idProduct
) {
177 printf("...adjusting Pearl mode to %s",
178 old_style_pearl
? "single" : "dual");
183 printf("...already in desired Pearl mode");
187 printf("...no Pearl adjustment");
192 if( usb_set_configuration(handle
, BLACKBERRY_CONFIGURATION
) < 0 )
193 driver_conflict(handle
);
195 // the Blackberry Pearl doesn't reset itself after the above,
196 // so do it ourselves
197 if( is_pearl
|| force_dual
) {
199 // It has been observed that the 8830 behaves both like
200 // a Pearl device (in that it has mass storage +
201 // database modes) as well as a Classic device in
202 // that it resets itself and doesn't need an explicit
205 // In order to deal with this, we insert a brief sleep.
206 // If it is an 8830, it will reset itself and the
207 // following reset call will fail. If it is a Pearl,
208 // the reset will work as normal.
211 if( usb_reset(handle
) < 0 ) {
212 printf("\nusb_reset failed: %s\n", usb_strerror());
219 printf("...no change\n");
227 bool power_write(const std::string
&file
, const std::string
&value
)
229 // attempt to open the state file
230 int fd
= open(file
.c_str(), O_RDWR
);
232 printf("autosuspend adjustment failure: (file: %s): %s\n",
238 int written
= write(fd
, value
.data(), value
.size());
242 if( written
< 0 || (size_t)written
!= value
.size() ) {
243 printf("autosuspend adjustment failure (write): (file: %s): %s\n",
249 printf("autosuspend adjustment: wrote %s to %s\n",
250 value
.c_str(), file
.c_str());
255 // Checks for USB suspend, and enables the device if suspended.
257 // Kernel 2.6.21 behaves with autosuspend=0 meaning off, while 2.6.22
258 // and higher needs autosuspend=-1 to turn it off. In 2.6.22, a value
259 // of 0 means "immediate" instead of "never".
261 // Version 2.6.22 adds variables internal to the system called
262 // autosuspend_disabled and autoresume_disabled. These are controlled by the
263 // /sys/class/usb_device/*/device/power/level file. (See below)
265 // Here's a summary of files under device/power. These may or may not exist
266 // depending on your kernel version and configuration.
270 // -1 or 0 means off, depending on kernel,
271 // otherwise it is the number of seconds to
275 // with the settings:
277 // on - suspend is disabled, device is fully powered
278 // auto - suspend is controlled by the kernel (default)
279 // suspend - suspend is enabled permanently
281 // You can write these strings to the file to control
282 // behaviour on a per-device basis.
284 // echo on > /sys/usb_device/.../device/power/level
287 // current state of device
291 // You can write these numbers to control behaviour, but
292 // any change you make here might change automatically
293 // if autosuspend is on.
295 // echo -n 0 > /sys/usb_device/.../device/power/state
301 // Given the above facts, use the following heuristics to try to disable
302 // autosuspend for the Blackberry:
304 // - if level exists, write "on" to it
305 // - if autosuspend exists, write -1 to it
306 // - if error, write 0 to it
307 // - if neither of the above work, and state exists, write 0 to it
311 if( udev_devpath
.size() == 0 )
312 return; // nothing to do
314 // let sysfs settle a bit
317 std::string power_path
= sysfs_path
+ "/" + udev_devpath
+ "/device/power/";
319 if( !power_write(power_path
+ "level", "on\n") )
320 if( !power_write(power_path
+ "autosuspend", "-1\n") )
321 if( !power_write(power_path
+ "autosuspend", "0\n") )
322 power_write(power_path
+ "state", "0");
325 int main(int argc
, char *argv
[])
327 struct usb_bus
*busses
;
332 // allow -o command line switch to choose which mode to use for
333 // Blackberry Pearls:
334 // Dual(default): 0004 -d
335 // With switch: 0001 -o
338 // process command line options
340 int cmd
= getopt(argc
, argv
, "dop:s:h");
346 case 'd': // Dual (default)
348 old_style_pearl
= false;
351 case 'o': // Old style pearl
353 old_style_pearl
= true;
356 case 'p': // udev devpath
357 udev_devpath
= optarg
;
360 case 's': // where sysfs is mounted
372 if( usb_find_busses() < 0 || usb_find_devices() < 0 ) {
373 printf("\nUnable to scan devices: %s\n", usb_strerror());
376 busses
= usb_get_busses();
378 printf("Scanning for Blackberry devices...\n");
381 for( bus
= busses
; bus
; bus
= bus
->next
) {
382 struct usb_device
*dev
;
384 for (dev
= bus
->devices
; dev
; dev
= dev
->next
) {
385 // Is this a blackberry?
386 if( dev
->descriptor
.idVendor
== VENDOR_RIM
) {
387 switch(dev
->descriptor
.idProduct
)
389 case PRODUCT_RIM_BLACKBERRY
:
390 if( !process(dev
, false) )
394 case PRODUCT_RIM_PEARL_DUAL
:
395 case PRODUCT_RIM_PEARL
:
396 case PRODUCT_RIM_PEARL_8120
:
397 case PRODUCT_RIM_PEARL_FLIP
:
398 case PRODUCT_RIM_STORM
:
399 if( !process(dev
, true) )