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