00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <usb.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <unistd.h>
00037 #include <errno.h>
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040 #include <fcntl.h>
00041 #include <string>
00042 #include <barry/common.h>
00043 #include "i18n.h"
00044
00045 bool old_style_pearl = false;
00046 bool force_dual = false;
00047 std::string udev_devpath;
00048 std::string sysfs_path = "/sys";
00049
00050 void Usage()
00051 {
00052 printf(
00053 "bcharge - Adjust Blackberry charging modes\n"
00054 " Copyright 2006-2010, Net Direct Inc. (http://www.netdirect.ca/)\n"
00055 "\n"
00056 " -d Dual mode (mode 0004) (default)\n"
00057 " -o Set a Pearl to old Blackberry mode (0001)\n"
00058 "\n"
00059 " -h This help message\n"
00060 " -p devpath The devpath argument from udev. If specified, will attempt\n"
00061 " to adjust USB suspend settings to keep the device charging.\n"
00062 " -s path The path where sysfs is mounted. Defaults to '/sys'\n"
00063 "\n"
00064 );
00065 }
00066
00067 void control(usb_dev_handle *dev, int requesttype, int request, int value,
00068 int index, char *bytes, int size, int timeout)
00069 {
00070 int result = usb_control_msg(dev, requesttype, request, value, index,
00071 bytes, size, timeout);
00072 if( result < 0 ) {
00073 printf("\nusb_control_msg failed: code: %d, %s\n", result,
00074 usb_strerror());
00075 }
00076 }
00077
00078 void charge(struct usb_dev_handle *handle)
00079 {
00080
00081
00082 char buffer[2];
00083 control(handle, 0xc0, 0xa5, 0, 1, buffer, 2, 100);
00084 control(handle, 0x40, 0xa2, 0, 1, buffer, 0, 100);
00085 }
00086
00087 void pearl_mode(struct usb_dev_handle *handle)
00088 {
00089 char buffer[2];
00090 if( old_style_pearl ) {
00091
00092 control(handle, 0xc0, 0xa9, 0, 1, buffer, 2, 100);
00093 }
00094 else {
00095
00096 control(handle, 0xc0, 0xa9, 1, 1, buffer, 2, 100);
00097 }
00098 }
00099
00100 int find_mass_storage_interface(struct usb_dev_handle *handle)
00101 {
00102
00103
00104 struct usb_device *dev = usb_device(handle);
00105 struct usb_config_descriptor *cfg = dev ? dev->config : 0;
00106
00107 if( cfg ) {
00108
00109 for( unsigned i = 0; cfg->interface && i < cfg->bNumInterfaces; i++ ) {
00110 struct usb_interface *iface = &cfg->interface[i];
00111 for( int a = 0; iface->altsetting && a < iface->num_altsetting; a++ ) {
00112 struct usb_interface_descriptor *id = &iface->altsetting[a];
00113 if( id->bInterfaceClass == USB_CLASS_MASS_STORAGE )
00114 return id->bInterfaceNumber;
00115 }
00116 }
00117 }
00118
00119
00120
00121
00122
00123 printf("Can't find Mass Storage interface, assuming 0.\n");
00124 return 0;
00125 }
00126
00127 void driver_conflict(struct usb_dev_handle *handle)
00128 {
00129
00130
00131
00132
00133
00134 #if LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
00135 printf("Detecting possible kernel driver conflict, trying to resolve...\n");
00136
00137 int iface = find_mass_storage_interface(handle);
00138 if( usb_detach_kernel_driver_np(handle, iface) < 0 )
00139 printf("usb_detach_kernel_driver_np() failed: %s\n", usb_strerror());
00140
00141 if( usb_set_configuration(handle, BLACKBERRY_CONFIGURATION) < 0 )
00142 printf("usb_set_configuration() failed: %s\n", usb_strerror());
00143 #endif
00144 }
00145
00146
00147 bool process(struct usb_device *dev, bool is_pearl)
00148 {
00149 bool apply = false;
00150 printf("Found device #%s...", dev->filename);
00151
00152
00153 usb_dev_handle *handle = usb_open(dev);
00154 if( !handle ) {
00155 printf("unable to open device\n");
00156 return false;
00157 }
00158
00159
00160 if( dev->config &&
00161 dev->descriptor.bNumConfigurations >= 1 &&
00162 dev->config[0].MaxPower < 250 ) {
00163 printf("adjusting charge setting");
00164 charge(handle);
00165 apply = true;
00166 }
00167 else {
00168 printf("already at 500mA");
00169 }
00170
00171
00172 if( is_pearl || force_dual ) {
00173 int desired_mode = old_style_pearl
00174 ? PRODUCT_RIM_BLACKBERRY : PRODUCT_RIM_PEARL_DUAL;
00175
00176 if( desired_mode != dev->descriptor.idProduct ) {
00177 printf("...adjusting Pearl mode to %s",
00178 old_style_pearl ? "single" : "dual");
00179 pearl_mode(handle);
00180 apply = true;
00181 }
00182 else {
00183 printf("...already in desired Pearl mode");
00184 }
00185 }
00186 else {
00187 printf("...no Pearl adjustment");
00188 }
00189
00190
00191 if( apply ) {
00192 if( usb_set_configuration(handle, BLACKBERRY_CONFIGURATION) < 0 )
00193 driver_conflict(handle);
00194
00195
00196
00197 if( is_pearl || force_dual ) {
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 sleep(1);
00211 if( usb_reset(handle) < 0 ) {
00212 printf("\nusb_reset failed: %s\n", usb_strerror());
00213 }
00214 }
00215
00216 printf("...done\n");
00217 }
00218 else {
00219 printf("...no change\n");
00220 }
00221
00222
00223 usb_close(handle);
00224 return apply;
00225 }
00226
00227 bool power_write(const std::string &file, const std::string &value)
00228 {
00229
00230 int fd = open(file.c_str(), O_RDWR);
00231 if( fd == -1 ) {
00232 printf("autosuspend adjustment failure: (file: %s): %s\n",
00233 file.c_str(),
00234 strerror(errno));
00235 return false;
00236 }
00237
00238 int written = write(fd, value.data(), value.size());
00239 int error = errno;
00240 close(fd);
00241
00242 if( written < 0 || (size_t)written != value.size() ) {
00243 printf("autosuspend adjustment failure (write): (file: %s): %s\n",
00244 file.c_str(),
00245 strerror(error));
00246 return false;
00247 }
00248
00249 printf("autosuspend adjustment: wrote %s to %s\n",
00250 value.c_str(), file.c_str());
00251 return true;
00252 }
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 void resume()
00310 {
00311 if( udev_devpath.size() == 0 )
00312 return;
00313
00314
00315 sleep(5);
00316
00317 std::string power_path = sysfs_path + "/" + udev_devpath + "/device/power/";
00318
00319 if( !power_write(power_path + "level", "on\n") )
00320 if( !power_write(power_path + "autosuspend", "-1\n") )
00321 if( !power_write(power_path + "autosuspend", "0\n") )
00322 power_write(power_path + "state", "0");
00323 }
00324
00325 int main(int argc, char *argv[])
00326 {
00327 struct usb_bus *busses;
00328
00329 INIT_I18N(PACKAGE);
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 for(;;) {
00340 int cmd = getopt(argc, argv, "dop:s:h");
00341 if( cmd == -1 )
00342 break;
00343
00344 switch( cmd )
00345 {
00346 case 'd':
00347 force_dual = true;
00348 old_style_pearl = false;
00349 break;
00350
00351 case 'o':
00352 force_dual = false;
00353 old_style_pearl = true;
00354 break;
00355
00356 case 'p':
00357 udev_devpath = optarg;
00358 break;
00359
00360 case 's':
00361 sysfs_path = optarg;
00362 break;
00363
00364 case 'h':
00365 default:
00366 Usage();
00367 return 0;
00368 }
00369 }
00370
00371 usb_init();
00372 if( usb_find_busses() < 0 || usb_find_devices() < 0 ) {
00373 printf("\nUnable to scan devices: %s\n", usb_strerror());
00374 return 1;
00375 }
00376 busses = usb_get_busses();
00377
00378 printf("Scanning for Blackberry devices...\n");
00379
00380 struct usb_bus *bus;
00381 for( bus = busses; bus; bus = bus->next ) {
00382 struct usb_device *dev;
00383
00384 for (dev = bus->devices; dev; dev = dev->next) {
00385
00386 if( dev->descriptor.idVendor == VENDOR_RIM ) {
00387 switch(dev->descriptor.idProduct)
00388 {
00389 case PRODUCT_RIM_BLACKBERRY:
00390 if( !process(dev, false) )
00391 resume();
00392 break;
00393
00394 case PRODUCT_RIM_PEARL_DUAL:
00395 case PRODUCT_RIM_PEARL:
00396 case PRODUCT_RIM_PEARL_8120:
00397 case PRODUCT_RIM_PEARL_FLIP:
00398 case PRODUCT_RIM_STORM:
00399 if( !process(dev, true) )
00400 resume();
00401 break;
00402 }
00403 }
00404 }
00405 }
00406 }
00407