Stealth Mode script
[tomato.git] / release / src / router / usbmodeswitch / usb_modeswitch.c
blob762138dc7d47653b3b25d1c4c8e3d570c8332fe3
1 /*
2 Mode switching tool for controlling flip flop (multiple device) USB gear
3 Version 1.1.9, 2011/08/05
5 Copyright (C) 2007 - 2011 Josua Dietze (mail to "usb_admin" at the domain
6 from the README; please do not post the complete address to the Internet!
7 Or write a personal message through the forum to "Josh". NO SUPPORT VIA
8 E-MAIL - please use the forum for that)
10 Command line parsing, decent usage/config output/handling, bugfixes and advanced
11 options added by:
12 Joakim Wennergren
14 TargetClass parameter implementation to support new Option devices/firmware:
15 Paul Hardwick (http://www.pharscape.org)
17 Created with initial help from:
18 "usbsnoop2libusb.pl" by Timo Lindfors (http://iki.fi/lindi/usb/usbsnoop2libusb.pl)
20 Config file parsing stuff borrowed from:
21 Guillaume Dargaud (http://www.gdargaud.net/Hack/SourceCode.html)
23 Hexstr2bin function borrowed from:
24 Jouni Malinen (http://hostap.epitest.fi/wpa_supplicant, from "common.c")
26 Other contributions: see README
28 Device information contributors are named in the "usb_modeswitch.setup" file.
30 This program is free software; you can redistribute it and/or modify
31 it under the terms of the GNU General Public License as published by
32 the Free Software Foundation; either version 2 of the License, or
33 (at your option) any later version.
35 This program is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 GNU General Public License for more details:
40 http://www.gnu.org/licenses/gpl.txt
44 /* Recommended tab size: 4 */
46 #define VERSION "1.1.9"
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <signal.h>
52 #include <ctype.h>
53 #include <getopt.h>
54 #include <syslog.h>
55 #include <unistd.h>
57 #include "usb_modeswitch.h"
59 #define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
60 #define LIBUSB_HAS_GET_DRIVER_NP
62 #define USB_ENDPOINT_IN LIBUSB_ENDPOINT_IN
63 #define USB_ENDPOINT_OUT LIBUSB_ENDPOINT_OUT
64 #define USB_ENDPOINT_TYPE_MASK LIBUSB_ENDPOINT_ADDRESS_MASK
65 #define USB_ENDPOINT_DIR_MASK LIBUSB_ENDPOINT_DIR_MASK
66 #define USB_ENDPOINT_TYPE_BULK LIBUSB_TRANSFER_TYPE_BULK
67 #define USB_TYPE_STANDARD LIBUSB_REQUEST_TYPE_STANDARD
68 #define USB_TYPE_CLASS LIBUSB_REQUEST_TYPE_CLASS
69 #define USB_TYPE_VENDOR LIBUSB_REQUEST_TYPE_VENDOR
70 #define USB_RECIP_DEVICE LIBUSB_RECIPIENT_DEVICE
71 #define USB_RECIP_INTERFACE LIBUSB_RECIPIENT_INTERFACE
72 #define USB_REQ_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE
73 #define USB_REQ_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION
75 #define usb_set_debug(x) libusb_set_debug(ctx, 3)
76 #define usb_close libusb_close
77 #define usb_get_string_simple libusb_get_string_descriptor_ascii
78 #define usb_reset libusb_reset_device
79 #define usb_claim_interface libusb_claim_interface
80 #define usb_clear_halt libusb_clear_halt
81 #define usb_release_interface libusb_release_interface
82 #define usb_control_msg libusb_control_transfer
83 #define usb_set_configuration libusb_set_configuration
84 #define usb_detach_kernel_driver_np libusb_detach_kernel_driver
86 /* libusb 1.0 wrappers */
87 int usb_bulk_io(struct libusb_device_handle *handle, int ep, char *bytes,
88 int size, int timeout)
90 int actual_length;
91 int r;
92 // usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
93 r = libusb_bulk_transfer(handle, ep & 0xff, bytes, size,
94 &actual_length, timeout);
96 /* if we timed out but did transfer some data, report as successful short
97 * read. FIXME: is this how libusb-0.1 works? */
98 if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
99 return actual_length;
101 return r;
104 int usb_bulk_read(struct libusb_device_handle *handle, int ep, char *bytes,
105 int size, int timeout)
107 if (!(ep & LIBUSB_ENDPOINT_IN)) {
108 /* libusb-0.1 will strangely fix up a read request from endpoint
109 * 0x01 to be from endpoint 0x81. do the same thing here, but
110 * warn about this silly behaviour. */
111 printf("endpoint %x is missing IN direction bit, fixing", ep);
112 ep |= LIBUSB_ENDPOINT_IN;
115 return usb_bulk_io(handle, ep, bytes, size, timeout);
118 int usb_bulk_write(struct libusb_device_handle *handle, int ep, char *bytes,
119 int size, int timeout)
121 if (ep & LIBUSB_ENDPOINT_IN) {
122 /* libusb-0.1 on BSD strangely fix up a write request to endpoint
123 * 0x81 to be to endpoint 0x01. do the same thing here, but
124 * warn about this silly behaviour. */
125 printf("endpoint %x has excessive IN direction bit, fixing", ep);
126 ep &= ~LIBUSB_ENDPOINT_IN;
129 return usb_bulk_io(handle, ep, bytes, size, timeout);
132 static int usb_interrupt_io(libusb_device_handle *handle, int ep, char *bytes,
133 int size, int timeout)
135 int actual_length;
136 int r;
137 // usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
138 r = libusb_interrupt_transfer(handle, ep & 0xff, bytes, size,
139 &actual_length, timeout);
141 /* if we timed out but did transfer some data, report as successful short
142 * read. FIXME: is this how libusb-0.1 works? */
143 if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
144 return actual_length;
146 return (r);
149 int usb_interrupt_read(libusb_device_handle *handle, int ep, char *bytes,
150 int size, int timeout)
152 if (!(ep & USB_ENDPOINT_IN)) {
153 /* libusb-0.1 will strangely fix up a read request from endpoint
154 * 0x01 to be from endpoint 0x81. do the same thing here, but
155 * warn about this silly behaviour. */
156 printf("endpoint %x is missing IN direction bit, fixing", ep);
157 ep |= USB_ENDPOINT_IN;
159 return usb_interrupt_io(handle, ep, bytes, size, timeout);
162 int usb_interrupt_write(libusb_device_handle *handle, int ep, char *bytes,
163 int size, int timeout)
165 if (ep & USB_ENDPOINT_IN) {
166 /* libusb-0.1 on BSD strangely fix up a write request to endpoint
167 * 0x81 to be to endpoint 0x01. do the same thing here, but
168 * warn about this silly behaviour. */
169 printf("endpoint %x has excessive IN direction bit, fixing", ep);
170 ep &= ~USB_ENDPOINT_IN;
173 return usb_interrupt_io(handle, ep, bytes, size, timeout);
176 int usb_get_driver_np(struct libusb_device_handle *dev, int interface,
177 char *name, unsigned int namelen)
179 int r = libusb_kernel_driver_active(dev, interface);
180 if (r == 1) {
181 /* libusb-1.0 doesn't expose driver name, so fill in a dummy value */
182 snprintf(name, namelen, "dummy");
183 return 0;
184 } else return r;
187 #define LINE_DIM 1024
188 #define BUF_SIZE 4096
189 #define DESCR_MAX 129
191 #define SEARCH_DEFAULT 0
192 #define SEARCH_TARGET 1
194 #define SHOW_PROGRESS if (show_progress) printf
196 char *TempPP=NULL;
198 static struct libusb_context *ctx = NULL;
199 static struct libusb_device *dev;
200 static struct libusb_device_handle *devh;
202 int DefaultVendor=0, DefaultProduct=0, TargetVendor=0, TargetProduct=-1, TargetClass=0;
203 int MessageEndpoint=0, ResponseEndpoint=0, ReleaseDelay=0;
204 int targetDeviceCount=0;
205 int devnum=-1, busnum=-1;
206 int ret;
208 char DetachStorageOnly=0, HuaweiMode=0, SierraMode=0, SonyMode=0, GCTMode=0, KobilMode=0;
209 char SequansMode=0, MobileActionMode=0, CiscoMode=0;
210 char verbose=0, show_progress=1, ResetUSB=0, CheckSuccess=0, config_read=0;
211 char NeedResponse=0, NoDriverLoading=0, InquireDevice=1, sysmode=0;
213 char imanufact[DESCR_MAX], iproduct[DESCR_MAX], iserial[DESCR_MAX];
215 char MessageContent[LINE_DIM];
216 char MessageContent2[LINE_DIM];
217 char MessageContent3[LINE_DIM];
218 char TargetProductList[LINE_DIM];
219 char ByteString[LINE_DIM/2];
220 char buffer[BUF_SIZE];
222 /* Settable Interface and Configuration (for debugging mostly) (jmw) */
223 int Interface = 0, Configuration = 0, AltSetting = -1;
226 static struct option long_options[] = {
227 {"help", no_argument, 0, 'h'},
228 {"version", no_argument, 0, 'e'},
229 {"default-vendor", required_argument, 0, 'v'},
230 {"default-product", required_argument, 0, 'p'},
231 {"target-vendor", required_argument, 0, 'V'},
232 {"target-product", required_argument, 0, 'P'},
233 {"target-class", required_argument, 0, 'C'},
234 {"message-endpoint", required_argument, 0, 'm'},
235 {"message-content", required_argument, 0, 'M'},
236 {"message-content2", required_argument, 0, '2'},
237 {"message-content3", required_argument, 0, '3'},
238 {"release-delay", required_argument, 0, 'w'},
239 {"response-endpoint", required_argument, 0, 'r'},
240 {"detach-only", no_argument, 0, 'd'},
241 {"huawei-mode", no_argument, 0, 'H'},
242 {"sierra-mode", no_argument, 0, 'S'},
243 {"sony-mode", no_argument, 0, 'O'},
244 {"kobil-mode", no_argument, 0, 'T'},
245 {"gct-mode", no_argument, 0, 'G'},
246 {"sequans-mode", no_argument, 0, 'N'},
247 {"mobileaction-mode", no_argument, 0, 'A'},
248 {"cisco-mode", no_argument, 0, 'L'},
249 {"need-response", no_argument, 0, 'n'},
250 {"reset-usb", no_argument, 0, 'R'},
251 {"config-file", required_argument, 0, 'c'},
252 {"verbose", no_argument, 0, 'W'},
253 {"quiet", no_argument, 0, 'Q'},
254 {"sysmode", no_argument, 0, 'D'},
255 {"no-inquire", no_argument, 0, 'I'},
256 {"check-success", required_argument, 0, 's'},
257 {"interface", required_argument, 0, 'i'},
258 {"configuration", required_argument, 0, 'u'},
259 {"altsetting", required_argument, 0, 'a'},
260 {0, 0, 0, 0}
264 void readConfigFile(const char *configFilename)
266 if (verbose) printf("\nReading config file: %s\n", configFilename);
267 ParseParamHex(configFilename, TargetVendor);
268 ParseParamHex(configFilename, TargetProduct);
269 ParseParamString(configFilename, TargetProductList);
270 ParseParamHex(configFilename, TargetClass);
271 ParseParamHex(configFilename, DefaultVendor);
272 ParseParamHex(configFilename, DefaultProduct);
273 ParseParamBool(configFilename, DetachStorageOnly);
274 ParseParamBool(configFilename, HuaweiMode);
275 ParseParamBool(configFilename, SierraMode);
276 ParseParamBool(configFilename, SonyMode);
277 ParseParamBool(configFilename, GCTMode);
278 ParseParamBool(configFilename, KobilMode);
279 ParseParamBool(configFilename, SequansMode);
280 ParseParamBool(configFilename, MobileActionMode);
281 ParseParamBool(configFilename, CiscoMode);
282 ParseParamBool(configFilename, NoDriverLoading);
283 ParseParamHex(configFilename, MessageEndpoint);
284 ParseParamString(configFilename, MessageContent);
285 ParseParamString(configFilename, MessageContent2);
286 ParseParamString(configFilename, MessageContent3);
287 ParseParamInt(configFilename, ReleaseDelay);
288 ParseParamHex(configFilename, NeedResponse);
289 ParseParamHex(configFilename, ResponseEndpoint);
290 ParseParamHex(configFilename, ResetUSB);
291 ParseParamHex(configFilename, InquireDevice);
292 ParseParamInt(configFilename, CheckSuccess);
293 ParseParamHex(configFilename, Interface);
294 ParseParamHex(configFilename, Configuration);
295 ParseParamHex(configFilename, AltSetting);
297 /* TargetProductList has priority over TargetProduct */
298 if (TargetProduct != -1 && TargetProductList[0] != '\0') {
299 TargetProduct = -1;
300 SHOW_PROGRESS("Warning: TargetProductList overrides TargetProduct!\n");
303 config_read = 1;
307 void printConfig()
309 if ( DefaultVendor )
310 printf ("DefaultVendor= 0x%04x\n", DefaultVendor);
311 else
312 printf ("DefaultVendor= not set\n");
313 if ( DefaultProduct )
314 printf ("DefaultProduct= 0x%04x\n", DefaultProduct);
315 else
316 printf ("DefaultProduct= not set\n");
317 if ( TargetVendor )
318 printf ("TargetVendor= 0x%04x\n", TargetVendor);
319 else
320 printf ("TargetVendor= not set\n");
321 if ( TargetProduct > -1 )
322 printf ("TargetProduct= 0x%04x\n", TargetProduct);
323 else
324 printf ("TargetProduct= not set\n");
325 if ( TargetClass )
326 printf ("TargetClass= 0x%02x\n", TargetClass);
327 else
328 printf ("TargetClass= not set\n");
329 printf ("TargetProductList=\"%s\"\n", TargetProductList);
330 printf ("\nDetachStorageOnly=%i\n", (int)DetachStorageOnly);
331 printf ("HuaweiMode=%i\n", (int)HuaweiMode);
332 printf ("SierraMode=%i\n", (int)SierraMode);
333 printf ("SonyMode=%i\n", (int)SonyMode);
334 printf ("GCTMode=%i\n", (int)GCTMode);
335 printf ("KobilMode=%i\n", (int)KobilMode);
336 printf ("SequansMode=%i\n", (int)SequansMode);
337 printf ("MobileActionMode=%i\n", (int)MobileActionMode);
338 printf ("CiscoMode=%i\n", (int)CiscoMode);
339 if ( MessageEndpoint )
340 printf ("MessageEndpoint=0x%02x\n", MessageEndpoint);
341 else
342 printf ("MessageEndpoint= not set\n");
343 printf ("MessageContent=\"%s\"\n", MessageContent);
344 if ( strlen(MessageContent2) )
345 printf ("MessageContent2=\"%s\"\n", MessageContent2);
346 if ( strlen(MessageContent3) )
347 printf ("MessageContent3=\"%s\"\n", MessageContent3);
348 printf ("NeedResponse=%i\n", (int)NeedResponse);
349 if ( ResponseEndpoint )
350 printf ("ResponseEndpoint=0x%02x\n", ResponseEndpoint);
351 else
352 printf ("ResponseEndpoint= not set\n");
353 printf ("Interface=0x%02x\n", Interface);
354 if ( Configuration > 0 )
355 printf ("Configuration=0x%02x\n", Configuration);
356 if ( AltSetting > -1 )
357 printf ("AltSetting=0x%02x\n", AltSetting);
358 if ( InquireDevice )
359 printf ("\nInquireDevice enabled (default)\n");
360 else
361 printf ("\nInquireDevice disabled\n");
362 if ( CheckSuccess )
363 printf ("Success check enabled, max. wait time %d seconds\n", CheckSuccess);
364 else
365 printf ("Success check disabled\n");
366 if ( sysmode )
367 printf ("System integration mode enabled\n");
368 else
369 printf ("System integration mode disabled\n");
370 printf ("\n");
374 int readArguments(int argc, char **argv)
376 int c, option_index = 0, count=0;
377 if (argc==1)
379 printHelp();
380 printVersion();
381 exit(1);
384 while (1)
386 c = getopt_long (argc, argv, "heWQDndHSOGTNALRIv:p:V:P:C:m:M:2:3:w:r:c:i:u:a:s:",
387 long_options, &option_index);
389 /* Detect the end of the options. */
390 if (c == -1)
391 break;
392 count++;
393 switch (c)
395 case 'R': ResetUSB = 1; break;
396 case 'v': DefaultVendor = strtol(optarg, NULL, 16); break;
397 case 'p': DefaultProduct = strtol(optarg, NULL, 16); break;
398 case 'V': TargetVendor = strtol(optarg, NULL, 16); break;
399 case 'P': TargetProduct = strtol(optarg, NULL, 16); break;
400 case 'C': TargetClass = strtol(optarg, NULL, 16); break;
401 case 'm': MessageEndpoint = strtol(optarg, NULL, 16); break;
402 case 'M': strcpy(MessageContent, optarg); break;
403 case '2': strcpy(MessageContent2, optarg); break;
404 case '3': strcpy(MessageContent3, optarg); break;
405 case 'w': ReleaseDelay = strtol(optarg, NULL, 10); count--; break;
406 case 'n': NeedResponse = 1; break;
407 case 'r': ResponseEndpoint = strtol(optarg, NULL, 16); break;
408 case 'd': DetachStorageOnly = 1; break;
409 case 'H': HuaweiMode = 1; break;
410 case 'S': SierraMode = 1; break;
411 case 'O': SonyMode = 1; break;
412 case 'G': GCTMode = 1; break;
413 case 'T': KobilMode = 1; break;
414 case 'N': SequansMode = 1; break;
415 case 'A': MobileActionMode = 1; break;
416 case 'L': CiscoMode = 1; break;
417 case 'c': readConfigFile(optarg); break;
418 case 'W': verbose = 1; show_progress = 1; count--; break;
419 case 'Q': show_progress = 0; verbose = 0; count--; break;
420 case 'D': sysmode = 1; count--; break;
421 case 's': CheckSuccess = strtol(optarg, NULL, 10); count--; break;
422 case 'I': InquireDevice = 0; break;
424 case 'i': Interface = strtol(optarg, NULL, 16); break;
425 case 'u': Configuration = strtol(optarg, NULL, 16); break;
426 case 'a': AltSetting = strtol(optarg, NULL, 16); break;
428 case 'e':
429 printVersion();
430 exit(0);
431 break;
432 case 'h':
433 printVersion();
434 printHelp();
435 exit(0);
436 break;
438 default: /* Unsupported - error message has already been printed */
439 printf ("\n");
440 printHelp();
441 exit(1);
445 return count;
449 int main(int argc, char **argv)
451 int numDefaults=0, specialMode=0, sonySuccess=0;
452 int currentConfig=0, defaultClass=0, interfaceClass=0;
454 /* Make sure we have empty strings even if not set by config */
455 TargetProductList[0] = '\0';
456 MessageContent[0] = '\0';
457 MessageContent2[0] = '\0';
458 MessageContent3[0] = '\0';
461 signal(SIGTERM, release_usb_device);
463 * Parameter parsing, USB preparation/diagnosis, plausibility checks
466 /* Check command arguments, use params instead of config file when given */
467 switch (readArguments(argc, argv)) {
468 case 0: /* no argument or -W, -q or -s */
469 break;
470 default: /* one or more arguments except -W, -q or -s */
471 if (!config_read) /* if arguments contain -c, the config file was already processed */
472 if (verbose) printf("Taking all parameters from the command line\n\n");
475 if (verbose)
476 printVersion();
478 if (verbose)
479 printConfig();
481 /* libusb initialization */
482 libusb_init(&ctx);
484 if (verbose)
485 usb_set_debug(15);
487 /* Plausibility checks. The default IDs are mandatory */
488 if (!(DefaultVendor && DefaultProduct)) {
489 SHOW_PROGRESS("No default vendor/product ID given. Aborting.\n\n");
490 exit(1);
492 if (strlen(MessageContent)) {
493 if (strlen(MessageContent) % 2 != 0) {
494 fprintf(stderr, "Error: MessageContent hex string has uneven length. Aborting.\n\n");
495 exit(1);
497 if ( hexstr2bin(MessageContent, ByteString, strlen(MessageContent)/2) == -1) {
498 fprintf(stderr, "Error: MessageContent %s\n is not a hex string. Aborting.\n\n", MessageContent);
499 exit(1);
502 SHOW_PROGRESS("\n");
504 if (show_progress)
505 if (CheckSuccess && !(TargetVendor || TargetProduct > -1 || TargetProductList[0] != '\0') && !TargetClass)
506 printf("Note: target parameter missing; success check limited\n");
508 /* Count existing target devices, remember for success check */
509 if (TargetVendor || TargetClass) {
510 SHOW_PROGRESS("Looking for target devices ...\n");
511 search_devices(&targetDeviceCount, TargetVendor, TargetProduct, TargetProductList, TargetClass, 0, SEARCH_TARGET);
512 if (targetDeviceCount) {
513 SHOW_PROGRESS(" Found devices in target mode or class (%d)\n", targetDeviceCount);
514 } else
515 SHOW_PROGRESS(" No devices in target mode or class found\n");
518 /* Count default devices, get the last one found */
519 SHOW_PROGRESS("Looking for default devices ...\n");
520 dev = search_devices(&numDefaults, DefaultVendor, DefaultProduct, "\0", TargetClass, Configuration, SEARCH_DEFAULT);
521 if (numDefaults) {
522 SHOW_PROGRESS(" Found devices in default mode, class or configuration (%d)\n", numDefaults);
523 } else {
524 SHOW_PROGRESS(" No devices in default mode found. Nothing to do. Bye.\n\n");
525 exit(0);
527 if (dev != NULL) {
528 devnum = libusb_get_device_address(dev);
529 busnum = libusb_get_bus_number(dev);
530 SHOW_PROGRESS("Accessing device %03d on bus %03d ...\n", devnum, busnum);
531 libusb_open(dev, &devh);
532 } else {
533 SHOW_PROGRESS(" No default device found. Is it connected? Bye.\n\n");
534 exit(0);
537 /* Get current configuration of default device
538 * A configuration value of -1 denotes a quirky device which has
539 * trouble determining the current configuration. Just use the first
540 * branch (which may be incorrect)
542 if (Configuration > -1)
543 currentConfig = get_current_configuration(devh);
544 else {
545 SHOW_PROGRESS("Skipping the check for the current configuration\n");
546 currentConfig = 0;
549 /* Get class of default device/interface */
550 struct libusb_device_descriptor descriptor;
551 libusb_get_device_descriptor(dev, &descriptor);
552 defaultClass = descriptor.bDeviceClass;
553 struct libusb_config_descriptor *config;
554 libusb_get_config_descriptor(dev, 0, &config);
555 interfaceClass = config->interface[0].altsetting[0].bInterfaceClass;
556 libusb_free_config_descriptor(config);
557 if (interfaceClass == -1) {
558 fprintf(stderr, "Error: getting the interface class failed. Aborting.\n\n");
559 exit(1);
562 if (defaultClass == 0)
563 defaultClass = interfaceClass;
564 else
565 if (interfaceClass == 8 && defaultClass != 8) {
566 /* Weird device with default class other than 0 and differing interface class */
567 SHOW_PROGRESS("Ambiguous Class/InterfaceClass: 0x%02x/0x08\n", defaultClass);
568 defaultClass = 8;
571 /* Check or get endpoints */
572 if (strlen(MessageContent) || InquireDevice || CiscoMode) {
573 if (!MessageEndpoint)
574 MessageEndpoint = find_first_bulk_output_endpoint(dev);
575 if (!MessageEndpoint) {
576 fprintf(stderr,"Error: message endpoint not given or found. Aborting.\n\n");
577 exit(1);
579 if (!ResponseEndpoint)
580 ResponseEndpoint = find_first_bulk_input_endpoint(dev);
581 if (!ResponseEndpoint) {
582 fprintf(stderr,"Error: response endpoint not given or found. Aborting.\n\n");
583 exit(1);
585 SHOW_PROGRESS("Using endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint, ResponseEndpoint);
588 if (!MessageEndpoint || !ResponseEndpoint)
589 if (InquireDevice && defaultClass == 0x08) {
590 SHOW_PROGRESS("Endpoints not found, skipping SCSI inquiry\n");
591 InquireDevice = 0;
594 if (InquireDevice && show_progress) {
595 if (defaultClass == 0x08) {
596 SHOW_PROGRESS("Inquiring device details; driver will be detached ...\n");
597 detachDriver();
598 if (deviceInquire() >= 0)
599 InquireDevice = 2;
600 } else
601 SHOW_PROGRESS("Not a storage device, skipping SCSI inquiry\n");
604 deviceDescription();
605 if (show_progress) {
606 printf("\nUSB description data (for identification)\n");
607 printf("-------------------------\n");
608 printf("Manufacturer: %s\n", imanufact);
609 printf(" Product: %s\n", iproduct);
610 printf(" Serial No.: %s\n", iserial);
611 printf("-------------------------\n");
614 /* Some scenarios are exclusive, so check for unwanted combinations */
615 specialMode = DetachStorageOnly + HuaweiMode + SierraMode + SonyMode + KobilMode
616 + SequansMode + MobileActionMode + CiscoMode;
617 if ( specialMode > 1 ) {
618 SHOW_PROGRESS("Invalid mode combination. Check your configuration. Aborting.\n\n");
619 exit(1);
622 if ( !specialMode && !strlen(MessageContent) && AltSetting == -1 && Configuration == 0 )
623 SHOW_PROGRESS("Warning: no switching method given.\n");
626 * The switching actions
629 if (sysmode) {
630 openlog("usb_modeswitch", 0, LOG_SYSLOG);
631 syslog(LOG_NOTICE, "switching %04x:%04x (%s: %s)", DefaultVendor, DefaultProduct, imanufact, iproduct);
634 if (DetachStorageOnly) {
635 SHOW_PROGRESS("Only detaching storage driver for switching ...\n");
636 if (InquireDevice == 2) {
637 SHOW_PROGRESS(" Any driver was already detached for inquiry\n");
638 } else {
639 ret = detachDriver();
640 if (ret == 2)
641 SHOW_PROGRESS(" You may want to remove the storage driver manually\n");
645 if (HuaweiMode) {
646 switchHuaweiMode();
648 if (SierraMode) {
649 switchSierraMode();
651 if (GCTMode) {
652 detachDriver();
653 switchGCTMode();
655 if(KobilMode) {
656 detachDriver();
657 switchKobilMode();
659 if (SequansMode) {
660 switchSequansMode();
662 if(MobileActionMode) {
663 switchActionMode();
665 if(CiscoMode) {
666 detachDriver();
667 switchCiscoMode();
669 if (SonyMode) {
670 if (CheckSuccess)
671 SHOW_PROGRESS("Note: ignoring CheckSuccess. Separate checks for Sony mode\n");
672 CheckSuccess = 0; /* separate and implied success control */
673 sonySuccess = switchSonyMode();
676 if (strlen(MessageContent) && MessageEndpoint) {
677 if (specialMode == 0) {
678 if (InquireDevice != 2)
679 detachDriver();
680 switchSendMessage();
681 } else
682 SHOW_PROGRESS("Warning: ignoring MessageContent. Can't combine with special mode\n");
685 if (Configuration > 0) {
686 if (currentConfig != Configuration) {
687 if (switchConfiguration()) {
688 currentConfig = get_current_configuration(devh);
689 if (currentConfig == Configuration) {
690 SHOW_PROGRESS("The configuration was set successfully\n");
691 } else {
692 SHOW_PROGRESS("Changing the configuration has failed\n");
695 } else {
696 SHOW_PROGRESS("Target configuration %d already active. Doing nothing\n", currentConfig);
700 if (AltSetting != -1) {
701 switchAltSetting();
704 /* No "removal" check if these are set */
705 if ((Configuration > 0 || AltSetting > -1) && !ResetUSB) {
706 usb_close(devh);
707 devh = 0;
710 if (ResetUSB) {
711 resetUSB();
712 usb_close(devh);
713 devh = 0;
716 if (CheckSuccess) {
717 if (checkSuccess()) {
718 if (sysmode) {
719 if (NoDriverLoading)
720 printf("ok:\n");
721 else
722 if (TargetProduct < 1)
723 printf("ok:no_data\n");
724 else
725 printf("ok:%04x:%04x\n", TargetVendor, TargetProduct);
727 } else
728 if (sysmode)
729 printf("fail:\n");
730 } else {
731 if (SonyMode)
732 if (sonySuccess) {
733 if (sysmode) {
734 syslog(LOG_NOTICE, "switched S.E. MD400 to modem mode");
735 printf("ok:\n"); /* ACM device, no driver action */
737 SHOW_PROGRESS("-> device should be stable now. Bye.\n\n");
738 } else {
739 if (sysmode)
740 printf("fail:\n");
741 SHOW_PROGRESS("-> switching was probably not completed. Bye.\n\n");
743 else
744 SHOW_PROGRESS("-> Run lsusb to note any changes. Bye.\n\n");
747 if (sysmode)
748 closelog();
749 if (devh)
750 usb_close(devh);
751 exit(0);
755 /* Get descriptor strings if available (identification details) */
756 void deviceDescription ()
758 int ret;
759 char* c;
760 memset (imanufact, ' ', DESCR_MAX);
761 memset (iproduct, ' ', DESCR_MAX);
762 memset (iserial, ' ', DESCR_MAX);
764 struct libusb_device_descriptor descriptor;
765 libusb_get_device_descriptor(dev, &descriptor);
767 int iManufacturer = descriptor.iManufacturer;
768 int iProduct = descriptor.iProduct;
769 int iSerialNumber = descriptor.iSerialNumber;
771 if (iManufacturer) {
772 ret = usb_get_string_simple(devh, iManufacturer, imanufact, DESCR_MAX);
773 if (ret < 0)
774 fprintf(stderr, "Error: could not get description string \"manufacturer\"\n");
775 } else
776 strcpy(imanufact, "not provided");
777 c = strstr(imanufact, " ");
778 if (c)
779 memset((void*)c, '\0', 1);
781 if (iProduct) {
782 ret = usb_get_string_simple(devh, iProduct, iproduct, DESCR_MAX);
783 if (ret < 0)
784 fprintf(stderr, "Error: could not get description string \"product\"\n");
785 } else
786 strcpy(iproduct, "not provided");
787 c = strstr(iproduct, " ");
788 if (c)
789 memset((void*)c, '\0', 1);
791 if (iSerialNumber) {
792 ret = usb_get_string_simple(devh, iSerialNumber, iserial, DESCR_MAX);
793 if (ret < 0)
794 fprintf(stderr, "Error: could not get description string \"serial number\"\n");
795 } else
796 strcpy(iserial, "not provided");
797 c = strstr(iserial, " ");
798 if (c)
799 memset((void*)c, '\0', 1);
803 /* Print result of SCSI command INQUIRY (identification details) */
804 int deviceInquire ()
806 const unsigned char inquire_msg[] = {
807 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
808 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
809 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
812 char *command;
813 char data[36];
814 int i, ret;
816 command = malloc(31);
817 if (command == NULL) {
818 ret = 1;
819 goto out;
822 memcpy(command, inquire_msg, sizeof (inquire_msg));
824 ret = usb_claim_interface(devh, Interface);
825 if (ret != 0) {
826 SHOW_PROGRESS(" Could not claim interface (error %d). Skipping device inquiry\n", ret);
827 goto out;
829 usb_clear_halt(devh, MessageEndpoint);
831 ret = usb_bulk_write(devh, MessageEndpoint, (char *)command, 31, 0);
832 if (ret < 0) {
833 SHOW_PROGRESS(" Could not send INQUIRY message (error %d)\n", ret);
834 goto out;
837 ret = usb_bulk_read(devh, ResponseEndpoint, data, 36, 0);
838 if (ret < 0) {
839 SHOW_PROGRESS(" Could not get INQUIRY response (error %d)\n", ret);
840 goto out;
843 i = usb_bulk_read(devh, ResponseEndpoint, command, 13, 0);
845 printf("\nSCSI inquiry data (for identification)\n");
846 printf("-------------------------\n");
848 printf(" Vendor String: ");
849 for (i = 8; i < 16; i++) printf("%c",data[i]);
850 printf("\n");
852 printf(" Model String: ");
853 for (i = 16; i < 32; i++) printf("%c",data[i]);
854 printf("\n");
856 printf("Revision String: ");
857 for (i = 32; i < 36; i++) printf("%c",data[i]);
859 printf("\n-------------------------\n");
861 out:
862 if (strlen(MessageContent) == 0)
863 usb_clear_halt(devh, MessageEndpoint);
864 usb_release_interface(devh, Interface);
865 free(command);
866 return ret;
870 void resetUSB ()
872 int success;
873 int bpoint = 0;
875 if (show_progress) {
876 printf("Resetting usb device ");
877 fflush(stdout);
880 sleep( 1 );
881 do {
882 success = usb_reset(devh);
883 if ( ((bpoint % 10) == 0) && show_progress ) {
884 printf(".");
885 fflush(stdout);
887 bpoint++;
888 if (bpoint > 100)
889 success = 1;
890 } while (success < 0);
892 if ( success ) {
893 SHOW_PROGRESS("\n Reset failed. Can be ignored if device switched OK.\n");
894 } else
895 SHOW_PROGRESS("\n OK, device was reset\n");
899 int switchSendMessage ()
901 const char* cmdHead = "55534243";
902 int ret, i;
903 char* msg[3];
904 msg[0] = MessageContent;
905 msg[1] = MessageContent2;
906 msg[2] = MessageContent3;
908 /* May be activated in future versions */
909 // if (MessageContent2[0] != '\0' || MessageContent3[0] != '\0')
910 // NeedResponse = 1;
912 SHOW_PROGRESS("Setting up communication with interface %d\n", Interface);
913 if (InquireDevice != 2) {
914 ret = usb_claim_interface(devh, Interface);
915 if (ret != 0) {
916 SHOW_PROGRESS(" Could not claim interface (error %d). Skipping message sending\n", ret);
917 return 0;
920 usb_clear_halt(devh, MessageEndpoint);
921 SHOW_PROGRESS("Using endpoint 0x%02x for message sending ...\n", MessageEndpoint);
922 if (show_progress)
923 fflush(stdout);
925 for (i=0; i<3; i++) {
926 if ( strlen(msg[i]) == 0)
927 continue;
929 if ( sendMessage(msg[i], i+1) )
930 goto skip;
932 if (NeedResponse) {
933 if ( strstr(msg[i],cmdHead) != NULL ) {
934 // UFI command
935 SHOW_PROGRESS("Reading the response to message %d (CSW) ...\n", i+1);
936 ret = read_bulk(ResponseEndpoint, ByteString, 13);
937 } else {
938 // Other bulk transfer
939 SHOW_PROGRESS("Reading the response to message %d ...\n", i+1);
940 ret = read_bulk(ResponseEndpoint, ByteString, strlen(msg[i])/2 );
942 if (ret < 0)
943 goto skip;
947 SHOW_PROGRESS("Resetting response endpoint 0x%02x\n", ResponseEndpoint);
948 ret = usb_clear_halt(devh, ResponseEndpoint);
949 if (ret)
950 SHOW_PROGRESS(" Could not reset endpoint (probably harmless): %d\n", ret);
951 SHOW_PROGRESS("Resetting message endpoint 0x%02x\n", MessageEndpoint);
952 ret = usb_clear_halt(devh, MessageEndpoint);
953 if (ret)
954 SHOW_PROGRESS(" Could not reset endpoint (probably harmless): %d\n", ret);
955 usleep(200000);
956 if (ReleaseDelay) {
957 SHOW_PROGRESS("Blocking the interface for %d ms before releasing ...\n", ReleaseDelay);
958 usleep(ReleaseDelay*1000);
960 ret = usb_release_interface(devh, Interface);
961 if (ret)
962 goto skip;
963 return 1;
965 skip:
966 SHOW_PROGRESS(" Device is gone, skipping any further commands\n");
967 usb_close(devh);
968 devh = 0;
969 return 2;
972 #define SWITCH_CONFIG_MAXTRIES 5
974 int switchConfiguration ()
976 int count = SWITCH_CONFIG_MAXTRIES;
977 int ret;
979 SHOW_PROGRESS("Changing configuration to %i ...\n", Configuration);
980 while (((ret = usb_set_configuration(devh, Configuration)) < 0) && --count) {
981 SHOW_PROGRESS(" Device is busy, trying to detach kernel driver\n");
982 detachDriver();
984 if (ret == 0 ) {
985 SHOW_PROGRESS(" OK, configuration set\n");
986 return 1;
988 SHOW_PROGRESS(" Setting the configuration returned error %d. Trying to continue\n", ret);
989 return 0;
993 int switchAltSetting ()
995 int ret;
997 SHOW_PROGRESS("Changing to alt setting %i ...\n", AltSetting);
998 ret = usb_claim_interface(devh, Interface);
999 ret = libusb_set_interface_alt_setting(devh, Interface, AltSetting);
1000 usb_release_interface(devh, Interface);
1001 if (ret != 0) {
1002 SHOW_PROGRESS(" Changing to alt setting returned error %d. Trying to continue\n", ret);
1003 return 0;
1004 } else {
1005 SHOW_PROGRESS(" OK, changed to alt setting\n");
1006 return 1;
1011 void switchHuaweiMode ()
1013 int ret;
1015 SHOW_PROGRESS("Sending Huawei control message ...\n");
1016 ret = usb_control_msg(devh, USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_REQ_SET_FEATURE, 00000001, 0, buffer, 0, 1000);
1017 if (ret != 0) {
1018 fprintf(stderr, "Error: sending Huawei control message failed (error %d). Aborting.\n\n", ret);
1019 exit(1);
1020 } else
1021 SHOW_PROGRESS(" OK, Huawei control message sent\n");
1025 void switchSierraMode ()
1027 int ret;
1029 SHOW_PROGRESS("Trying to send Sierra control message\n");
1030 ret = usb_control_msg(devh, 0x40, 0x0b, 00000001, 0, buffer, 0, 1000);
1031 if (ret != 0) {
1032 fprintf(stderr, "Error: sending Sierra control message failed (error %d). Aborting.\n\n", ret);
1033 exit(1);
1034 } else
1035 SHOW_PROGRESS(" OK, Sierra control message sent\n");
1039 void switchGCTMode ()
1041 int ret;
1043 ret = usb_claim_interface(devh, Interface);
1044 if (ret != 0) {
1045 SHOW_PROGRESS(" Could not claim interface (error %d). Skipping GCT sequence \n", ret);
1046 return;
1049 SHOW_PROGRESS("Sending GCT control message 1 ...\n");
1050 ret = usb_control_msg(devh, 0xa1, 0xa0, 0, Interface, buffer, 1, 1000);
1051 SHOW_PROGRESS("Sending GCT control message 2 ...\n");
1052 ret = usb_control_msg(devh, 0xa1, 0xfe, 0, Interface, buffer, 1, 1000);
1053 SHOW_PROGRESS(" OK, GCT control messages sent\n");
1054 usb_release_interface(devh, Interface);
1058 int switchKobilMode() {
1059 int ret;
1061 SHOW_PROGRESS("Sending Kobil control message ...\n");
1062 ret = usb_control_msg(devh, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, 0x88, 0, 0, buffer, 8, 1000);
1063 if (ret != 0) {
1064 fprintf(stderr, "Error: sending Kobil control message failed (error %d). Aborting.\n\n", ret);
1065 exit(1);
1066 } else
1067 SHOW_PROGRESS(" OK, Kobil control message sent\n");
1068 return 1;
1072 int switchSonyMode ()
1074 int i, found, ret;
1075 detachDriver();
1077 if (CheckSuccess) {
1078 printf("Note: CheckSuccess pointless with Sony mode, disabling\n");
1079 CheckSuccess = 0;
1082 SHOW_PROGRESS("Trying to send Sony control message\n");
1083 ret = usb_control_msg(devh, 0xc0, 0x11, 2, 0, buffer, 3, 100);
1084 if (ret < 0) {
1085 fprintf(stderr, "Error: sending Sony control message failed (error %d). Aborting.\n\n", ret);
1086 exit(1);
1087 } else
1088 SHOW_PROGRESS(" OK, control message sent, waiting for device to return ...\n");
1090 usb_close(devh);
1091 devh = 0;
1093 /* Now waiting for the device to reappear */
1094 devnum=-1;
1095 busnum=-1;
1096 i=0;
1097 dev = 0;
1098 while ( dev == 0 && i < 30 ) {
1099 if ( i > 5 ) {
1100 dev = search_devices(&found, DefaultVendor, DefaultProduct, "\0", TargetClass, 0, SEARCH_TARGET);
1102 if ( dev != 0 )
1103 break;
1104 sleep(1);
1105 if (show_progress) {
1106 printf("#");
1107 fflush(stdout);
1109 i++;
1111 SHOW_PROGRESS("\n After %d seconds:",i);
1112 if ( dev ) {
1113 SHOW_PROGRESS(" device came back, proceeding\n");
1114 libusb_open(dev, &devh);
1115 if (devh == 0) {
1116 fprintf(stderr, "Error: could not get handle on device\n");
1117 return 0;
1119 } else {
1120 SHOW_PROGRESS(" device still gone, cancelling\n");
1121 return 0;
1123 sleep(1);
1125 SHOW_PROGRESS("Sending Sony control message again ...\n");
1126 ret = usb_control_msg(devh, 0xc0, 0x11, 2, 0, buffer, 3, 100);
1127 if (ret < 0) {
1128 fprintf(stderr, "Error: sending Sony control message (2) failed (error %d)\n", ret);
1129 return 0;
1131 SHOW_PROGRESS(" OK, control message sent\n");
1132 return 1;
1136 #define EP_OUT 0x02
1137 #define EP_IN 0x81
1138 #define SIZE 0x08
1140 #define MOBILE_ACTION_READLOOP1 63
1141 #define MOBILE_ACTION_READLOOP2 73
1143 int switchActionMode ()
1145 int i;
1146 SHOW_PROGRESS("Sending MobileAction control sequence ...\n");
1147 memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
1148 usb_control_msg(devh, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x0300, 0, buffer, SIZE, 1000);
1149 memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
1150 usb_control_msg(devh, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x0300, 0, buffer, SIZE, 1000);
1151 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1152 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1153 memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
1154 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1155 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1156 memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
1157 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1158 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1159 memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
1160 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1161 for (i=0; i < MOBILE_ACTION_READLOOP1; i++) {
1162 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1164 memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
1165 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1166 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1167 memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
1168 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1169 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1170 memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
1171 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1172 for (i=0; i < MOBILE_ACTION_READLOOP2; i++) {
1173 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1175 memcpy(buffer, "\x33\x04\xfe\x00\xf4\x6c\x1f\xf0", SIZE);
1176 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1177 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1178 memcpy(buffer, "\x32\x07\xfe\xf0\x29\xb9\x3a\xf0", SIZE);
1179 ret = usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1180 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1181 if (ret < 0) {
1182 SHOW_PROGRESS(" MobileAction control sequence did not complete\n Last error was %d\n",ret);
1183 return 1;
1184 } else {
1185 SHOW_PROGRESS(" MobileAction control sequence complete\n");
1186 return 0;
1191 #define SQN_SET_DEVICE_MODE_REQUEST 0x0b
1192 #define SQN_GET_DEVICE_MODE_REQUEST 0x0a
1194 #define SQN_DEFAULT_DEVICE_MODE 0x00
1195 #define SQN_MASS_STORAGE_MODE 0x01
1196 #define SQN_CUSTOM_DEVICE_MODE 0x02
1198 int switchSequansMode() {
1199 int ret;
1201 SHOW_PROGRESS("Sending Sequans vendor request\n");
1202 ret = usb_control_msg(devh, USB_TYPE_VENDOR | USB_RECIP_DEVICE, SQN_SET_DEVICE_MODE_REQUEST, SQN_CUSTOM_DEVICE_MODE, 0, buffer, 0, 1000);
1203 if (ret != 0) {
1204 fprintf(stderr, "Error: sending Sequans request failed (error %d). Aborting.\n\n", ret);
1205 exit(1);
1206 } else
1207 SHOW_PROGRESS(" OK, Sequans request was sent\n");
1209 return 1;
1212 int switchCiscoMode() {
1213 int ret, i;
1214 char* msg[11];
1216 SHOW_PROGRESS("Preparing for sending Cisco message sequence\n");
1218 msg[0] = "55534243f83bcd810002000080000afd000000030000000100000000000000";
1219 msg[1] = "55534243984300820002000080000afd000000070000000100000000000000";
1220 msg[2] = "55534243984300820000000000000afd000100071000000000000000000000";
1221 msg[3] = "55534243984300820002000080000afd000200230000000100000000000000";
1222 msg[4] = "55534243984300820000000000000afd000300238200000000000000000000";
1223 msg[5] = "55534243984300820002000080000afd000200260000000100000000000000";
1224 msg[6] = "55534243984300820000000000000afd00030026c800000000000000000000";
1225 msg[7] = "55534243d84c04820002000080000afd000010730000000100000000000000";
1226 msg[8] = "55534243d84c04820002000080000afd000200240000000100000000000000";
1227 msg[9] = "55534243d84c04820000000000000afd000300241300000000000000000000";
1228 msg[10] = "55534243d84c04820000000000000afd000110732400000000000000000000";
1230 SHOW_PROGRESS("Setting up communication with interface %d\n", Interface);
1231 ret = usb_claim_interface(devh, Interface);
1232 if (ret != 0) {
1233 SHOW_PROGRESS(" Could not claim interface (error %d). Skipping message sending\n", ret);
1234 return 0;
1236 // usb_clear_halt(devh, MessageEndpoint);
1237 if (show_progress)
1238 fflush(stdout);
1240 for (i=0; i<11; i++) {
1241 if ( sendMessage(msg[i], i+1) )
1242 goto skip;
1244 SHOW_PROGRESS("Reading the response (CSW) to bulk message %d ...\n",i+1);
1245 ret = read_bulk(ResponseEndpoint, ByteString, 13);
1246 if (ret < 0)
1247 goto skip;
1250 if (ReleaseDelay) {
1251 SHOW_PROGRESS("Blocking the interface for %d ms before releasing ...\n", ReleaseDelay);
1252 usleep(ReleaseDelay*1000);
1254 ret = usb_release_interface(devh, Interface);
1255 if (ret)
1256 goto skip;
1257 return 1;
1259 skip:
1260 SHOW_PROGRESS("Device returned error, skipping any further commands\n");
1261 usb_close(devh);
1262 devh = 0;
1263 return 2;
1266 /* Detach driver
1268 int detachDriver()
1270 int ret;
1272 #ifndef LIBUSB_HAS_GET_DRIVER_NP
1273 printf(" Cant't do driver detection and detaching on this platform.\n");
1274 return 2;
1275 #else
1277 SHOW_PROGRESS("Looking for active driver ...\n");
1278 ret = usb_get_driver_np(devh, Interface, buffer, BUF_SIZE);
1279 if (ret != 0) {
1280 SHOW_PROGRESS(" No driver found. Either detached before or never attached\n");
1281 return 1;
1283 SHOW_PROGRESS(" OK, driver found (\"%s\")\n", buffer);
1284 if (DetachStorageOnly && strcmp(buffer,"usb-storage")) {
1285 SHOW_PROGRESS(" Warning: driver is not usb-storage\n");
1287 #endif
1289 #ifndef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
1290 SHOW_PROGRESS(" Can't do driver detaching on this platform\n");
1291 return 2;
1292 #else
1294 ret = usb_detach_kernel_driver_np(devh, Interface);
1295 if (ret == 0) {
1296 SHOW_PROGRESS(" OK, driver \"%s\" detached\n", buffer);
1297 } else
1298 SHOW_PROGRESS(" Driver \"%s\" detach failed with error %d. Trying to continue\n", buffer, ret);
1299 return 1;
1300 #endif
1304 int sendMessage(char* message, int count)
1306 int message_length, ret;
1308 if (strlen(message) % 2 != 0) {
1309 fprintf(stderr, "Error: MessageContent %d hex string has uneven length. Skipping ...\n", count);
1310 return 1;
1312 message_length = strlen(message) / 2;
1313 if ( hexstr2bin(message, ByteString, message_length) == -1) {
1314 fprintf(stderr, "Error: MessageContent %d %s\n is not a hex string. Skipping ...\n", count, MessageContent);
1315 return 1;
1317 SHOW_PROGRESS("Trying to send message %d to endpoint 0x%02x ...\n", count, MessageEndpoint);
1318 fflush(stdout);
1319 ret = write_bulk(MessageEndpoint, ByteString, message_length);
1320 if (ret == -19)
1321 return 1;
1323 return 0;
1327 int checkSuccess()
1329 int i=0, ret;
1330 int newTargetCount, success=0;
1332 SHOW_PROGRESS("\nChecking for mode switch (max. %d times, once per second) ...\n", CheckSuccess);
1333 sleep(1);
1335 /* If target parameters are given, don't check for vanished device
1336 * Changed for Cisco AM10 where a new device is added while the install
1337 * storage device stays active
1339 if ((TargetVendor || TargetClass) && devh) {
1340 usb_close(devh);
1341 devh = 0;
1344 /* if target ID is not given but target class is, assign default as target;
1345 * it will be needed for sysmode output
1347 if (!TargetVendor && TargetClass) {
1348 TargetVendor = DefaultVendor;
1349 TargetProduct = DefaultProduct;
1352 /* devh is 0 if device vanished during command transmission or if target params were given
1354 if (devh)
1355 for (i=0; i < CheckSuccess; i++) {
1357 /* Test if default device still can be accessed; positive result does
1358 * not necessarily mean failure
1360 SHOW_PROGRESS(" Waiting for original device to vanish ...\n");
1362 ret = usb_claim_interface(devh, Interface);
1363 usb_release_interface(devh, Interface);
1364 if (ret < 0) {
1365 SHOW_PROGRESS(" Original device can't be accessed anymore. Good.\n");
1366 usb_close(devh);
1367 devh = 0;
1368 break;
1370 if (i == CheckSuccess-1) {
1371 SHOW_PROGRESS(" Original device still present after the timeout\n\nMode switch most likely failed. Bye.\n\n");
1372 } else
1373 sleep(1);
1376 if ( TargetVendor && (TargetProduct > -1 || TargetProductList[0] != '\0') ) {
1378 /* Recount target devices (compare with previous count) if target data is given.
1379 * Target device on the same bus with higher device number is returned,
1380 * description is read for syslog message
1382 for (i=i; i < CheckSuccess; i++) {
1383 SHOW_PROGRESS(" Searching for target devices ...\n");
1384 dev = search_devices(&newTargetCount, TargetVendor, TargetProduct, TargetProductList, TargetClass, 0, SEARCH_TARGET);
1385 if (dev && (newTargetCount > targetDeviceCount)) {
1386 printf("\nFound target device, now opening\n");
1387 libusb_open(dev, &devh);
1388 deviceDescription();
1389 usb_close(devh);
1390 devh = 0;
1391 if (verbose) {
1392 printf("\nFound target device %03d on bus %03d\n", \
1393 libusb_get_device_address(dev), libusb_get_bus_number(dev));
1394 printf("\nTarget device description data\n");
1395 printf("-------------------------\n");
1396 printf("Manufacturer: %s\n", imanufact);
1397 printf(" Product: %s\n", iproduct);
1398 printf(" Serial No.: %s\n", iserial);
1399 printf("-------------------------\n");
1401 SHOW_PROGRESS(" Found correct target device\n\nMode switch succeeded. Bye.\n\n");
1402 success = 2;
1403 break;
1405 if (i == CheckSuccess-1) {
1406 SHOW_PROGRESS(" No new devices in target mode or class found\n\nMode switch has failed. Bye.\n\n");
1407 } else
1408 sleep(1);
1410 } else
1411 /* No target data given, rely on the vanished device */
1412 if (!devh) {
1413 SHOW_PROGRESS(" (For a better success check provide target IDs or class)\n");
1414 SHOW_PROGRESS(" Original device vanished after switching\n\nMode switch most likely succeeded. Bye.\n\n");
1415 success = 1;
1418 switch (success) {
1419 case 3:
1420 if (sysmode)
1421 syslog(LOG_NOTICE, "switched to new device, but hit libusb1 bug");
1422 TargetProduct = -1;
1423 success = 1;
1424 break;
1425 case 2:
1426 if (sysmode)
1427 syslog(LOG_NOTICE, "switched to %04x:%04x (%s: %s)", TargetVendor, TargetProduct, imanufact, iproduct);
1428 success = 1;
1429 break;
1430 case 1:
1431 if (sysmode)
1432 syslog(LOG_NOTICE, "device seems to have switched");
1433 default:
1436 if (sysmode)
1437 closelog();
1439 return success;
1444 int write_bulk(int endpoint, char *message, int length)
1446 int ret;
1447 ret = usb_bulk_write(devh, endpoint, message, length, 3000);
1448 if (ret >= 0 ) {
1449 SHOW_PROGRESS(" OK, message successfully sent\n");
1450 } else
1451 if (ret == -19) {
1452 SHOW_PROGRESS(" Device seems to have vanished right after sending. Good.\n");
1453 } else
1454 SHOW_PROGRESS(" Sending the message returned error %d. Trying to continue\n", ret);
1455 return ret;
1459 int read_bulk(int endpoint, char *buffer, int length)
1461 int ret;
1462 ret = usb_bulk_read(devh, endpoint, buffer, length, 3000);
1463 usb_bulk_read(devh, endpoint, buffer, 13, 100);
1464 if (ret >= 0 ) {
1465 SHOW_PROGRESS(" OK, response successfully read (%d bytes).\n", ret);
1466 } else
1467 if (ret == -19) {
1468 SHOW_PROGRESS(" Device seems to have vanished after reading. Good.\n");
1469 } else
1470 SHOW_PROGRESS(" Response reading got error %d\n", ret);
1471 return ret;
1475 void release_usb_device(int dummy) {
1476 SHOW_PROGRESS("Program cancelled by system. Bye.\n\n");
1477 if (devh) {
1478 usb_release_interface(devh, Interface);
1479 usb_close(devh);
1481 if (sysmode)
1482 closelog();
1483 exit(0);
1488 /* Iterates over busses and devices, counts the ones with the given
1489 * ID/class and returns the last one of them
1491 struct libusb_device* search_devices( int *numFound, int vendor, int product, char* productList, int targetClass, int configuration, int mode)
1493 char *listcopy=NULL, *token, buffer[2];
1494 int devClass;
1495 struct libusb_device* right_dev = NULL;
1496 struct libusb_device_handle *testdevh;
1498 /* only target class given, target vendor and product assumed unchanged */
1499 if ( targetClass && !(vendor || product) ) {
1500 vendor = DefaultVendor;
1501 product = DefaultProduct;
1503 *numFound = 0;
1505 /* Sanity check */
1506 if (!vendor || (!product && productList == '\0') )
1507 return NULL;
1509 if (productList != '\0')
1510 listcopy = malloc(strlen(productList)+1);
1512 struct libusb_device **devs;
1513 int i=0;
1515 if (libusb_get_device_list(ctx, &devs) < 0) {
1516 perror ("failed to access USB");
1517 return 0;
1520 while ((dev = devs[i++]) != NULL) {
1521 struct libusb_device_descriptor descriptor;
1522 libusb_get_device_descriptor(dev, &descriptor);
1523 int idVendor = descriptor.idVendor;
1524 int idProduct = descriptor.idProduct;
1526 if (verbose)
1527 printf (" searching devices, found USB ID %04x:%04x\n", idVendor, idProduct);
1528 if (idVendor != vendor)
1529 continue;
1530 if (verbose)
1531 printf (" found matching vendor ID\n");
1532 // product list given
1533 if ( strlen(productList) ) {
1534 strcpy(listcopy, productList);
1535 token = strtok(listcopy, ",");
1536 while (token != NULL) {
1537 if (strlen(token) != 4) {
1538 SHOW_PROGRESS("Error: entry in product ID list has wrong length: %s. Ignoring\n", token);
1539 goto NextToken;
1541 if ( hexstr2bin(token, buffer, strlen(token)/2) == -1) {
1542 SHOW_PROGRESS("Error: entry in product ID list is not a hex string: %s. Ignoring\n", token);
1543 goto NextToken;
1545 product = 0;
1546 product += (unsigned char)buffer[0];
1547 product <<= 8;
1548 product += (unsigned char)buffer[1];
1549 if (product == idProduct) {
1550 if (verbose)
1551 printf (" found matching product ID from list\n");
1552 (*numFound)++;
1553 if (busnum == -1)
1554 right_dev = dev;
1555 else
1556 if (libusb_get_device_address(dev) >= devnum && libusb_get_bus_number(dev) == busnum) {
1557 right_dev = dev;
1558 TargetProduct = idProduct;
1559 break;
1563 NextToken:
1564 token = strtok(NULL, ",");
1566 /* Product ID is given */
1567 } else
1568 if (product == idProduct) {
1569 if (verbose)
1570 printf (" found matching product ID\n");
1571 if (targetClass == 0 && configuration < 1) {
1572 (*numFound)++;
1573 right_dev = dev;
1574 if (verbose)
1575 printf (" adding device\n");
1576 } else {
1577 if (targetClass != 0) {
1578 struct libusb_device_descriptor descriptor;
1579 libusb_get_device_descriptor(dev, &descriptor);
1580 devClass = descriptor.bDeviceClass;
1581 struct libusb_config_descriptor *config;
1582 libusb_get_config_descriptor(dev, 0, &config);
1583 int ifaceClass = config->interface[0].altsetting[0].bInterfaceClass;
1584 libusb_free_config_descriptor(config);
1586 if (devClass == 0)
1587 devClass = ifaceClass;
1588 else
1589 /* Check for some quirky devices */
1590 if (devClass != ifaceClass)
1591 devClass = ifaceClass;
1592 if (devClass == targetClass) {
1593 if (verbose)
1594 printf (" target class %02x matching\n", targetClass);
1595 if (mode == SEARCH_TARGET) {
1596 (*numFound)++;
1597 right_dev = dev;
1598 if (verbose)
1599 printf (" adding device\n");
1600 } else
1601 if (verbose)
1602 printf (" not adding device\n");
1603 } else {
1604 if (verbose)
1605 printf (" target class %02x not matching\n", targetClass);
1606 if (mode == SEARCH_DEFAULT) {
1607 (*numFound)++;
1608 right_dev = dev;
1609 if (verbose)
1610 printf (" adding device\n");
1613 } else {
1614 // check configuration (only if no target class given)
1615 libusb_open(dev, &testdevh);
1616 int testconfig = get_current_configuration(testdevh);
1617 if (testconfig != configuration) {
1618 if (verbose)
1619 printf (" device configuration %d not matching parameter\n", testconfig);
1620 (*numFound)++;
1621 right_dev = dev;
1622 if (verbose)
1623 printf (" adding device\n");
1624 } else
1625 if (verbose)
1626 printf (" not adding device, target configuration already set\n");
1629 /* hack: if busnum has other than init value, we are called from
1630 * successCheck() and do probe for plausible new devnum/busnum
1632 if (busnum != -1)
1633 if (libusb_get_device_address(dev) < devnum || libusb_get_bus_number(dev) != busnum) {
1634 if (verbose)
1635 printf (" warning: busnum/devnum indicates an unrelated device\n");
1636 //right_dev = NULL;
1640 if (productList != NULL)
1641 free(listcopy);
1642 return right_dev;
1646 #define USB_DIR_OUT 0x00
1647 #define USB_DIR_IN 0x80
1649 /* Autodetect bulk endpoints (ab) */
1651 int find_first_bulk_output_endpoint(struct libusb_device *dev)
1653 int i;
1654 struct libusb_config_descriptor *config;
1655 libusb_get_config_descriptor(dev, 0, &config);
1656 const struct libusb_interface_descriptor *alt = &(config[0].interface[0].altsetting[0]);
1657 const struct libusb_endpoint_descriptor *ep;
1659 for(i=0;i < alt->bNumEndpoints;i++) {
1660 ep=&(alt->endpoint[i]);
1661 if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
1662 ( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT ) ) {
1663 return ep->bEndpointAddress;
1666 libusb_free_config_descriptor(config);
1668 return 0;
1672 int find_first_bulk_input_endpoint(struct libusb_device *dev)
1674 int i;
1675 struct libusb_config_descriptor *config;
1676 libusb_get_config_descriptor(dev, 0, &config);
1677 const struct libusb_interface_descriptor *alt = &(config[0].interface[0].altsetting[0]);
1678 const struct libusb_endpoint_descriptor *ep;
1679 for(i=0;i < alt->bNumEndpoints;i++) {
1680 ep=&(alt->endpoint[i]);
1681 if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
1682 ( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN ) ) {
1683 return ep->bEndpointAddress;
1686 libusb_free_config_descriptor(config);
1688 return 0;
1691 int get_current_configuration(struct libusb_device_handle* devh)
1693 int ret;
1695 SHOW_PROGRESS("Getting the current device configuration ...\n");
1696 ret = usb_control_msg(devh, USB_DIR_IN + USB_TYPE_STANDARD + USB_RECIP_DEVICE, USB_REQ_GET_CONFIGURATION, 0, 0, buffer, 1, 1000);
1697 if (ret < 0) {
1698 // There are quirky devices which fail to respond properly to this command
1699 fprintf(stderr, "Error getting the current configuration (error %d). Assuming configuration 1.\n", ret);
1700 if (Configuration) {
1701 fprintf(stderr, " No configuration setting possible for this device.\n");
1702 Configuration = 0;
1704 return 1;
1705 } else {
1706 SHOW_PROGRESS(" OK, got current device configuration (%d)\n", buffer[0]);
1707 return buffer[0];
1712 /* Parameter parsing */
1714 char* ReadParseParam(const char* FileName, char *VariableName)
1716 static char Str[LINE_DIM];
1717 char *VarName, *Comment=NULL, *Equal=NULL;
1718 char *FirstQuote, *LastQuote, *P1, *P2;
1719 int Line=0, Len=0, Pos=0;
1720 FILE *file=fopen(FileName, "r");
1722 if (file==NULL) {
1723 fprintf(stderr, "Error: Could not find file %s\n\n", FileName);
1724 exit(1);
1727 while (fgets(Str, LINE_DIM-1, file) != NULL) {
1728 Line++;
1729 Len=strlen(Str);
1730 if (Len==0) goto Next;
1731 if (Str[Len-1]=='\n' or Str[Len-1]=='\r') Str[--Len]='\0';
1732 Equal = strchr (Str, '='); // search for equal sign
1733 Pos = strcspn (Str, ";#!"); // search for comment
1734 Comment = (Pos==Len) ? NULL : Str+Pos;
1735 if (Equal==NULL or ( Comment!=NULL and Comment<=Equal)) goto Next; // Only comment
1736 *Equal++ = '\0';
1737 if (Comment!=NULL) *Comment='\0';
1739 // String
1740 FirstQuote=strchr (Equal, '"'); // search for double quote char
1741 LastQuote=strrchr (Equal, '"');
1742 if (FirstQuote!=NULL) {
1743 if (LastQuote==NULL) {
1744 fprintf(stderr, "Error reading parameter file %s line %d - Missing end quote.\n", FileName, Line);
1745 goto Next;
1747 *FirstQuote=*LastQuote='\0';
1748 Equal=FirstQuote+1;
1751 // removes leading/trailing spaces
1752 Pos=strspn (Str, " \t");
1753 if (Pos==strlen(Str)) {
1754 fprintf(stderr, "Error reading parameter file %s line %d - Missing variable name.\n", FileName, Line);
1755 goto Next; // No function name
1757 while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '\t'))!=NULL)
1758 if (P1!=NULL) *P1='\0';
1759 else if (P2!=NULL) *P2='\0';
1760 VarName=Str+Pos;
1762 Pos=strspn (Equal, " \t");
1763 if (Pos==strlen(Equal)) {
1764 fprintf(stderr, "Error reading parameter file %s line %d - Missing value.\n", FileName, Line);
1765 goto Next; // No function name
1767 Equal+=Pos;
1769 if (strcmp(VarName, VariableName)==0) { // Found it
1770 fclose(file);
1771 return Equal;
1773 Next:;
1776 fclose(file);
1777 return NULL;
1781 int hex2num(char c)
1783 if (c >= '0' && c <= '9')
1784 return c - '0';
1785 if (c >= 'a' && c <= 'f')
1786 return c - 'a' + 10;
1787 if (c >= 'A' && c <= 'F')
1788 return c - 'A' + 10;
1789 return -1;
1793 int hex2byte(const char *hex)
1795 int a, b;
1796 a = hex2num(*hex++);
1797 if (a < 0)
1798 return -1;
1799 b = hex2num(*hex++);
1800 if (b < 0)
1801 return -1;
1802 return (a << 4) | b;
1805 int hexstr2bin(const char *hex, char *buffer, int len)
1807 int i;
1808 int a;
1809 const char *ipos = hex;
1810 char *opos = buffer;
1812 for (i = 0; i < len; i++) {
1813 a = hex2byte(ipos);
1814 if (a < 0)
1815 return -1;
1816 *opos++ = a;
1817 ipos += 2;
1819 return 0;
1822 void printVersion()
1824 char* version = VERSION;
1825 printf("\n * usb_modeswitch: handle USB devices with multiple modes\n");
1826 printf(" * Version %s (C) Josua Dietze 2011\n", version);
1827 printf(" * Based on libusb0 (0.1.12 and above)\n\n");
1828 printf(" ! PLEASE REPORT NEW CONFIGURATIONS !\n\n");
1831 void printHelp()
1833 printf ("\nUsage: usb_modeswitch [-hvpVPmMrndHSOGATRIQWDiua] [-c filename]\n\n");
1834 printf (" -h, --help this help\n");
1835 printf (" -e, --version print version information and exit\n");
1836 printf (" -v, --default-vendor NUM vendor ID of original mode (mandatory)\n");
1837 printf (" -p, --default-product NUM product ID of original mode (mandatory)\n");
1838 printf (" -V, --target-vendor NUM target mode vendor ID (optional)\n");
1839 printf (" -P, --target-product NUM target mode product ID (optional)\n");
1840 printf (" -C, --target-class NUM target mode device class (optional)\n");
1841 printf (" -m, --message-endpoint NUM direct the message transfer there (optional)\n");
1842 printf (" -M, --message-content <msg> message to send (hex number as string)\n");
1843 printf (" -2 <msg>, -3 <msg> additional messages to send (-n recommended)\n");
1844 printf (" -n, --need-response read response to the message transfer (CSW)\n");
1845 printf (" -r, --response-endpoint NUM read response from there (optional)\n");
1846 printf (" -d, --detach-only detach the active driver, no further action\n");
1847 printf (" -H, --huawei-mode apply a special procedure\n");
1848 printf (" -S, --sierra-mode apply a special procedure\n");
1849 printf (" -O, --sony-mode apply a special procedure\n");
1850 printf (" -G, --gct-mode apply a special procedure\n");
1851 printf (" -N, --sequans-mode apply a special procedure\n");
1852 printf (" -A, --mobileaction-mode apply a special procedure\n");
1853 printf (" -T, --kobil-mode apply a special procedure\n");
1854 printf (" -L, --cisco-mode apply a special procedure\n");
1855 printf (" -R, --reset-usb reset the device after all other actions\n");
1856 printf (" -Q, --quiet don't show progress or error messages\n");
1857 printf (" -W, --verbose print all settings and debug output\n");
1858 printf (" -D, --sysmode specific result and syslog message\n");
1859 printf (" -s, --success <seconds> switching result check with timeout\n");
1860 printf (" -I, --no-inquire do not get SCSI attributes (default on)\n\n");
1861 printf (" -c, --config-file <filename> load configuration from file\n\n");
1862 printf (" -i, --interface NUM select initial USB interface (default 0)\n");
1863 printf (" -u, --configuration NUM select USB configuration\n");
1864 printf (" -a, --altsetting NUM select alternative USB interface setting\n\n");