usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / usbmodeswitch / usb_modeswitch.c
blob53b3fdff1ce9af3045cab53bc535643c998c1b7b
1 /*
2 Mode switching tool for controlling flip flop (multiple device) USB gear
3 Version 1.2.6, 2013/06/02
5 Copyright (C) 2007 - 2013 Josua Dietze (mail to "usb_admin" at the domain
6 of the home page; or write a personal message through the forum to "Josh".
7 NO SUPPORT VIA E-MAIL - please use the forum for that)
9 Major contributions:
11 Command line parsing, decent usage/config output/handling, bugfixes and advanced
12 options added by:
13 Joakim Wennergren
15 TargetClass parameter implementation to support new Option devices/firmware:
16 Paul Hardwick (http://www.pharscape.org)
18 Created with initial help from:
19 "usbsnoop2libusb.pl" by Timo Lindfors (http://iki.fi/lindi/usb/usbsnoop2libusb.pl)
21 Config file parsing stuff borrowed from:
22 Guillaume Dargaud (http://www.gdargaud.net/Hack/SourceCode.html)
24 Hexstr2bin function borrowed from:
25 Jouni Malinen (http://hostap.epitest.fi/wpa_supplicant, from "common.c")
27 Other contributions: see README
29 Device information contributors are named in the "device_reference.txt" file. See
30 homepage.
32 This program is free software; you can redistribute it and/or modify
33 it under the terms of the GNU General Public License as published by
34 the Free Software Foundation; either version 2 of the License, or
35 (at your option) any later version.
37 This program is distributed in the hope that it will be useful,
38 but WITHOUT ANY WARRANTY; without even the implied warranty of
39 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 GNU General Public License for more details:
42 http://www.gnu.org/licenses/gpl.txt
46 /* Recommended tab size: 4 */
48 #define VERSION "1.2.5"
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <signal.h>
54 #include <ctype.h>
55 #include <getopt.h>
56 #include <syslog.h>
57 #include <unistd.h>
59 #include "usb_modeswitch.h"
61 #define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
62 #define LIBUSB_HAS_GET_DRIVER_NP
64 #define USB_ENDPOINT_IN LIBUSB_ENDPOINT_IN
65 #define USB_ENDPOINT_OUT LIBUSB_ENDPOINT_OUT
66 #define USB_ENDPOINT_TYPE_MASK LIBUSB_ENDPOINT_ADDRESS_MASK
67 #define USB_ENDPOINT_DIR_MASK LIBUSB_ENDPOINT_DIR_MASK
68 #define USB_ENDPOINT_TYPE_BULK LIBUSB_TRANSFER_TYPE_BULK
69 #define USB_TYPE_STANDARD LIBUSB_REQUEST_TYPE_STANDARD
70 #define USB_TYPE_CLASS LIBUSB_REQUEST_TYPE_CLASS
71 #define USB_TYPE_VENDOR LIBUSB_REQUEST_TYPE_VENDOR
72 #define USB_RECIP_DEVICE LIBUSB_RECIPIENT_DEVICE
73 #define USB_RECIP_INTERFACE LIBUSB_RECIPIENT_INTERFACE
74 #define USB_REQ_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE
75 #define USB_REQ_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION
77 #define usb_set_debug(x) libusb_set_debug(ctx, 3)
78 #define usb_close libusb_close
79 #define usb_get_string_simple libusb_get_string_descriptor_ascii
80 #define usb_reset libusb_reset_device
81 #define usb_claim_interface libusb_claim_interface
82 #define usb_clear_halt libusb_clear_halt
83 #define usb_release_interface libusb_release_interface
84 #define usb_control_msg libusb_control_transfer
85 #define usb_set_configuration libusb_set_configuration
86 #define usb_detach_kernel_driver_np libusb_detach_kernel_driver
88 /* libusb 1.0 wrappers */
89 int usb_bulk_io(struct libusb_device_handle *handle, int ep, char *bytes,
90 int size, int timeout)
92 int actual_length;
93 int r;
94 // usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
95 r = libusb_bulk_transfer(handle, ep & 0xff, bytes, size,
96 &actual_length, timeout);
98 /* if we timed out but did transfer some data, report as successful short
99 * read. FIXME: is this how libusb-0.1 works? */
100 if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
101 return actual_length;
103 return r;
106 int usb_bulk_read(struct libusb_device_handle *handle, int ep, char *bytes,
107 int size, int timeout)
109 if (!(ep & LIBUSB_ENDPOINT_IN)) {
110 /* libusb-0.1 will strangely fix up a read request from endpoint
111 * 0x01 to be from endpoint 0x81. do the same thing here, but
112 * warn about this silly behaviour. */
113 printf("endpoint %x is missing IN direction bit, fixing", ep);
114 ep |= LIBUSB_ENDPOINT_IN;
117 return usb_bulk_io(handle, ep, bytes, size, timeout);
120 int usb_bulk_write(struct libusb_device_handle *handle, int ep, char *bytes,
121 int size, int timeout)
123 if (ep & LIBUSB_ENDPOINT_IN) {
124 /* libusb-0.1 on BSD strangely fix up a write request to endpoint
125 * 0x81 to be to endpoint 0x01. do the same thing here, but
126 * warn about this silly behaviour. */
127 printf("endpoint %x has excessive IN direction bit, fixing", ep);
128 ep &= ~LIBUSB_ENDPOINT_IN;
131 return usb_bulk_io(handle, ep, bytes, size, timeout);
134 static int usb_interrupt_io(libusb_device_handle *handle, int ep, char *bytes,
135 int size, int timeout)
137 int actual_length;
138 int r;
139 // usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
140 r = libusb_interrupt_transfer(handle, ep & 0xff, bytes, size,
141 &actual_length, timeout);
143 /* if we timed out but did transfer some data, report as successful short
144 * read. FIXME: is this how libusb-0.1 works? */
145 if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
146 return actual_length;
148 return (r);
151 int usb_interrupt_read(libusb_device_handle *handle, int ep, char *bytes,
152 int size, int timeout)
154 if (!(ep & USB_ENDPOINT_IN)) {
155 /* libusb-0.1 will strangely fix up a read request from endpoint
156 * 0x01 to be from endpoint 0x81. do the same thing here, but
157 * warn about this silly behaviour. */
158 printf("endpoint %x is missing IN direction bit, fixing", ep);
159 ep |= USB_ENDPOINT_IN;
161 return usb_interrupt_io(handle, ep, bytes, size, timeout);
164 int usb_interrupt_write(libusb_device_handle *handle, int ep, char *bytes,
165 int size, int timeout)
167 if (ep & USB_ENDPOINT_IN) {
168 /* libusb-0.1 on BSD strangely fix up a write request to endpoint
169 * 0x81 to be to endpoint 0x01. do the same thing here, but
170 * warn about this silly behaviour. */
171 printf("endpoint %x has excessive IN direction bit, fixing", ep);
172 ep &= ~USB_ENDPOINT_IN;
175 return usb_interrupt_io(handle, ep, bytes, size, timeout);
178 int usb_get_driver_np(struct libusb_device_handle *dev, int interface,
179 char *name, unsigned int namelen)
181 int r = libusb_kernel_driver_active(dev, interface);
182 if (r == 1) {
183 /* libusb-1.0 doesn't expose driver name, so fill in a dummy value */
184 snprintf(name, namelen, "dummy");
185 return 0;
186 } else return r;
189 #define LINE_DIM 1024
190 #define MAXLINES 50
191 #define BUF_SIZE 4096
192 #define DESCR_MAX 129
194 #define SEARCH_DEFAULT 0
195 #define SEARCH_TARGET 1
196 #define SEARCH_BUSDEV 2
198 #define SWITCH_CONFIG_MAXTRIES 5
200 #define SHOW_PROGRESS if (show_progress) fprintf
202 char *TempPP=NULL;
204 static struct libusb_context *ctx = NULL;
205 static struct libusb_device *dev;
206 static struct libusb_device_handle *devh;
208 int DefaultVendor=0, DefaultProduct=0, TargetVendor=0, TargetProduct=-1, TargetClass=0;
209 int MessageEndpoint=0, ResponseEndpoint=0, ReleaseDelay=0;
210 int targetDeviceCount=0, searchMode;
211 int devnum=-1, busnum=-1;
212 int ret;
214 char DetachStorageOnly=0, HuaweiMode=0, SierraMode=0, SonyMode=0, GCTMode=0, KobilMode=0;
215 char SequansMode=0, MobileActionMode=0, CiscoMode=0, QisdaMode=0, QuantaMode=0;
216 char verbose=0, show_progress=1, ResetUSB=0, CheckSuccess=0, config_read=0;
217 char NeedResponse=0, NoDriverLoading=0, InquireDevice=1, sysmode=0, mbim=0;
219 char imanufact[DESCR_MAX], iproduct[DESCR_MAX], iserial[DESCR_MAX];
221 char MessageContent[LINE_DIM];
222 char MessageContent2[LINE_DIM];
223 char MessageContent3[LINE_DIM];
224 char TargetProductList[LINE_DIM];
225 char ByteString[LINE_DIM/2];
226 char buffer[BUF_SIZE];
228 FILE *output;
231 /* Settable Interface and Configuration (for debugging mostly) (jmw) */
232 int Interface = -1, Configuration = 0, AltSetting = -1;
235 static struct option long_options[] = {
236 {"help", no_argument, 0, 'h'},
237 {"version", no_argument, 0, 'e'},
238 {"default-vendor", required_argument, 0, 'v'},
239 {"default-product", required_argument, 0, 'p'},
240 {"target-vendor", required_argument, 0, 'V'},
241 {"target-product", required_argument, 0, 'P'},
242 {"target-class", required_argument, 0, 'C'},
243 {"message-endpoint", required_argument, 0, 'm'},
244 {"message-content", required_argument, 0, 'M'},
245 {"message-content2", required_argument, 0, '2'},
246 {"message-content3", required_argument, 0, '3'},
247 {"release-delay", required_argument, 0, 'w'},
248 {"response-endpoint", required_argument, 0, 'r'},
249 {"bus-num", required_argument, 0, 'b'},
250 {"device-num", required_argument, 0, 'g'},
251 {"detach-only", no_argument, 0, 'd'},
252 {"huawei-mode", no_argument, 0, 'H'},
253 {"sierra-mode", no_argument, 0, 'S'},
254 {"sony-mode", no_argument, 0, 'O'},
255 {"qisda-mode", no_argument, 0, 'B'},
256 {"quanta-mode", no_argument, 0, 'E'},
257 {"kobil-mode", no_argument, 0, 'T'},
258 {"gct-mode", no_argument, 0, 'G'},
259 {"sequans-mode", no_argument, 0, 'N'},
260 {"mobileaction-mode", no_argument, 0, 'A'},
261 {"cisco-mode", no_argument, 0, 'L'},
262 {"need-response", no_argument, 0, 'n'},
263 {"reset-usb", no_argument, 0, 'R'},
264 {"config-file", required_argument, 0, 'c'},
265 {"verbose", no_argument, 0, 'W'},
266 {"quiet", no_argument, 0, 'Q'},
267 {"sysmode", no_argument, 0, 'D'},
268 {"no-inquire", no_argument, 0, 'I'},
269 {"stdinput", no_argument, 0, 't'},
270 {"find-mbim", no_argument, 0, 'j'},
271 {"long-config", required_argument, 0, 'f'},
272 {"check-success", required_argument, 0, 's'},
273 {"interface", required_argument, 0, 'i'},
274 {"configuration", required_argument, 0, 'u'},
275 {"altsetting", required_argument, 0, 'a'},
276 {0, 0, 0, 0}
280 void readConfigFile(const char *configFilename)
282 ParseParamHex(configFilename, TargetVendor);
283 ParseParamHex(configFilename, TargetProduct);
284 ParseParamString(configFilename, TargetProductList);
285 ParseParamHex(configFilename, TargetClass);
286 ParseParamHex(configFilename, DefaultVendor);
287 ParseParamHex(configFilename, DefaultProduct);
288 ParseParamBool(configFilename, DetachStorageOnly);
289 ParseParamBool(configFilename, HuaweiMode);
290 ParseParamBool(configFilename, SierraMode);
291 ParseParamBool(configFilename, SonyMode);
292 ParseParamBool(configFilename, QisdaMode);
293 ParseParamBool(configFilename, QuantaMode);
294 ParseParamBool(configFilename, GCTMode);
295 ParseParamBool(configFilename, KobilMode);
296 ParseParamBool(configFilename, SequansMode);
297 ParseParamBool(configFilename, MobileActionMode);
298 ParseParamBool(configFilename, CiscoMode);
299 ParseParamBool(configFilename, NoDriverLoading);
300 ParseParamHex(configFilename, MessageEndpoint);
301 ParseParamString(configFilename, MessageContent);
302 ParseParamString(configFilename, MessageContent2);
303 ParseParamString(configFilename, MessageContent3);
304 ParseParamInt(configFilename, ReleaseDelay);
305 ParseParamHex(configFilename, NeedResponse);
306 ParseParamHex(configFilename, ResponseEndpoint);
307 ParseParamHex(configFilename, ResetUSB);
308 ParseParamHex(configFilename, InquireDevice);
309 ParseParamInt(configFilename, CheckSuccess);
310 ParseParamHex(configFilename, Interface);
311 ParseParamHex(configFilename, Configuration);
312 ParseParamHex(configFilename, AltSetting);
314 /* TargetProductList has priority over TargetProduct */
315 if (TargetProduct != -1 && TargetProductList[0] != '\0') {
316 TargetProduct = -1;
317 SHOW_PROGRESS(output,"Warning: TargetProductList overrides TargetProduct!\n");
320 config_read = 1;
324 void printConfig()
326 if ( DefaultVendor )
327 printf ("DefaultVendor= 0x%04x\n", DefaultVendor);
328 else
329 fprintf (output,"DefaultVendor= not set\n");
330 if ( DefaultProduct )
331 fprintf (output,"DefaultProduct= 0x%04x\n", DefaultProduct);
332 else
333 fprintf (output,"DefaultProduct= not set\n");
334 if ( TargetVendor )
335 fprintf (output,"TargetVendor= 0x%04x\n", TargetVendor);
336 else
337 fprintf (output,"TargetVendor= not set\n");
338 if ( TargetProduct > -1 )
339 fprintf (output,"TargetProduct= 0x%04x\n", TargetProduct);
340 else
341 fprintf (output,"TargetProduct= not set\n");
342 if ( TargetClass )
343 fprintf (output,"TargetClass= 0x%02x\n", TargetClass);
344 else
345 fprintf (output,"TargetClass= not set\n");
346 fprintf (output,"TargetProductList=\"%s\"\n", TargetProductList);
347 fprintf (output,"\nDetachStorageOnly=%i\n", (int)DetachStorageOnly);
348 fprintf (output,"HuaweiMode=%i\n", (int)HuaweiMode);
349 fprintf (output,"SierraMode=%i\n", (int)SierraMode);
350 fprintf (output,"SonyMode=%i\n", (int)SonyMode);
351 fprintf (output,"QisdaMode=%i\n", (int)QisdaMode);
352 fprintf (output,"QuantaMode=%i\n", (int)QuantaMode);
353 fprintf (output,"GCTMode=%i\n", (int)GCTMode);
354 fprintf (output,"KobilMode=%i\n", (int)KobilMode);
355 fprintf (output,"SequansMode=%i\n", (int)SequansMode);
356 fprintf (output,"MobileActionMode=%i\n", (int)MobileActionMode);
357 fprintf (output,"CiscoMode=%i\n", (int)CiscoMode);
358 if ( MessageEndpoint )
359 fprintf (output,"MessageEndpoint=0x%02x\n", MessageEndpoint);
360 else
361 fprintf (output,"MessageEndpoint= not set\n");
362 fprintf (output,"MessageContent=\"%s\"\n", MessageContent);
363 if ( strlen(MessageContent2) )
364 fprintf (output,"MessageContent2=\"%s\"\n", MessageContent2);
365 if ( strlen(MessageContent3) )
366 fprintf (output,"MessageContent3=\"%s\"\n", MessageContent3);
367 fprintf (output,"NeedResponse=%i\n", (int)NeedResponse);
368 if ( ResponseEndpoint )
369 fprintf (output,"ResponseEndpoint=0x%02x\n", ResponseEndpoint);
370 else
371 fprintf (output,"ResponseEndpoint= not set\n");
372 if ( Interface > -1 )
373 fprintf (output,"Interface=0x%02x\n", Interface);
374 if ( Configuration > 0 )
375 fprintf (output,"Configuration=0x%02x\n", Configuration);
376 if ( AltSetting > -1 )
377 fprintf (output,"AltSetting=0x%02x\n", AltSetting);
378 if ( InquireDevice )
379 fprintf (output,"\nInquireDevice enabled (default)\n");
380 else
381 fprintf (output,"\nInquireDevice disabled\n");
382 if ( CheckSuccess )
383 fprintf (output,"Success check enabled, max. wait time %d seconds\n", CheckSuccess);
384 else
385 fprintf (output,"Success check disabled\n");
386 if ( sysmode )
387 fprintf (output,"System integration mode enabled\n");
388 else
389 fprintf (output,"System integration mode disabled\n");
390 fprintf (output,"\n");
394 int readArguments(int argc, char **argv)
396 int c, option_index = 0, count=0;
397 char *longConfig = NULL;
398 if (argc==1)
400 printHelp();
401 printVersion();
402 exit(1);
405 while (1)
407 c = getopt_long (argc, argv, "hejWQDndHSOBEGTNALRItv:p:V:P:C:m:M:2:3:w:r:c:i:u:a:s:f:b:g:",
408 long_options, &option_index);
410 /* Detect the end of the options. */
411 if (c == -1)
412 break;
413 count++;
414 switch (c)
416 case 'R': ResetUSB = 1; break;
417 case 'v': DefaultVendor = strtol(optarg, NULL, 16); break;
418 case 'p': DefaultProduct = strtol(optarg, NULL, 16); break;
419 case 'V': TargetVendor = strtol(optarg, NULL, 16); break;
420 case 'P': TargetProduct = strtol(optarg, NULL, 16); break;
421 case 'C': TargetClass = strtol(optarg, NULL, 16); break;
422 case 'm': MessageEndpoint = strtol(optarg, NULL, 16); break;
423 case 'M': strncpy(MessageContent, optarg, LINE_DIM); break;
424 case '2': strncpy(MessageContent2, optarg, LINE_DIM); break;
425 case '3': strncpy(MessageContent3, optarg, LINE_DIM); break;
426 case 'w': ReleaseDelay = strtol(optarg, NULL, 10); break;
427 case 'n': NeedResponse = 1; break;
428 case 'r': ResponseEndpoint = strtol(optarg, NULL, 16); break;
429 case 'd': DetachStorageOnly = 1; break;
430 case 'H': HuaweiMode = 1; break;
431 case 'S': SierraMode = 1; break;
432 case 'O': SonyMode = 1; break;
433 case 'B': QisdaMode = 1; break;
434 case 'E': QuantaMode = 1; break;
435 case 'G': GCTMode = 1; break;
436 case 'T': KobilMode = 1; break;
437 case 'N': SequansMode = 1; break;
438 case 'A': MobileActionMode = 1; break;
439 case 'L': CiscoMode = 1; break;
440 case 'c': readConfigFile(optarg); break;
441 case 't': readConfigFile("stdin"); break;
442 case 'W': verbose = 1; show_progress = 1; count--; break;
443 case 'Q': show_progress = 0; verbose = 0; count--; break;
444 case 'D': sysmode = 1; InquireDevice = 0; count--; break;
445 case 's': CheckSuccess = strtol(optarg, NULL, 10); count--; break;
446 case 'I': InquireDevice = 0; break;
447 case 'b': busnum = strtol(optarg, NULL, 10); break;
448 case 'g': devnum = strtol(optarg, NULL, 10); break;
450 case 'i': Interface = strtol(optarg, NULL, 16); break;
451 case 'u': Configuration = strtol(optarg, NULL, 16); break;
452 case 'a': AltSetting = strtol(optarg, NULL, 16); break;
453 case 'j': mbim = 1; break;
455 case 'f':
456 longConfig = malloc(strlen(optarg)+5);
457 strcpy(longConfig,"##\n");
458 strcat(longConfig,optarg);
459 strcat(longConfig,"\n");
460 readConfigFile(longConfig);
461 free(longConfig);
462 break;
464 case 'e':
465 printVersion();
466 exit(0);
467 break;
468 case 'h':
469 printVersion();
470 printHelp();
471 exit(0);
472 break;
474 default: /* Unsupported - error message has already been printed */
475 fprintf (output,"\n");
476 printHelp();
477 exit(1);
481 return count;
485 int main(int argc, char **argv)
487 int numDefaults=0, specialMode=0, sonySuccess=0;
488 int currentConfig=0, defaultClass=0, interfaceClass=0;
489 struct libusb_device_descriptor descriptor;
490 struct libusb_config_descriptor *config;
493 /* Make sure we have empty strings even if not set by config */
494 TargetProductList[0] = '\0';
495 MessageContent[0] = '\0';
496 MessageContent2[0] = '\0';
497 MessageContent3[0] = '\0';
499 /* Useful for debugging during boot */
500 // output=fopen("/dev/console", "w");
501 output=stdout;
503 signal(SIGTERM, release_usb_device);
506 * Parameter parsing, USB preparation/diagnosis, plausibility checks
509 /* Check command arguments, use params instead of config file when given */
510 switch (readArguments(argc, argv)) {
511 case 0: /* no argument or -W, -q or -s */
512 break;
513 default: /* one or more arguments except -W, -q or -s */
514 if (!config_read) /* if arguments contain -c, the config file was already processed */
515 if (verbose) fprintf(output,"Taking all parameters from the command line\n\n");
518 if (verbose) {
519 printVersion();
520 printConfig();
521 SHOW_PROGRESS(output,"\n");
524 /* Some sanity checks. The default IDs are mandatory */
525 if (!(DefaultVendor && DefaultProduct)) {
526 SHOW_PROGRESS(output,"No default vendor/product ID given. Aborting.\n\n");
527 exit(1);
529 if (strlen(MessageContent)) {
530 if (strlen(MessageContent) % 2 != 0) {
531 fprintf(stderr, "Error: MessageContent hex string has uneven length. Aborting.\n\n");
532 exit(1);
534 if ( hexstr2bin(MessageContent, ByteString, strlen(MessageContent)/2) == -1) {
535 fprintf(stderr, "Error: MessageContent %s\n is not a hex string. Aborting.\n\n", MessageContent);
536 exit(1);
540 if (devnum == -1) {
541 searchMode = SEARCH_DEFAULT;
542 } else {
543 SHOW_PROGRESS(output,"Use given bus/device number: %03d/%03d ...\n", busnum, devnum);
544 searchMode = SEARCH_BUSDEV;
547 if (show_progress)
548 if (CheckSuccess && !(TargetVendor || TargetProduct > -1 || TargetProductList[0] != '\0') && !TargetClass)
549 printf("Note: target parameter missing; success check limited\n");
551 /* libusb initialization */
552 libusb_init(&ctx);
554 if (verbose)
555 usb_set_debug(15);
557 if (mbim) {
558 printf("%d\n", findMBIMConfig(DefaultVendor, DefaultProduct, searchMode) );
559 exit(0);
562 /* Count existing target devices, remember for success check */
563 if ((TargetVendor || TargetClass) && searchMode != SEARCH_BUSDEV) {
564 SHOW_PROGRESS(output,"Looking for target devices ...\n");
565 search_devices(&targetDeviceCount, TargetVendor, TargetProduct, TargetProductList, TargetClass, 0, SEARCH_TARGET);
566 if (targetDeviceCount) {
567 SHOW_PROGRESS(output," Found devices in target mode or class (%d)\n", targetDeviceCount);
568 } else
569 SHOW_PROGRESS(output," No devices in target mode or class found\n");
572 /* Count default devices, get the last one found */
573 SHOW_PROGRESS(output,"Looking for default devices ...\n");
574 dev = search_devices(&numDefaults, DefaultVendor, DefaultProduct, "\0", TargetClass, Configuration, searchMode);
575 if (numDefaults) {
576 SHOW_PROGRESS(output," Found device in default mode, class or configuration (%d)\n", numDefaults);
577 } else {
578 SHOW_PROGRESS(output," No devices in default mode found. Nothing to do. Bye.\n\n");
579 exit(0);
581 if (dev == NULL) {
582 SHOW_PROGRESS(output," No bus/device match. Is device connected? Bye.\n\n");
583 exit(0);
584 } else {
585 if (devnum == -1) {
586 devnum = libusb_get_device_address(dev);
587 busnum = libusb_get_bus_number(dev);
588 SHOW_PROGRESS(output,"Accessing device %03d on bus %03d ...\n", devnum, busnum);
590 libusb_open(dev, &devh);
591 if (devh == NULL) {
592 SHOW_PROGRESS(output,"Error opening the device. Aborting.\n\n");
593 exit(1);
597 /* Get current configuration of default device
598 * A configuration value of -1 helps with quirky devices which have
599 * trouble determining the current configuration. We are just using the
600 * current config branch then.
601 * This affects only single-configuration devices so it's no problem.
602 * The dispatcher is using this always if no change of configuration
603 * is required for switching
605 if (Configuration > -1)
606 currentConfig = get_current_configuration(devh);
607 else {
608 SHOW_PROGRESS(output,"Skipping the check for the current configuration\n");
609 currentConfig = 0;
612 libusb_get_device_descriptor(dev, &descriptor);
613 defaultClass = descriptor.bDeviceClass;
614 libusb_get_config_descriptor(dev, 0, &config);
615 if (Interface == -1)
616 Interface = config->interface[0].altsetting[0].bInterfaceNumber;
617 SHOW_PROGRESS(output,"Using interface number %d\n", Interface);
619 /* Get class of default device/interface */
620 interfaceClass = get_interface_class(config, Interface);
621 libusb_free_config_descriptor(config);
622 if (interfaceClass == -1) {
623 fprintf(stderr, "Error: getting the class of interface %d failed. Does it exist? Aborting.\n\n",Interface);
624 exit(1);
627 if (defaultClass == 0)
628 defaultClass = interfaceClass;
629 else
630 if (interfaceClass == 8 && defaultClass != 8) {
631 /* Weird device with default class other than 0 and differing interface class */
632 SHOW_PROGRESS(output,"Ambiguous Class/InterfaceClass: 0x%02x/0x08\n", defaultClass);
633 defaultClass = 8;
636 if (strlen(MessageContent) && strncmp("55534243",MessageContent,8) == 0)
637 if (defaultClass != 8) {
638 fprintf(stderr, "Error: can't use storage command in MessageContent with interface %d;\n"
639 " interface class is %d, should be 8. Aborting.\n\n", Interface, defaultClass);
640 exit(1);
643 /* Check or get endpoints */
644 if (strlen(MessageContent) || InquireDevice || CiscoMode) {
645 if (!MessageEndpoint)
646 MessageEndpoint = find_first_bulk_output_endpoint(dev);
647 if (!MessageEndpoint) {
648 fprintf(stderr,"Error: message endpoint not given or found. Aborting.\n\n");
649 exit(1);
651 if (!ResponseEndpoint)
652 ResponseEndpoint = find_first_bulk_input_endpoint(dev);
653 if (!ResponseEndpoint) {
654 fprintf(stderr,"Error: response endpoint not given or found. Aborting.\n\n");
655 exit(1);
657 SHOW_PROGRESS(output,"Using endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint, ResponseEndpoint);
660 if (!MessageEndpoint || !ResponseEndpoint)
661 if (InquireDevice && defaultClass == 0x08) {
662 SHOW_PROGRESS(output,"Endpoints not found, skipping SCSI inquiry\n");
663 InquireDevice = 0;
666 if (InquireDevice && show_progress) {
667 if (defaultClass == 0x08) {
668 SHOW_PROGRESS(output,"Inquiring device details; driver will be detached ...\n");
669 detachDriver();
670 if (deviceInquire() >= 0)
671 InquireDevice = 2;
672 } else
673 SHOW_PROGRESS(output,"Not a storage device, skipping SCSI inquiry\n");
676 deviceDescription();
677 if (show_progress) {
678 printf("\nUSB description data (for identification)\n");
679 printf("-------------------------\n");
680 printf("Manufacturer: %s\n", imanufact);
681 printf(" Product: %s\n", iproduct);
682 printf(" Serial No.: %s\n", iserial);
683 printf("-------------------------\n");
686 /* Some scenarios are exclusive, so check for unwanted combinations */
687 specialMode = DetachStorageOnly + HuaweiMode + SierraMode + SonyMode + QisdaMode + KobilMode
688 + SequansMode + MobileActionMode + CiscoMode + QuantaMode;
689 if ( specialMode > 1 ) {
690 SHOW_PROGRESS(output,"Invalid mode combination. Check your configuration. Aborting.\n\n");
691 exit(1);
694 if ( !specialMode && !strlen(MessageContent) && AltSetting == -1 && Configuration == 0 )
695 SHOW_PROGRESS(output,"Warning: no switching method given.\n");
698 * The switching actions
701 if (sysmode) {
702 openlog("usb_modeswitch", 0, LOG_SYSLOG);
703 syslog(LOG_NOTICE, "switching device %04x:%04x on %03d/%03d", DefaultVendor, DefaultProduct, busnum, devnum);
706 if (DetachStorageOnly) {
707 SHOW_PROGRESS(output,"Only detaching storage driver for switching ...\n");
708 if (InquireDevice == 2) {
709 SHOW_PROGRESS(output," Any driver was already detached for inquiry\n");
710 } else {
711 ret = detachDriver();
712 if (ret == 2)
713 SHOW_PROGRESS(output," You may want to remove the storage driver manually\n");
717 if (HuaweiMode) {
718 switchHuaweiMode();
720 if (SierraMode) {
721 switchSierraMode();
723 if (GCTMode) {
724 detachDriver();
725 switchGCTMode();
727 if (QisdaMode) {
728 switchQisdaMode();
730 if(KobilMode) {
731 detachDriver();
732 switchKobilMode();
734 if(QuantaMode) {
735 switchQuantaMode();
737 if (SequansMode) {
738 switchSequansMode();
740 if(MobileActionMode) {
741 switchActionMode();
743 if(CiscoMode) {
744 detachDriver();
745 switchCiscoMode();
747 if (SonyMode) {
748 if (CheckSuccess)
749 SHOW_PROGRESS(output,"Note: ignoring CheckSuccess. Separate checks for Sony mode\n");
750 CheckSuccess = 0; /* separate and implied success control */
751 sonySuccess = switchSonyMode();
754 if (strlen(MessageContent) && MessageEndpoint) {
755 if (specialMode == 0) {
756 if (InquireDevice != 2)
757 detachDriver();
758 switchSendMessage();
759 } else
760 SHOW_PROGRESS(output,"Warning: ignoring MessageContent. Can't combine with special mode\n");
763 if (Configuration > 0) {
764 if (currentConfig != Configuration) {
765 if (switchConfiguration()) {
766 currentConfig = get_current_configuration(devh);
767 if (currentConfig == Configuration) {
768 SHOW_PROGRESS(output,"The configuration was set successfully\n");
769 } else {
770 SHOW_PROGRESS(output,"Changing the configuration has failed\n");
773 } else {
774 SHOW_PROGRESS(output,"Target configuration %d already active. Doing nothing\n", currentConfig);
778 if (AltSetting != -1) {
779 switchAltSetting();
782 /* No "removal" check if these are set */
783 if ((Configuration > 0 || AltSetting > -1) && !ResetUSB) {
784 usb_close(devh);
785 devh = 0;
788 if (ResetUSB) {
789 resetUSB();
790 usb_close(devh);
791 devh = 0;
794 if (CheckSuccess) {
795 if (searchMode == SEARCH_BUSDEV && sysmode) {
796 SHOW_PROGRESS(output,"Bus/dev search active, referring success check to wrapper. Bye.\n\n");
797 printf("ok:busdev\n");
798 goto CLOSING;
800 if (checkSuccess()) {
801 if (sysmode) {
802 if (NoDriverLoading)
803 printf("ok:\n");
804 else
805 if (TargetProduct < 1)
806 printf("ok:no_data\n");
807 else
808 printf("ok:%04x:%04x\n", TargetVendor, TargetProduct);
810 } else
811 if (sysmode)
812 printf("fail:\n");
813 } else {
814 if (SonyMode)
815 if (sonySuccess) {
816 if (sysmode) {
817 syslog(LOG_NOTICE, "switched S.E. MD400 to modem mode");
818 printf("ok:\n"); /* ACM device, no driver action */
820 SHOW_PROGRESS(output,"-> device should be stable now. Bye.\n\n");
821 } else {
822 if (sysmode)
823 printf("fail:\n");
824 SHOW_PROGRESS(output,"-> switching was probably not completed. Bye.\n\n");
826 else
827 SHOW_PROGRESS(output,"-> Run lsusb to note any changes. Bye.\n\n");
829 CLOSING:
830 if (sysmode)
831 closelog();
832 if (devh)
833 usb_close(devh);
834 exit(0);
838 /* Get descriptor strings if available (identification details) */
839 void deviceDescription ()
841 int ret;
842 char* c;
843 memset (imanufact, ' ', DESCR_MAX);
844 memset (iproduct, ' ', DESCR_MAX);
845 memset (iserial, ' ', DESCR_MAX);
847 struct libusb_device_descriptor descriptor;
848 libusb_get_device_descriptor(dev, &descriptor);
850 int iManufacturer = descriptor.iManufacturer;
851 int iProduct = descriptor.iProduct;
852 int iSerialNumber = descriptor.iSerialNumber;
854 if (iManufacturer) {
855 ret = usb_get_string_simple(devh, iManufacturer, imanufact, DESCR_MAX);
856 if (ret < 0)
857 fprintf(stderr, "Error: could not get description string \"manufacturer\"\n");
858 } else
859 strcpy(imanufact, "not provided");
860 c = strstr(imanufact, " ");
861 if (c)
862 memset((void*)c, '\0', 1);
864 if (iProduct) {
865 ret = usb_get_string_simple(devh, iProduct, iproduct, DESCR_MAX);
866 if (ret < 0)
867 fprintf(stderr, "Error: could not get description string \"product\"\n");
868 } else
869 strcpy(iproduct, "not provided");
870 c = strstr(iproduct, " ");
871 if (c)
872 memset((void*)c, '\0', 1);
874 if (iSerialNumber) {
875 ret = usb_get_string_simple(devh, iSerialNumber, iserial, DESCR_MAX);
876 if (ret < 0)
877 fprintf(stderr, "Error: could not get description string \"serial number\"\n");
878 } else
879 strcpy(iserial, "not provided");
880 c = strstr(iserial, " ");
881 if (c)
882 memset((void*)c, '\0', 1);
886 /* Print result of SCSI command INQUIRY (identification details) */
887 int deviceInquire ()
889 const unsigned char inquire_msg[] = {
890 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
891 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
892 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
893 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
895 char *command;
896 char data[36];
897 int i, ret;
899 command = malloc(31);
900 if (command == NULL) {
901 ret = 1;
902 goto out;
905 memcpy(command, inquire_msg, sizeof (inquire_msg));
907 ret = usb_claim_interface(devh, Interface);
908 if (ret != 0) {
909 SHOW_PROGRESS(output," Could not claim interface (error %d). Skipping device inquiry\n", ret);
910 goto out;
912 usb_clear_halt(devh, MessageEndpoint);
914 ret = usb_bulk_write(devh, MessageEndpoint, (char *)command, 31, 0);
915 if (ret < 0) {
916 SHOW_PROGRESS(output," Could not send INQUIRY message (error %d)\n", ret);
917 goto out;
920 ret = usb_bulk_read(devh, ResponseEndpoint, data, 36, 0);
921 if (ret < 0) {
922 SHOW_PROGRESS(output," Could not get INQUIRY response (error %d)\n", ret);
923 goto out;
926 i = usb_bulk_read(devh, ResponseEndpoint, command, 13, 0);
928 printf("\nSCSI inquiry data (for identification)\n");
929 printf("-------------------------\n");
931 printf(" Vendor String: ");
932 for (i = 8; i < 16; i++) printf("%c",data[i]);
933 printf("\n");
935 printf(" Model String: ");
936 for (i = 16; i < 32; i++) printf("%c",data[i]);
937 printf("\n");
939 printf("Revision String: ");
940 for (i = 32; i < 36; i++) printf("%c",data[i]);
942 printf("\n-------------------------\n");
944 out:
945 if (strlen(MessageContent) == 0)
946 usb_clear_halt(devh, MessageEndpoint);
947 usb_release_interface(devh, Interface);
948 free(command);
949 return ret;
953 int findMBIMConfig(int vendor, int product, int mode)
955 struct libusb_device **devs;
956 int resultConfig=0;
957 int i=0, j;
959 if (libusb_get_device_list(ctx, &devs) < 0) {
960 perror("failed to access USB");
961 return 0;
964 SHOW_PROGRESS(output,"Search USB devices...\n");
965 while ((dev = devs[i++]) != NULL) {
966 struct libusb_device_descriptor descriptor;
967 libusb_get_device_descriptor(dev, &descriptor);
969 if (mode == SEARCH_BUSDEV) {
970 if ((libusb_get_bus_number(dev) != busnum) ||
971 (libusb_get_device_address(dev) != devnum)) {
972 continue;
973 } else {
974 // if (verbose)
975 // fprintf (output," searching devices, found USB ID %04x:%04x\n", descriptor.idVendor, descriptor.idProduct);
976 if (descriptor.idVendor != vendor)
977 continue;
978 if (product != descriptor.idProduct)
979 continue;
982 SHOW_PROGRESS(output,"Found device, searching for MBIM configuration...\n");
984 // No check if there is only one configuration
985 if (descriptor.bNumConfigurations < 2)
986 return -1;
988 // Checking all interfaces of all configurations
989 for (j=0; j<descriptor.bNumConfigurations; j++) {
990 struct libusb_config_descriptor *config;
992 libusb_get_config_descriptor(dev, j, &config);
993 resultConfig = config->bConfigurationValue;
994 for (i=0; i<config->bNumInterfaces; i++) {
995 // SHOW_PROGRESS(output,"MBIM Check: looking at ifc %d, class is %d, subclass is %d\n",
996 // i,config->interface[i].altsetting[0].bInterfaceClass,config->interface[i].altsetting[0].bInterfaceSubClass);
998 if ( config->interface[i].altsetting[0].bInterfaceClass == 2 )
999 if ( config->interface[i].altsetting[0].bInterfaceSubClass == 0x0e ) {
1000 // found MBIM interface in this configuration
1001 libusb_free_config_descriptor(config);
1002 return resultConfig;
1005 libusb_free_config_descriptor(config);
1007 return -1;
1009 return 0;
1012 void resetUSB ()
1014 int success;
1015 int bpoint = 0;
1017 if (show_progress) {
1018 printf("Resetting usb device ");
1019 fflush(stdout);
1022 sleep( 1 );
1023 do {
1024 success = usb_reset(devh);
1025 if ( ((bpoint % 10) == 0) && show_progress ) {
1026 printf(".");
1027 fflush(stdout);
1029 bpoint++;
1030 if (bpoint > 100)
1031 success = 1;
1032 } while (success < 0);
1034 if ( success ) {
1035 SHOW_PROGRESS(output,"\n Reset failed. Can be ignored if device switched OK.\n");
1036 } else
1037 SHOW_PROGRESS(output,"\n OK, device was reset\n");
1041 int switchSendMessage ()
1043 const char* cmdHead = "55534243";
1044 int ret, i;
1045 char* msg[3];
1046 msg[0] = MessageContent;
1047 msg[1] = MessageContent2;
1048 msg[2] = MessageContent3;
1050 /* May be activated in future versions */
1051 // if (MessageContent2[0] != '\0' || MessageContent3[0] != '\0')
1052 // NeedResponse = 1;
1054 SHOW_PROGRESS(output,"Setting up communication with interface %d\n", Interface);
1055 if (InquireDevice != 2) {
1056 ret = usb_claim_interface(devh, Interface);
1057 if (ret != 0) {
1058 SHOW_PROGRESS(output," Could not claim interface (error %d). Skipping message sending\n", ret);
1059 return 0;
1062 usb_clear_halt(devh, MessageEndpoint);
1063 SHOW_PROGRESS(output,"Using endpoint 0x%02x for message sending ...\n", MessageEndpoint);
1064 if (show_progress)
1065 fflush(stdout);
1067 for (i=0; i<3; i++) {
1068 if ( strlen(msg[i]) == 0)
1069 continue;
1071 if ( sendMessage(msg[i], i+1) )
1072 goto skip;
1074 if (NeedResponse) {
1075 if ( strstr(msg[i],cmdHead) != NULL ) {
1076 // UFI command
1077 SHOW_PROGRESS(output,"Reading the response to message %d (CSW) ...\n", i+1);
1078 ret = read_bulk(ResponseEndpoint, ByteString, 13);
1079 } else {
1080 // Other bulk transfer
1081 SHOW_PROGRESS(output,"Reading the response to message %d ...\n", i+1);
1082 ret = read_bulk(ResponseEndpoint, ByteString, strlen(msg[i])/2 );
1084 if (ret < 0)
1085 goto skip;
1089 SHOW_PROGRESS(output,"Resetting response endpoint 0x%02x\n", ResponseEndpoint);
1090 ret = usb_clear_halt(devh, ResponseEndpoint);
1091 if (ret)
1092 SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret);
1093 SHOW_PROGRESS(output,"Resetting message endpoint 0x%02x\n", MessageEndpoint);
1094 ret = usb_clear_halt(devh, MessageEndpoint);
1095 if (ret)
1096 SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret);
1097 usleep(50000);
1099 if (ReleaseDelay) {
1100 SHOW_PROGRESS(output,"Blocking the interface for %d ms before releasing ...\n", ReleaseDelay);
1101 usleep(ReleaseDelay*1000);
1103 ret = usb_release_interface(devh, Interface);
1104 if (ret)
1105 goto skip;
1106 return 1;
1108 skip:
1109 SHOW_PROGRESS(output," Device is gone, skipping any further commands\n");
1110 usb_close(devh);
1111 devh = 0;
1112 return 2;
1115 int switchConfiguration ()
1117 int count = SWITCH_CONFIG_MAXTRIES;
1118 int ret;
1120 SHOW_PROGRESS(output,"Changing configuration to %i ...\n", Configuration);
1121 while (((ret = usb_set_configuration(devh, Configuration)) < 0) && --count) {
1122 SHOW_PROGRESS(output," Device is busy, trying to detach kernel driver\n");
1123 detachDriver();
1125 if (ret == 0 ) {
1126 SHOW_PROGRESS(output," OK, configuration set\n");
1127 return 1;
1129 SHOW_PROGRESS(output," Setting the configuration returned error %d. Trying to continue\n", ret);
1130 return 0;
1134 int switchAltSetting ()
1136 int ret;
1138 SHOW_PROGRESS(output,"Changing to alt setting %i ...\n", AltSetting);
1139 ret = usb_claim_interface(devh, Interface);
1140 ret = libusb_set_interface_alt_setting(devh, Interface, AltSetting);
1141 usb_release_interface(devh, Interface);
1142 if (ret != 0) {
1143 SHOW_PROGRESS(output," Changing to alt setting returned error %d. Trying to continue\n", ret);
1144 return 0;
1145 } else {
1146 SHOW_PROGRESS(output," OK, changed to alt setting\n");
1147 return 1;
1152 void switchHuaweiMode ()
1154 int ret;
1156 SHOW_PROGRESS(output,"Sending Huawei control message ...\n");
1157 ret = usb_control_msg(devh, USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_REQ_SET_FEATURE, 00000001, 0, buffer, 0, 1000);
1158 if (ret != 0) {
1159 fprintf(stderr, "Error: sending Huawei control message failed (error %d). Aborting.\n\n", ret);
1160 exit(1);
1161 } else
1162 SHOW_PROGRESS(output," OK, Huawei control message sent\n");
1166 void switchSierraMode ()
1168 int ret;
1170 SHOW_PROGRESS(output,"Trying to send Sierra control message\n");
1171 ret = usb_control_msg(devh, USB_TYPE_VENDOR, 0x0b, 00000001, 0, buffer, 0, 1000);
1172 if (ret == LIBUSB_ERROR_PIPE) {
1173 SHOW_PROGRESS(output," communication with device stopped. May have switched, continue ...\n");
1174 return;
1176 if (ret != 0) {
1177 fprintf(stderr, "Error: sending Sierra control message failed (error %d). Aborting.\n\n", ret);
1178 exit(1);
1179 } else
1180 SHOW_PROGRESS(output," OK, Sierra control message sent\n");
1184 void switchGCTMode ()
1186 int ret;
1188 ret = usb_claim_interface(devh, Interface);
1189 if (ret != 0) {
1190 SHOW_PROGRESS(output," Could not claim interface (error %d). Skipping GCT sequence \n", ret);
1191 return;
1194 SHOW_PROGRESS(output,"Sending GCT control message 1 ...\n");
1195 ret = usb_control_msg(devh, 0xa1, 0xa0, 0, Interface, buffer, 1, 1000);
1196 SHOW_PROGRESS(output,"Sending GCT control message 2 ...\n");
1197 ret = usb_control_msg(devh, 0xa1, 0xfe, 0, Interface, buffer, 1, 1000);
1198 SHOW_PROGRESS(output," OK, GCT control messages sent\n");
1199 usb_release_interface(devh, Interface);
1203 int switchKobilMode() {
1204 int ret;
1206 SHOW_PROGRESS(output,"Sending Kobil control message ...\n");
1207 ret = usb_control_msg(devh, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, 0x88, 0, 0, buffer, 8, 1000);
1208 if (ret != 0) {
1209 fprintf(stderr, "Error: sending Kobil control message failed (error %d). Aborting.\n\n", ret);
1210 exit(1);
1211 } else
1212 SHOW_PROGRESS(output," OK, Kobil control message sent\n");
1213 return 1;
1216 void switchQuantaMode() {
1217 int ret;
1219 SHOW_PROGRESS(output,"Sending Quanta control message ...\n");
1220 ret = usb_control_msg(devh, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, 0xff, 0, 0, buffer, 0, 1000);
1221 if (ret < 0) {
1222 SHOW_PROGRESS(output," Sending Quanta control message returned error %d, continue anyway ...\n", ret);
1223 } else {
1224 SHOW_PROGRESS(output," OK, Quanta control message sent\n");
1228 int switchQisdaMode () {
1229 int ret;
1231 SHOW_PROGRESS(output,"Sending Qisda control message ...\n");
1232 memcpy(buffer, "\x05\x8c\x04\x08\xa0\xee\x20\x00\x5c\x01\x04\x08\x98\xcd\xea\xbf", 16);
1233 ret = usb_control_msg(devh, 0x40, 0x04, 00000000, 0, buffer, 16, 1000);
1234 if (ret != 0) {
1235 fprintf(stderr, "Error: sending Qisda control message failed (error %d). Aborting.\n\n", ret);
1236 exit(1);
1237 } else
1238 SHOW_PROGRESS(output," OK, Qisda control message sent\n");
1239 return 1;
1242 int switchSonyMode ()
1244 int i, found, ret;
1245 detachDriver();
1247 if (CheckSuccess) {
1248 printf("Note: CheckSuccess pointless with Sony mode, disabling\n");
1249 CheckSuccess = 0;
1252 SHOW_PROGRESS(output,"Trying to send Sony control message\n");
1253 ret = usb_control_msg(devh, 0xc0, 0x11, 2, 0, buffer, 3, 100);
1254 if (ret < 0) {
1255 fprintf(stderr, "Error: sending Sony control message failed (error %d). Aborting.\n\n", ret);
1256 exit(1);
1257 } else
1258 SHOW_PROGRESS(output," OK, control message sent, waiting for device to return ...\n");
1260 usb_close(devh);
1261 devh = 0;
1263 /* Now waiting for the device to reappear */
1264 devnum=-1;
1265 busnum=-1;
1266 i=0;
1267 dev = 0;
1268 while ( dev == 0 && i < 30 ) {
1269 if ( i > 5 ) {
1270 dev = search_devices(&found, DefaultVendor, DefaultProduct, "\0", TargetClass, 0, SEARCH_TARGET);
1272 if ( dev != 0 )
1273 break;
1274 sleep(1);
1275 if (show_progress) {
1276 printf("#");
1277 fflush(stdout);
1279 i++;
1281 SHOW_PROGRESS(output,"\n After %d seconds:",i);
1282 if ( dev ) {
1283 SHOW_PROGRESS(output," device came back, proceeding\n");
1284 libusb_open(dev, &devh);
1285 if (devh == 0) {
1286 fprintf(stderr, "Error: could not get handle on device\n");
1287 return 0;
1289 } else {
1290 SHOW_PROGRESS(output," device still gone, cancelling\n");
1291 return 0;
1293 sleep(1);
1295 SHOW_PROGRESS(output,"Sending Sony control message again ...\n");
1296 ret = usb_control_msg(devh, 0xc0, 0x11, 2, 0, buffer, 3, 100);
1297 if (ret < 0) {
1298 fprintf(stderr, "Error: sending Sony control message (2) failed (error %d)\n", ret);
1299 return 0;
1301 SHOW_PROGRESS(output," OK, control message sent\n");
1302 return 1;
1306 #define EP_OUT 0x02
1307 #define EP_IN 0x81
1308 #define SIZE 0x08
1310 #define MOBILE_ACTION_READLOOP1 63
1311 #define MOBILE_ACTION_READLOOP2 73
1313 int switchActionMode ()
1315 int i;
1316 SHOW_PROGRESS(output,"Sending MobileAction control sequence ...\n");
1317 memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
1318 usb_control_msg(devh, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x0300, 0, buffer, SIZE, 1000);
1319 memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
1320 usb_control_msg(devh, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x0300, 0, buffer, SIZE, 1000);
1321 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1322 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1323 memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
1324 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1325 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1326 memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
1327 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1328 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1329 memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
1330 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1331 for (i=0; i < MOBILE_ACTION_READLOOP1; i++) {
1332 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1334 memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
1335 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1336 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1337 memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
1338 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1339 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1340 memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
1341 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1342 for (i=0; i < MOBILE_ACTION_READLOOP2; i++) {
1343 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1345 memcpy(buffer, "\x33\x04\xfe\x00\xf4\x6c\x1f\xf0", SIZE);
1346 usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1347 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1348 memcpy(buffer, "\x32\x07\xfe\xf0\x29\xb9\x3a\xf0", SIZE);
1349 ret = usb_interrupt_write(devh, EP_OUT, buffer, SIZE, 1000);
1350 usb_interrupt_read(devh, EP_IN, buffer, SIZE, 1000);
1351 if (ret < 0) {
1352 SHOW_PROGRESS(output," MobileAction control sequence did not complete\n Last error was %d\n",ret);
1353 return 1;
1354 } else {
1355 SHOW_PROGRESS(output," MobileAction control sequence complete\n");
1356 return 0;
1361 #define SQN_SET_DEVICE_MODE_REQUEST 0x0b
1362 #define SQN_GET_DEVICE_MODE_REQUEST 0x0a
1364 #define SQN_DEFAULT_DEVICE_MODE 0x00
1365 #define SQN_MASS_STORAGE_MODE 0x01
1366 #define SQN_CUSTOM_DEVICE_MODE 0x02
1368 int switchSequansMode() {
1369 int ret;
1371 SHOW_PROGRESS(output,"Sending Sequans vendor request\n");
1372 ret = usb_control_msg(devh, USB_TYPE_VENDOR | USB_RECIP_DEVICE, SQN_SET_DEVICE_MODE_REQUEST, SQN_CUSTOM_DEVICE_MODE, 0, buffer, 0, 1000);
1373 if (ret != 0) {
1374 fprintf(stderr, "Error: sending Sequans request failed (error %d). Aborting.\n\n", ret);
1375 exit(1);
1376 } else
1377 SHOW_PROGRESS(output," OK, Sequans request was sent\n");
1379 return 1;
1382 int switchCiscoMode() {
1383 int ret, i;
1384 char* msg[11];
1386 SHOW_PROGRESS(output,"Preparing for sending Cisco message sequence\n");
1388 msg[0] = "55534243f83bcd810002000080000afd000000030000000100000000000000";
1389 msg[1] = "55534243984300820002000080000afd000000070000000100000000000000";
1390 msg[2] = "55534243984300820000000000000afd000100071000000000000000000000";
1391 msg[3] = "55534243984300820002000080000afd000200230000000100000000000000";
1392 msg[4] = "55534243984300820000000000000afd000300238200000000000000000000";
1393 msg[5] = "55534243984300820002000080000afd000200260000000100000000000000";
1394 msg[6] = "55534243984300820000000000000afd00030026c800000000000000000000";
1395 msg[7] = "55534243d84c04820002000080000afd000010730000000100000000000000";
1396 msg[8] = "55534243d84c04820002000080000afd000200240000000100000000000000";
1397 msg[9] = "55534243d84c04820000000000000afd000300241300000000000000000000";
1398 msg[10] = "55534243d84c04820000000000000afd000110732400000000000000000000";
1400 SHOW_PROGRESS(output,"Setting up communication with interface %d\n", Interface);
1401 ret = usb_claim_interface(devh, Interface);
1402 if (ret != 0) {
1403 SHOW_PROGRESS(output," Could not claim interface (error %d). Skipping message sending\n", ret);
1404 return 0;
1406 // usb_clear_halt(devh, MessageEndpoint);
1407 if (show_progress)
1408 fflush(output);
1410 for (i=0; i<11; i++) {
1411 if ( sendMessage(msg[i], i+1) )
1412 goto skip;
1414 SHOW_PROGRESS(output,"Reading the response (CSW) to bulk message %d ...\n",i+1);
1415 ret = read_bulk(ResponseEndpoint, ByteString, 13);
1416 if (ret < 0)
1417 goto skip;
1420 if (ReleaseDelay) {
1421 SHOW_PROGRESS(output,"Blocking the interface for %d ms before releasing ...\n", ReleaseDelay);
1422 usleep(ReleaseDelay*1000);
1424 ret = usb_release_interface(devh, Interface);
1425 if (ret)
1426 goto skip;
1427 return 1;
1429 skip:
1430 SHOW_PROGRESS(output,"Device returned error, skipping any further commands\n");
1431 usb_close(devh);
1432 devh = 0;
1433 return 2;
1436 /* Detach driver
1438 int detachDriver()
1440 int ret;
1442 #ifndef LIBUSB_HAS_GET_DRIVER_NP
1443 printf(" Cant't do driver detection and detaching on this platform.\n");
1444 return 2;
1445 #else
1447 SHOW_PROGRESS(output,"Looking for active driver ...\n");
1448 ret = usb_get_driver_np(devh, Interface, buffer, BUF_SIZE);
1449 if (ret != 0) {
1450 SHOW_PROGRESS(output," No driver found. Either detached before or never attached\n");
1451 return 1;
1453 if (strncmp("dummy",buffer,5) == 0) {
1454 SHOW_PROGRESS(output," OK, driver found; name unknown, limitation of libusb1\n");
1455 strcpy(buffer,"unkown");
1456 } else {
1457 SHOW_PROGRESS(output," OK, driver found (\"%s\")\n", buffer);
1459 #endif
1461 #ifndef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
1462 SHOW_PROGRESS(output," Can't do driver detaching on this platform\n");
1463 return 2;
1464 #else
1466 ret = usb_detach_kernel_driver_np(devh, Interface);
1467 if (ret == 0) {
1468 SHOW_PROGRESS(output," OK, driver \"%s\" detached\n", buffer);
1469 } else
1470 SHOW_PROGRESS(output," Driver \"%s\" detach failed with error %d. Trying to continue\n", buffer, ret);
1471 return 1;
1472 #endif
1476 int sendMessage(char* message, int count)
1478 int message_length, ret;
1480 if (strlen(message) % 2 != 0) {
1481 fprintf(stderr, "Error: MessageContent %d hex string has uneven length. Skipping ...\n", count);
1482 return 1;
1484 message_length = strlen(message) / 2;
1485 if ( hexstr2bin(message, ByteString, message_length) == -1) {
1486 fprintf(stderr, "Error: MessageContent %d %s\n is not a hex string. Skipping ...\n", count, MessageContent);
1487 return 1;
1489 SHOW_PROGRESS(output,"Trying to send message %d to endpoint 0x%02x ...\n", count, MessageEndpoint);
1490 fflush(output);
1491 ret = write_bulk(MessageEndpoint, ByteString, message_length);
1492 if (ret == LIBUSB_ERROR_NO_DEVICE)
1493 return 1;
1495 return 0;
1499 int checkSuccess()
1501 int i=0, ret;
1502 int newTargetCount, success=0;
1504 SHOW_PROGRESS(output,"\nChecking for mode switch (max. %d times, once per second) ...\n", CheckSuccess);
1505 sleep(1);
1507 /* If target parameters are given, don't check for vanished device
1508 * Changed for Cisco AM10 where a new device is added while the install
1509 * storage device stays active
1511 if ((TargetVendor || TargetClass) && devh) {
1512 usb_close(devh);
1513 devh = 0;
1516 /* if target ID is not given but target class is, assign default as target;
1517 * it will be needed for sysmode output
1519 if (!TargetVendor && TargetClass) {
1520 TargetVendor = DefaultVendor;
1521 TargetProduct = DefaultProduct;
1524 /* devh is 0 if device vanished during command transmission or if target params were given
1526 if (devh)
1527 for (i=0; i < CheckSuccess; i++) {
1529 /* Test if default device still can be accessed; positive result does
1530 * not necessarily mean failure
1532 SHOW_PROGRESS(output," Waiting for original device to vanish ...\n");
1534 ret = usb_claim_interface(devh, Interface);
1535 usb_release_interface(devh, Interface);
1536 if (ret < 0) {
1537 SHOW_PROGRESS(output," Original device can't be accessed anymore. Good.\n");
1538 usb_close(devh);
1539 devh = 0;
1540 break;
1542 if (i == CheckSuccess-1) {
1543 SHOW_PROGRESS(output," Original device still present after the timeout\n\nMode switch most likely failed. Bye.\n\n");
1544 } else
1545 sleep(1);
1548 if ( TargetVendor && (TargetProduct > -1 || TargetProductList[0] != '\0') ) {
1550 /* Recount target devices (compare with previous count) if target data is given.
1551 * Target device on the same bus with higher device number is returned,
1552 * description is read for syslog message
1554 for (i=i; i < CheckSuccess; i++) {
1555 SHOW_PROGRESS(output," Searching for target devices ...\n");
1556 dev = search_devices(&newTargetCount, TargetVendor, TargetProduct, TargetProductList, TargetClass, 0, SEARCH_TARGET);
1557 if (dev && (newTargetCount > targetDeviceCount)) {
1558 printf("\nFound target device, now opening\n");
1559 libusb_open(dev, &devh);
1560 deviceDescription();
1561 usb_close(devh);
1562 devh = 0;
1563 if (verbose) {
1564 printf("\nFound target device %03d on bus %03d\n", \
1565 libusb_get_device_address(dev), libusb_get_bus_number(dev));
1566 printf("\nTarget device description data\n");
1567 printf("-------------------------\n");
1568 printf("Manufacturer: %s\n", imanufact);
1569 printf(" Product: %s\n", iproduct);
1570 printf(" Serial No.: %s\n", iserial);
1571 printf("-------------------------\n");
1573 SHOW_PROGRESS(output," Found correct target device\n\nMode switch succeeded. Bye.\n\n");
1574 success = 2;
1575 break;
1577 if (i == CheckSuccess-1) {
1578 SHOW_PROGRESS(output," No new devices in target mode or class found\n\nMode switch has failed. Bye.\n\n");
1579 } else
1580 sleep(1);
1582 } else
1583 /* No target data given, rely on the vanished device */
1584 if (!devh) {
1585 SHOW_PROGRESS(output," (For a better success check provide target IDs or class)\n");
1586 SHOW_PROGRESS(output," Original device vanished after switching\n\nMode switch most likely succeeded. Bye.\n\n");
1587 success = 1;
1590 switch (success) {
1591 case 3:
1592 if (sysmode)
1593 syslog(LOG_NOTICE, "switched to new device, but hit libusb1 bug");
1594 TargetProduct = -1;
1595 success = 1;
1596 break;
1597 case 2:
1598 if (sysmode)
1599 syslog(LOG_NOTICE, "switched to %04x:%04x on %03d/%03d", TargetVendor, TargetProduct, busnum, devnum);
1600 success = 1;
1601 break;
1602 case 1:
1603 if (sysmode)
1604 syslog(LOG_NOTICE, "device seems to have switched");
1605 default:
1608 if (sysmode)
1609 closelog();
1611 return success;
1616 int write_bulk(int endpoint, char *message, int length)
1618 int ret;
1619 ret = usb_bulk_write(devh, endpoint, message, length, 3000);
1620 if (ret >= 0 ) {
1621 SHOW_PROGRESS(output," OK, message successfully sent\n");
1622 } else
1623 if (ret == LIBUSB_ERROR_NO_DEVICE) {
1624 SHOW_PROGRESS(output," Device seems to have vanished right after sending. Good.\n");
1625 } else
1626 SHOW_PROGRESS(output," Sending the message returned error %d. Trying to continue\n", ret);
1627 return ret;
1631 int read_bulk(int endpoint, char *buffer, int length)
1633 int ret;
1634 ret = usb_bulk_read(devh, endpoint, buffer, length, 3000);
1635 usb_bulk_read(devh, endpoint, buffer, 13, 100);
1636 if (ret >= 0 ) {
1637 SHOW_PROGRESS(output," OK, response successfully read (%d bytes).\n", ret);
1638 } else
1639 if (ret == LIBUSB_ERROR_NO_DEVICE) {
1640 SHOW_PROGRESS(output," Device seems to have vanished after reading. Good.\n");
1641 } else
1642 SHOW_PROGRESS(output," Response reading got error %d\n", ret);
1643 return ret;
1647 void release_usb_device(int __attribute__((unused)) dummy) {
1648 SHOW_PROGRESS(output,"Program cancelled by system. Bye.\n\n");
1649 if (devh) {
1650 usb_release_interface(devh, Interface);
1651 usb_close(devh);
1653 if (sysmode)
1654 closelog();
1655 exit(0);
1660 /* Iterates over busses and devices, counts the ones which match the given
1661 * parameters and returns the last one of them
1663 struct libusb_device* search_devices( int *numFound, int vendor, int product, char* productList, int targetClass, int configuration, int mode)
1665 char *listcopy=NULL, *token, buffer[2];
1666 int devClass;
1667 struct libusb_device* right_dev = NULL;
1668 struct libusb_device_handle *testdevh;
1669 struct libusb_device **devs;
1670 int i=0;
1672 /* only target class given, target vendor and product assumed unchanged */
1673 if ( targetClass && !(vendor || product) ) {
1674 vendor = DefaultVendor;
1675 product = DefaultProduct;
1677 *numFound = 0;
1679 /* Sanity check */
1680 if (!vendor || (!product && productList == '\0') )
1681 return NULL;
1683 if (productList != '\0')
1684 listcopy = malloc(strlen(productList)+1);
1686 if (libusb_get_device_list(ctx, &devs) < 0) {
1687 perror("failed to access USB");
1688 return 0;
1691 while ((dev = devs[i++]) != NULL) {
1692 struct libusb_device_descriptor descriptor;
1693 libusb_get_device_descriptor(dev, &descriptor);
1694 int idVendor = descriptor.idVendor;
1695 int idProduct = descriptor.idProduct;
1697 if (mode == SEARCH_BUSDEV) {
1698 if ((libusb_get_bus_number(dev) != busnum) ||
1699 (libusb_get_device_address(dev) != devnum))
1700 continue;
1701 else
1702 SHOW_PROGRESS(output," bus/device number matched\n");
1705 if (verbose)
1706 fprintf (output," searching devices, found USB ID %04x:%04x\n",
1707 idVendor, idProduct);
1708 if (idVendor != vendor)
1709 continue;
1710 if (verbose)
1711 fprintf (output," found matching vendor ID\n");
1712 // product list given
1713 if ( strlen(productList) ) {
1714 strcpy(listcopy, productList);
1715 token = strtok(listcopy, ",");
1716 while (token != NULL) {
1717 if (strlen(token) != 4) {
1718 SHOW_PROGRESS(output,"Error: entry in product ID list has wrong length: %s. Ignoring\n", token);
1719 goto NextToken;
1721 if ( hexstr2bin(token, buffer, strlen(token)/2) == -1) {
1722 SHOW_PROGRESS(output,"Error: entry in product ID list is not a hex string: %s. Ignoring\n", token);
1723 goto NextToken;
1725 product = 0;
1726 product += (unsigned char)buffer[0];
1727 product <<= 8;
1728 product += (unsigned char)buffer[1];
1729 if (product == idProduct) {
1730 if (verbose)
1731 fprintf (output," found matching product ID from list\n");
1732 (*numFound)++;
1733 if (busnum == -1)
1734 right_dev = dev;
1735 else
1736 if (libusb_get_device_address(dev) >= devnum && libusb_get_bus_number(dev) == busnum) {
1737 right_dev = dev;
1738 TargetProduct = idProduct;
1739 break;
1742 NextToken:
1743 token = strtok(NULL, ",");
1745 /* Product ID is given */
1746 } else
1747 if (product == idProduct) {
1748 SHOW_PROGRESS(output," found matching product ID\n");
1749 if (targetClass == 0 && configuration < 1) {
1750 (*numFound)++;
1751 SHOW_PROGRESS(output," adding device\n");
1752 right_dev = dev;
1753 } else {
1754 if (targetClass != 0) {
1755 struct libusb_device_descriptor descriptor;
1756 libusb_get_device_descriptor(dev, &descriptor);
1757 devClass = descriptor.bDeviceClass;
1758 struct libusb_config_descriptor *config;
1759 libusb_get_config_descriptor(dev, 0, &config);
1760 int ifaceClass = config->interface[0].altsetting[0].bInterfaceClass;
1761 libusb_free_config_descriptor(config);
1763 if (devClass == 0)
1764 devClass = ifaceClass;
1765 else
1766 /* Check for some quirky devices */
1767 if (devClass != ifaceClass)
1768 devClass = ifaceClass;
1769 if (devClass == targetClass) {
1770 if (verbose)
1771 fprintf (output," target class %02x matching\n", targetClass);
1772 if (mode == SEARCH_TARGET) {
1773 (*numFound)++;
1774 right_dev = dev;
1775 if (verbose)
1776 fprintf (output," adding device\n");
1777 } else
1778 if (verbose)
1779 fprintf (output," not adding device\n");
1780 } else {
1781 if (verbose)
1782 fprintf (output," target class %02x not matching\n", targetClass);
1783 if (mode == SEARCH_DEFAULT || mode == SEARCH_BUSDEV) {
1784 (*numFound)++;
1785 right_dev = dev;
1786 if (verbose)
1787 fprintf (output," adding device\n");
1790 } else {
1791 // check configuration (only if no target class given)
1792 libusb_open(dev, &testdevh);
1793 int testconfig = get_current_configuration(testdevh);
1794 if (testconfig != configuration) {
1795 if (verbose)
1796 fprintf (output," device configuration %d not matching parameter\n", testconfig);
1797 (*numFound)++;
1798 right_dev = dev;
1799 if (verbose)
1800 fprintf (output," adding device\n");
1801 } else
1802 if (verbose)
1803 fprintf (output," not adding device, target configuration already set\n");
1808 if (listcopy != NULL)
1809 free(listcopy);
1810 return right_dev;
1814 #define USB_DIR_OUT 0x00
1815 #define USB_DIR_IN 0x80
1817 /* Autodetect bulk endpoints (ab) */
1819 int find_first_bulk_output_endpoint(struct libusb_device *dev)
1821 int i;
1822 struct libusb_config_descriptor *config;
1823 libusb_get_config_descriptor(dev, 0, &config);
1824 const struct libusb_interface_descriptor *alt = &(config[0].interface[0].altsetting[0]);
1825 const struct libusb_endpoint_descriptor *ep;
1827 for(i=0;i < alt->bNumEndpoints;i++) {
1828 ep=&(alt->endpoint[i]);
1829 if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
1830 ( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT ) ) {
1831 return ep->bEndpointAddress;
1834 libusb_free_config_descriptor(config);
1836 return 0;
1840 int find_first_bulk_input_endpoint(struct libusb_device *dev)
1842 int i;
1843 struct libusb_config_descriptor *config;
1844 libusb_get_config_descriptor(dev, 0, &config);
1845 const struct libusb_interface_descriptor *alt = &(config[0].interface[0].altsetting[0]);
1846 const struct libusb_endpoint_descriptor *ep;
1847 for(i=0;i < alt->bNumEndpoints;i++) {
1848 ep=&(alt->endpoint[i]);
1849 if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
1850 ( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN ) ) {
1851 return ep->bEndpointAddress;
1854 libusb_free_config_descriptor(config);
1856 return 0;
1859 int get_current_configuration(struct libusb_device_handle* devh)
1861 int ret;
1863 SHOW_PROGRESS(output,"Getting the current device configuration ...\n");
1864 ret = usb_control_msg(devh, USB_DIR_IN + USB_TYPE_STANDARD + USB_RECIP_DEVICE, USB_REQ_GET_CONFIGURATION, 0, 0, buffer, 1, 1000);
1865 if (ret < 0) {
1866 // There are quirky devices which fail to respond properly to this command
1867 fprintf(stderr, "Error getting the current configuration (error %d). Assuming configuration 1.\n", ret);
1868 if (Configuration) {
1869 fprintf(stderr, " No configuration setting possible for this device.\n");
1870 Configuration = 0;
1872 return 1;
1873 } else {
1874 SHOW_PROGRESS(output," OK, got current device configuration (%d)\n", buffer[0]);
1875 return buffer[0];
1879 int get_interface_class(struct libusb_config_descriptor *cfg, int ifcNumber)
1881 int i;
1883 for (i=0; i<cfg->bNumInterfaces; i++) {
1884 // SHOW_PROGRESS(output,"Test: looking at ifc %d, class is %d\n",i,cfg->interface[i].altsetting[0].bInterfaceClass);
1885 if (cfg->interface[i].altsetting[0].bInterfaceNumber == ifcNumber)
1886 return cfg->interface[i].altsetting[0].bInterfaceClass;
1889 return -1;
1892 /* Parameter parsing */
1894 char* ReadParseParam(const char* FileName, char *VariableName)
1896 static int numLines = 0;
1897 static char* ConfigBuffer[MAXLINES];
1899 char *VarName, *Comment=NULL, *Equal=NULL;
1900 char *FirstQuote, *LastQuote, *P1, *P2;
1901 int Line=0;
1902 unsigned Len=0, Pos=0;
1903 char Str[LINE_DIM], *token, *configPos;
1904 FILE *file = NULL;
1906 // Reading and storing input during the first call
1907 if (numLines==0) {
1908 if (strncmp(FileName,"##",2) == 0) {
1909 if (verbose) fprintf(output,"\nReading long config from command line\n");
1910 // "Embedded" configuration data
1911 configPos = (char*)FileName;
1912 token = strtok(configPos, "\n");
1913 strncpy(Str,token,LINE_DIM-1);
1914 } else {
1915 if (strcmp(FileName, "stdin")==0) {
1916 if (verbose) fprintf(output,"\nReading long config from stdin\n");
1917 file = stdin;
1918 } else {
1919 if (verbose) fprintf(output,"\nReading config file: %s\n", FileName);
1920 file=fopen(FileName, "r");
1922 if (file==NULL) {
1923 fprintf(stderr, "Error: Could not find file %s\n\n", FileName);
1924 exit(1);
1925 } else {
1926 token = fgets(Str, LINE_DIM-1, file);
1929 while (token != NULL && numLines < MAXLINES) {
1930 // Line++;
1931 Len=strlen(Str);
1932 if (Len==0)
1933 goto NextLine;
1934 if (Str[Len-1]=='\n' or Str[Len-1]=='\r')
1935 Str[--Len]='\0';
1936 Equal = strchr (Str, '='); // search for equal sign
1937 Pos = strcspn (Str, ";#!"); // search for comment
1938 Comment = (Pos==Len) ? NULL : Str+Pos;
1939 if (Equal==NULL or ( Comment!=NULL and Comment<=Equal))
1940 goto NextLine; // Comment or irrelevant, don't save
1941 Len=strlen(Str)+1;
1942 ConfigBuffer[numLines] = malloc(Len*sizeof(char));
1943 strcpy(ConfigBuffer[numLines],Str);
1944 numLines++;
1945 NextLine:
1946 if (file == NULL) {
1947 token = strtok(NULL, "\n");
1948 if (token != NULL)
1949 strncpy(Str,token,LINE_DIM-1);
1950 } else
1951 token = fgets(Str, LINE_DIM-1, file);
1953 if (file != NULL)
1954 fclose(file);
1957 // Now checking for parameters
1958 Line=0;
1959 while (Line < numLines) {
1960 strcpy(Str,ConfigBuffer[Line]);
1961 Equal = strchr (Str, '='); // search for equal sign
1962 *Equal++ = '\0';
1964 // String
1965 FirstQuote=strchr (Equal, '"'); // search for double quote char
1966 LastQuote=strrchr (Equal, '"');
1967 if (FirstQuote!=NULL) {
1968 if (LastQuote==NULL) {
1969 fprintf(stderr, "Error reading parameters from file %s - Missing end quote:\n%s\n", FileName, Str);
1970 goto Next;
1972 *FirstQuote=*LastQuote='\0';
1973 Equal=FirstQuote+1;
1976 // removes leading/trailing spaces
1977 Pos=strspn (Str, " \t");
1978 if (Pos==strlen(Str)) {
1979 fprintf(stderr, "Error reading parameters from file %s - Missing variable name:\n%s\n", FileName, Str);
1980 goto Next; // No function name
1982 while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '\t'))!=NULL)
1983 if (P1!=NULL) *P1='\0';
1984 else if (P2!=NULL) *P2='\0';
1985 VarName=Str+Pos;
1987 Pos=strspn (Equal, " \t");
1988 if (Pos==strlen(Equal)) {
1989 fprintf(stderr, "Error reading parameter from file %s - Missing value:\n%s\n", FileName, Str);
1990 goto Next; // No function name
1992 Equal+=Pos;
1994 if (strcmp(VarName, VariableName)==0) { // Found it
1995 return Equal;
1997 Next:
1998 Line++;
2001 return NULL;
2005 int hex2num(char c)
2007 if (c >= '0' && c <= '9')
2008 return c - '0';
2009 if (c >= 'a' && c <= 'f')
2010 return c - 'a' + 10;
2011 if (c >= 'A' && c <= 'F')
2012 return c - 'A' + 10;
2013 return -1;
2017 int hex2byte(const char *hex)
2019 int a, b;
2020 a = hex2num(*hex++);
2021 if (a < 0)
2022 return -1;
2023 b = hex2num(*hex++);
2024 if (b < 0)
2025 return -1;
2026 return (a << 4) | b;
2029 int hexstr2bin(const char *hex, char *buffer, int len)
2031 int i;
2032 int a;
2033 const char *ipos = hex;
2034 char *opos = buffer;
2036 for (i = 0; i < len; i++) {
2037 a = hex2byte(ipos);
2038 if (a < 0)
2039 return -1;
2040 *opos++ = a;
2041 ipos += 2;
2043 return 0;
2046 void printVersion()
2048 char* version = VERSION;
2049 printf("\n * usb_modeswitch: handle USB devices with multiple modes\n"
2050 " * Version %s (C) Josua Dietze 2012\n"
2051 " * Based on libusb0 (0.1.12 and above)\n\n"
2052 " ! PLEASE REPORT NEW CONFIGURATIONS !\n\n", version);
2055 void printHelp()
2057 fprintf (output,"\nUsage: usb_modeswitch [<params>] [-c filename]\n\n"
2058 " -h, --help this help\n"
2059 " -e, --version print version information and exit\n"
2060 " -j, --find-mbim return config no. with MBIM interface, exit\n"
2061 " -v, --default-vendor NUM vendor ID of original mode (mandatory)\n"
2062 " -p, --default-product NUM product ID of original mode (mandatory)\n"
2063 " -V, --target-vendor NUM target mode vendor ID (optional)\n"
2064 " -P, --target-product NUM target mode product ID (optional)\n"
2065 " -C, --target-class NUM target mode device class (optional)\n"
2066 " -b, --busnum NUM system bus number of device (for hard ID)\n"
2067 " -g, --devnum NUM system device number (for hard ID)\n"
2068 " -m, --message-endpoint NUM direct the message transfer there (optional)\n"
2069 " -M, --message-content <msg> message to send (hex number as string)\n"
2070 " -2 <msg>, -3 <msg> additional messages to send (-n recommended)\n"
2071 " -n, --need-response read response to the message transfer (CSW)\n"
2072 " -r, --response-endpoint NUM read response from there (optional)\n"
2073 " -d, --detach-only detach the active driver, no further action\n"
2074 " -H, --huawei-mode apply a special procedure\n"
2075 " -S, --sierra-mode apply a special procedure\n"
2076 " -O, --sony-mode apply a special procedure\n"
2077 " -G, --gct-mode apply a special procedure\n"
2078 " -N, --sequans-mode apply a special procedure\n"
2079 " -A, --mobileaction-mode apply a special procedure\n"
2080 " -T, --kobil-mode apply a special procedure\n"
2081 " -L, --cisco-mode apply a special procedure\n"
2082 " -B, --qisda-mode apply a special procedure\n"
2083 " -E, --quanta-mode apply a special procedure\n"
2084 " -R, --reset-usb reset the device after all other actions\n"
2085 " -Q, --quiet don't show progress or error messages\n"
2086 " -W, --verbose print all settings and debug output\n"
2087 " -D, --sysmode specific result and syslog message\n"
2088 " -s, --success <seconds> switching result check with timeout\n"
2089 " -I, --no-inquire do not get SCSI attributes (default on)\n\n"
2090 " -c, --config-file <filename> load long configuration from file\n\n"
2091 " -t, --stdinput read long configuration from stdin\n\n"
2092 " -f, --long-config <text> get long configuration from string\n\n"
2093 " -i, --interface NUM select initial USB interface (default 0)\n"
2094 " -u, --configuration NUM select USB configuration\n"
2095 " -a, --altsetting NUM select alternative USB interface setting\n\n");