2 /// \file bcharge_libusb_1_0.cc
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 1.0):
14 /// g++ -o bcharge bcharge.cc -I/usr/include/libusb -lusb-1.0
18 Copyright (C) 2006-2011, Net Direct Inc. (http://www.netdirect.ca/)
19 Portions Copyright (C) 2011, RealVNC Ltd.
21 This program is free software; you can redistribute it and/or modify
22 it under the terms of the GNU General Public License as published by
23 the Free Software Foundation; either version 2 of the License, or
24 (at your option) any later version.
26 This program is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
30 See the GNU General Public License in the COPYING file at the
31 root directory of this project for more details.
39 #include <sys/types.h>
43 #include <barry/common.h>
48 PEARL_CLASSIC_MODE_0001
, // force classic mode
49 PEARL_DUAL_MODE_0004
, // force dual mode
50 CONDITIONAL_DUAL_MODE
, // set dual mode if no class 255
51 // interface is found (database iface)
54 std::string udev_devpath
;
55 std::string sysfs_path
= "/sys";
60 "bcharge - Adjust Blackberry charging modes\n"
61 " Copyright 2006-2011, Net Direct Inc. (http://www.netdirect.ca/)\n"
63 " -d Set to dual mode (0004)\n"
64 " -o Set a Pearl to old Blackberry mode (0001)\n"
65 " -g Set dual mode only if database interface class 255\n"
68 " -h This help message\n"
69 " -p devpath The devpath argument from udev. If specified, will attempt\n"
70 " to adjust USB suspend settings to keep the device charging.\n"
71 " -s path The path where sysfs is mounted. Defaults to '/sys'\n"
76 void control(libusb_device_handle
*dev
, int requesttype
, int request
, int value
,
77 int index
, unsigned char *bytes
, int size
, int timeout
)
79 int result
= libusb_control_transfer(dev
, requesttype
, request
, value
, index
,
80 bytes
, size
, timeout
);
82 printf("\nusb_control_transfer failed: code: %d\n", result
);
86 void charge(libusb_device_handle
*handle
)
88 // the special sauce... these steps seem to do the trick
89 // for the 7750 series... needs testing on others
90 unsigned char buffer
[2];
91 control(handle
, 0xc0, 0xa5, 0, 1, buffer
, 2, 100);
92 control(handle
, 0x40, 0xa2, 0, 1, buffer
, 0, 100);
95 void pearl_classic_mode(libusb_device_handle
*handle
)
97 unsigned char buffer
[2];
98 // use this for "old style" interface: product ID 0001
99 control(handle
, 0xc0, 0xa9, 0, 1, buffer
, 2, 100);
102 void pearl_dual_mode(libusb_device_handle
*handle
)
104 unsigned char buffer
[2];
106 control(handle
, 0xc0, 0xa9, 1, 1, buffer
, 2, 100);
109 int find_interface(libusb_device_handle
*handle
, int iface_class
)
111 // search the configuration descriptor for the given class ID
112 libusb_device
*dev
= libusb_get_device(handle
);
113 struct libusb_config_descriptor
*cfg
= NULL
;
114 int err
= libusb_get_config_descriptor(dev
, BLACKBERRY_CONFIGURATION
, &cfg
);
117 if( err
== 0 && cfg
) {
120 cfg
->interface
&& ret
== -1 &&
121 i
< cfg
->bNumInterfaces
;
123 const struct libusb_interface
*iface
= &cfg
->interface
[i
];
125 iface
->altsetting
&& ret
== -1 &&
126 a
< iface
->num_altsetting
;
128 const struct libusb_interface_descriptor
*id
= &iface
->altsetting
[a
];
129 if( id
->bInterfaceClass
== iface_class
)
130 ret
= id
->bInterfaceNumber
;
133 libusb_free_config_descriptor(cfg
);
140 int find_mass_storage_interface(libusb_device_handle
*handle
)
142 int iface
= find_interface(handle
, LIBUSB_CLASS_MASS_STORAGE
);
145 // if we get here, then we didn't find the Mass Storage
146 // interface ... this should never happen, but if it does,
147 // assume the device is showing product ID 0006, and the
148 // Mass Storage interface is interface #0
149 printf("Can't find Mass Storage interface, assuming 0.\n");
157 void driver_conflict(libusb_device_handle
*handle
)
159 // this is called if the first usb_set_configuration()
160 // failed... this most probably means that usb_storage
161 // has already claimed the Mass Storage interface,
162 // in which case we politely tell it to go away.
163 printf("Detecting possible kernel driver conflict, trying to resolve...\n");
165 int iface
= find_mass_storage_interface(handle
);
166 int err
= libusb_detach_kernel_driver(handle
, iface
);
168 printf("libusb_detach_kernel_driver() failed: %d\n", err
);
170 err
= libusb_set_configuration(handle
, BLACKBERRY_CONFIGURATION
);
172 printf("libusb_set_configuration() failed: %d\n", err
);
175 // returns true if device mode was modified, false otherwise
176 bool process(libusb_device
*dev
, ModeType mode
)
179 printf("Found device #%d-%d...",
180 libusb_get_bus_number(dev
),
181 libusb_get_device_address(dev
));
184 libusb_device_handle
*handle
;
185 int err
= libusb_open(dev
, &handle
);
187 printf("unable to open device, %d\n", err
);
191 struct libusb_config_descriptor
*config
= NULL
;
192 err
= libusb_get_active_config_descriptor(dev
, &config
);
195 if( config
&& config
->MaxPower
< 250 ) {
196 printf("adjusting charge setting");
201 printf("already at 500mA");
204 libusb_free_config_descriptor(config
);
207 printf("failed to discover power level\n");
210 // Retrieve the device descriptor
211 struct libusb_device_descriptor desc
;
212 err
= libusb_get_device_descriptor(dev
, &desc
);
214 printf("failed to get device descriptor: %d\n", err
);
222 printf("...no Pearl mode adjustment");
225 case PEARL_CLASSIC_MODE_0001
:
226 if( desc
.idProduct
!= PRODUCT_RIM_BLACKBERRY
) {
227 printf("...adjusting Pearl mode to single");
228 pearl_classic_mode(handle
);
232 printf("...already in classic/single mode");
236 case PEARL_DUAL_MODE_0004
:
237 if( desc
.idProduct
!= PRODUCT_RIM_PEARL_DUAL
) {
238 printf("...adjusting Pearl mode to dual");
239 pearl_dual_mode(handle
);
243 printf("...already in dual mode");
247 case CONDITIONAL_DUAL_MODE
:
248 if( find_interface(handle
, 255) == -1 ) {
249 printf("...no database iface found, setting dual mode");
250 pearl_dual_mode(handle
);
254 printf("...found database iface, no change");
259 printf("Bug: default case");
266 if( libusb_set_configuration(handle
, BLACKBERRY_CONFIGURATION
) < 0 )
267 driver_conflict(handle
);
269 // the Blackberry Pearl doesn't reset itself after the above,
270 // so do it ourselves
271 if( mode
== PEARL_DUAL_MODE_0004
) {
273 // It has been observed that the 8830 behaves both like
274 // a Pearl device (in that it has mass storage +
275 // database modes) as well as a Classic device in
276 // that it resets itself and doesn't need an explicit
279 // In order to deal with this, we insert a brief sleep.
280 // If it is an 8830, it will reset itself and the
281 // following reset call will fail. If it is a Pearl,
282 // the reset will work as normal.
285 err
= libusb_reset_device(handle
);
287 printf("\nlibusb_reset_device() failed: %d\n", err
);
294 printf("...no change");
299 libusb_close(handle
);
303 bool power_write(const std::string
&file
, const std::string
&value
)
305 // attempt to open the state file
306 int fd
= open(file
.c_str(), O_RDWR
);
308 printf("autosuspend adjustment failure: (file: %s): %s\n",
314 int written
= write(fd
, value
.data(), value
.size());
318 if( written
< 0 || (size_t)written
!= value
.size() ) {
319 printf("autosuspend adjustment failure (write): (file: %s): %s\n",
325 printf("autosuspend adjustment: wrote %s to %s\n",
326 value
.c_str(), file
.c_str());
331 // Checks for USB suspend, and enables the device if suspended.
333 // Kernel 2.6.21 behaves with autosuspend=0 meaning off, while 2.6.22
334 // and higher needs autosuspend=-1 to turn it off. In 2.6.22, a value
335 // of 0 means "immediate" instead of "never".
337 // Version 2.6.22 adds variables internal to the system called
338 // autosuspend_disabled and autoresume_disabled. These are controlled by the
339 // /sys/class/usb_device/*/device/power/level file. (See below)
341 // Here's a summary of files under device/power. These may or may not exist
342 // depending on your kernel version and configuration.
346 // -1 or 0 means off, depending on kernel,
347 // otherwise it is the number of seconds to
351 // with the settings:
353 // on - suspend is disabled, device is fully powered
354 // auto - suspend is controlled by the kernel (default)
355 // suspend - suspend is enabled permanently
357 // You can write these strings to the file to control
358 // behaviour on a per-device basis.
360 // echo on > /sys/usb_device/.../device/power/level
363 // current state of device
367 // You can write these numbers to control behaviour, but
368 // any change you make here might change automatically
369 // if autosuspend is on.
371 // echo -n 0 > /sys/usb_device/.../device/power/state
377 // Given the above facts, use the following heuristics to try to disable
378 // autosuspend for the Blackberry:
380 // - if level exists, write "on" to it
381 // - if autosuspend exists, write -1 to it
382 // - if error, write 0 to it
383 // - if neither of the above work, and state exists, write 0 to it
387 if( udev_devpath
.size() == 0 )
388 return; // nothing to do
390 // let sysfs settle a bit
393 std::string power_path
= sysfs_path
+ "/" + udev_devpath
+ "/device/power/";
395 if( !power_write(power_path
+ "level", "on\n") )
396 if( !power_write(power_path
+ "autosuspend", "-1\n") )
397 if( !power_write(power_path
+ "autosuspend", "0\n") )
398 power_write(power_path
+ "state", "0");
401 int main(int argc
, char *argv
[])
403 ModeType mode
= NO_CHANGE
;
408 // allow -o command line switch to choose which mode to use for
409 // Blackberry Pearls:
411 // With switch: 0001 -o
414 // process command line options
416 int cmd
= getopt(argc
, argv
, "dogp:s:h");
423 mode
= PEARL_DUAL_MODE_0004
;
426 case 'o': // Classic style pearl
427 mode
= PEARL_CLASSIC_MODE_0001
;
430 case 'g': // Guess whether dual is needed
431 mode
= CONDITIONAL_DUAL_MODE
;
434 case 'p': // udev devpath
435 udev_devpath
= optarg
;
438 case 's': // where sysfs is mounted
450 libusb_context
*usbctx
= NULL
;
451 int err
= libusb_init(&usbctx
);
453 printf("Failed to start up USB: %d\n", err
);
457 libusb_device
**devices
= NULL
;
458 int count
= libusb_get_device_list(usbctx
, &devices
);
460 printf("Scanning for Blackberry devices...\n");
462 for( int i
= 0; i
< count
; ++i
) {
463 // Is this a blackberry?
464 struct libusb_device_descriptor desc
;
465 err
= libusb_get_device_descriptor(devices
[i
], &desc
);
466 if( err
== 0 && desc
.idVendor
== VENDOR_RIM
) {
467 if( !process(devices
[i
], mode
) )
473 libusb_free_device_list(devices
, 1);