usb_modeswitch ver. 2.3.0 with data package 2016-01-12
[tomato.git] / release / src / router / usbmodeswitch / usb_modeswitch.c
blobd38fb0684030185bd89d1554beb4daeb72921314
1 /*
2 Mode switching tool for controlling mode of 'multi-state' USB devices
3 Version 2.3.0, 2016/01/12
5 Copyright (C) 2007 - 2016 Josua Dietze (mail to "digidietze" 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 code 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 "2.3.0"
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"
62 // Little helpers
64 int usb_bulk_io(struct libusb_device_handle *handle, int ep, unsigned char *bytes,
65 int size, int timeout)
67 int actual_length;
68 int r;
69 // usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
70 r = libusb_bulk_transfer(handle, ep & 0xff, bytes, size,
71 &actual_length, timeout);
73 /* if we timed out but did transfer some data, report as successful short
74 * read. FIXME: is this how libusb-0.1 works? */
75 if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
76 return actual_length;
78 return r;
82 static int usb_interrupt_io(libusb_device_handle *handle, int ep, unsigned char *bytes,
83 int size, int timeout)
85 int actual_length;
86 int r;
87 // usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
88 r = libusb_interrupt_transfer(handle, ep & 0xff, bytes, size,
89 &actual_length, timeout);
91 /* if we timed out but did transfer some data, report as successful short
92 * read. FIXME: is this how libusb-0.1 works? */
93 if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
94 return actual_length;
96 return (r);
100 #define LINE_DIM 1024
101 #define MAXLINES 50
102 #define BUF_SIZE 4096
103 #define DESCR_MAX 129
105 #define SEARCH_DEFAULT 0
106 #define SEARCH_TARGET 1
107 #define SEARCH_BUSDEV 2
109 #define SWITCH_CONFIG_MAXTRIES 5
111 #define SHOW_PROGRESS if (show_progress) fprintf
113 char *TempPP=NULL;
115 static struct libusb_context *ctx = NULL;
116 static struct libusb_device *dev = NULL;
117 static struct libusb_device_handle *devh = NULL;
118 static struct libusb_config_descriptor *active_config = NULL;
120 int DefaultVendor=0, DefaultProduct=0, TargetVendor=0, TargetProduct=-1, TargetClass=0;
121 int MessageEndpoint=0, ResponseEndpoint=0, ReleaseDelay=0;
122 int targetDeviceCount=0, searchMode;
123 int devnum=-1, busnum=-1;
125 unsigned int ModeMap = 0;
126 #define DETACHONLY_MODE 0x00000001
127 #define HUAWEI_MODE 0x00000002
128 #define SIERRA_MODE 0x00000004
129 #define SONY_MODE 0x00000008
130 #define GCT_MODE 0x00000010
131 #define KOBIL_MODE 0x00000020
132 #define SEQUANS_MODE 0x00000040
133 #define MOBILEACTION_MODE 0x00000080
134 #define CISCO_MODE 0x00000100
135 #define QISDA_MODE 0x00000200
136 #define QUANTA_MODE 0x00000400
137 #define BLACKBERRY_MODE 0x00000800
138 #define PANTECH_MODE 0x00001000
139 #define HUAWEINEW_MODE 0x00002000
140 #define OPTION_MODE 0x00004000
143 int PantechMode=0;
144 char verbose=0, show_progress=1, ResetUSB=0, CheckSuccess=0, config_read=0;
145 char NoDriverLoading=0, sysmode=0, mbim=0;
146 char StandardEject=0;
148 char MessageContent[LINE_DIM];
149 char MessageContent2[LINE_DIM];
150 char MessageContent3[LINE_DIM];
151 char TargetProductList[LINE_DIM];
152 char DefaultProductList[5];
153 unsigned char ByteString[LINE_DIM/2];
154 unsigned char buffer[BUF_SIZE];
156 FILE *output;
159 /* Settable Interface and Configuration (for debugging mostly) (jmw) */
160 int Interface = -1, Configuration = 0, AltSetting = -1;
163 static struct option long_options[] = {
164 {"help", no_argument, 0, 'h'},
165 {"version", no_argument, 0, 'e'},
166 {"default-vendor", required_argument, 0, 'v'},
167 {"default-product", required_argument, 0, 'p'},
168 {"target-vendor", required_argument, 0, 'V'},
169 {"target-product", required_argument, 0, 'P'},
170 {"target-class", required_argument, 0, 'C'},
171 {"message-endpoint", required_argument, 0, 'm'},
172 {"message-content", required_argument, 0, 'M'},
173 {"message-content2", required_argument, 0, '2'},
174 {"message-content3", required_argument, 0, '3'},
175 {"release-delay", required_argument, 0, 'w'},
176 {"response-endpoint", required_argument, 0, 'r'},
177 {"bus-num", required_argument, 0, 'b'},
178 {"device-num", required_argument, 0, 'g'},
179 {"detach-only", no_argument, 0, 'd'},
180 {"huawei-mode", no_argument, 0, 'H'},
181 {"huawei-new-mode", no_argument, 0, 'J'},
182 {"sierra-mode", no_argument, 0, 'S'},
183 {"sony-mode", no_argument, 0, 'O'},
184 {"qisda-mode", no_argument, 0, 'B'},
185 {"quanta-mode", no_argument, 0, 'E'},
186 {"kobil-mode", no_argument, 0, 'T'},
187 {"gct-mode", no_argument, 0, 'G'},
188 {"sequans-mode", no_argument, 0, 'N'},
189 {"mobileaction-mode", no_argument, 0, 'A'},
190 {"cisco-mode", no_argument, 0, 'L'},
191 {"blackberry-mode", no_argument, 0, 'Z'},
192 {"option-mode", no_argument, 0, 'U'},
193 {"pantech-mode", required_argument, 0, 'F'},
194 {"std-eject", no_argument, 0, 'K'},
195 {"need-response", no_argument, 0, 'n'},
196 {"reset-usb", no_argument, 0, 'R'},
197 {"config-file", required_argument, 0, 'c'},
198 {"verbose", no_argument, 0, 'W'},
199 {"quiet", no_argument, 0, 'Q'},
200 {"sysmode", no_argument, 0, 'D'},
201 {"inquire", no_argument, 0, 'I'},
202 {"stdinput", no_argument, 0, 't'},
203 {"find-mbim", no_argument, 0, 'j'},
204 {"long-config", required_argument, 0, 'f'},
205 {"check-success", required_argument, 0, 's'},
206 {"interface", required_argument, 0, 'i'},
207 {"configuration", required_argument, 0, 'u'},
208 {"altsetting", required_argument, 0, 'a'},
209 {0, 0, 0, 0}
213 void readConfigFile(const char *configFilename)
215 ParseParamHex(configFilename, TargetVendor);
216 ParseParamHex(configFilename, TargetProduct);
217 ParseParamString(configFilename, TargetProductList);
218 ParseParamHex(configFilename, TargetClass);
219 ParseParamHex(configFilename, DefaultVendor);
220 ParseParamHex(configFilename, DefaultProduct);
221 ParseParamBoolMap(configFilename, DetachStorageOnly, ModeMap, DETACHONLY_MODE);
222 ParseParamBoolMap(configFilename, HuaweiMode, ModeMap, HUAWEI_MODE);
223 ParseParamBoolMap(configFilename, HuaweiNewMode, ModeMap, HUAWEINEW_MODE);
224 ParseParamBoolMap(configFilename, SierraMode, ModeMap, SIERRA_MODE);
225 ParseParamBoolMap(configFilename, SonyMode, ModeMap, SONY_MODE);
226 ParseParamBoolMap(configFilename, GCTMode, ModeMap, GCT_MODE);
227 ParseParamBoolMap(configFilename, KobilMode, ModeMap, KOBIL_MODE);
228 ParseParamBoolMap(configFilename, SequansMode, ModeMap, SEQUANS_MODE);
229 ParseParamBoolMap(configFilename, MobileActionMode, ModeMap, MOBILEACTION_MODE);
230 ParseParamBoolMap(configFilename, CiscoMode, ModeMap, CISCO_MODE);
231 ParseParamBoolMap(configFilename, QisdaMode, ModeMap, QISDA_MODE);
232 ParseParamBoolMap(configFilename, QuantaMode, ModeMap, QUANTA_MODE);
233 ParseParamBoolMap(configFilename, OptionMode, ModeMap, OPTION_MODE);
234 ParseParamBoolMap(configFilename, BlackberryMode, ModeMap, BLACKBERRY_MODE);
235 ParseParamInt(configFilename, PantechMode);
236 if (PantechMode)
237 ModeMap |= PANTECH_MODE;
238 ParseParamBool(configFilename, StandardEject);
239 ParseParamBool(configFilename, NoDriverLoading);
240 ParseParamHex(configFilename, MessageEndpoint);
241 ParseParamString(configFilename, MessageContent);
242 ParseParamString(configFilename, MessageContent2);
243 ParseParamString(configFilename, MessageContent3);
244 ParseParamInt(configFilename, ReleaseDelay);
245 ParseParamHex(configFilename, ResponseEndpoint);
246 ParseParamHex(configFilename, ResetUSB);
247 ParseParamInt(configFilename, CheckSuccess);
248 ParseParamHex(configFilename, Interface);
249 ParseParamHex(configFilename, Configuration);
250 ParseParamHex(configFilename, AltSetting);
252 /* TargetProductList has priority over TargetProduct */
253 if (TargetProduct != -1 && TargetProductList[0] != '\0') {
254 TargetProduct = -1;
255 SHOW_PROGRESS(output,"Warning: TargetProductList overrides TargetProduct!\n");
258 config_read = 1;
262 void printConfig()
264 if ( DefaultVendor )
265 fprintf (output,"DefaultVendor= 0x%04x\n", DefaultVendor);
266 if ( DefaultProduct )
267 fprintf (output,"DefaultProduct= 0x%04x\n", DefaultProduct);
268 if ( TargetVendor )
269 fprintf (output,"TargetVendor= 0x%04x\n", TargetVendor);
270 if ( TargetProduct > -1 )
271 fprintf (output,"TargetProduct= 0x%04x\n", TargetProduct);
272 if ( TargetClass )
273 fprintf (output,"TargetClass= 0x%02x\n", TargetClass);
274 if ( strlen(TargetProductList) )
275 fprintf (output,"TargetProductList=\"%s\"\n", TargetProductList);
276 if (StandardEject)
277 fprintf (output,"\nStandardEject=1\n");
278 if (ModeMap & DETACHONLY_MODE)
279 fprintf (output,"\nDetachStorageOnly=1\n");
280 if (ModeMap & HUAWEI_MODE)
281 fprintf (output,"HuaweiMode=1\n");
282 if (ModeMap & HUAWEINEW_MODE)
283 fprintf (output,"HuaweiNewMode=1\n");
284 if (ModeMap & SIERRA_MODE)
285 fprintf (output,"SierraMode=1\n");
286 if (ModeMap & SONY_MODE)
287 fprintf (output,"SonyMode=1\n");
288 if (ModeMap & QISDA_MODE)
289 fprintf (output,"QisdaMode=1\n");
290 if (ModeMap & QUANTA_MODE)
291 fprintf (output,"QuantaMode=1\n");
292 if (ModeMap & GCT_MODE)
293 fprintf (output,"GCTMode=1\n");
294 if (ModeMap & KOBIL_MODE)
295 fprintf (output,"KobilMode=1\n");
296 if (ModeMap & SEQUANS_MODE)
297 fprintf (output,"SequansMode=1\n");
298 if (ModeMap & MOBILEACTION_MODE)
299 fprintf (output,"MobileActionMode=1\n");
300 if (ModeMap & CISCO_MODE)
301 fprintf (output,"CiscoMode=1\n");
302 if (ModeMap & BLACKBERRY_MODE)
303 fprintf (output,"BlackberryMode=1\n");
304 if (ModeMap & OPTION_MODE)
305 fprintf (output,"OptionMode=1\n");
306 if (ModeMap & PANTECH_MODE)
307 fprintf (output,"PantechMode=1\n");
308 if ( MessageEndpoint )
309 fprintf (output,"MessageEndpoint=0x%02x\n", MessageEndpoint);
310 if ( strlen(MessageContent) )
311 fprintf (output,"MessageContent=\"%s\"\n", MessageContent);
312 if ( strlen(MessageContent2) )
313 fprintf (output,"MessageContent2=\"%s\"\n", MessageContent2);
314 if ( strlen(MessageContent3) )
315 fprintf (output,"MessageContent3=\"%s\"\n", MessageContent3);
316 if ( ResponseEndpoint )
317 fprintf (output,"ResponseEndpoint=0x%02x\n", ResponseEndpoint);
318 if ( Interface > -1 )
319 fprintf (output,"Interface=0x%02x\n", Interface);
320 if ( Configuration > 0 )
321 fprintf (output,"Configuration=0x%02x\n", Configuration);
322 if ( AltSetting > -1 )
323 fprintf (output,"AltSetting=0x%02x\n", AltSetting);
324 if ( CheckSuccess )
325 fprintf (output,"Success check enabled, max. wait time %d seconds\n", CheckSuccess);
326 if ( sysmode )
327 fprintf (output,"System integration mode enabled\n");
331 int readArguments(int argc, char **argv)
333 int c, option_index = 0, count=0;
334 char *longConfig = NULL;
335 if (argc==1)
337 printHelp();
338 printVersion();
339 exit(1);
342 while (1)
344 c = getopt_long (argc, argv, "hejWQDndKHJSOBEGTNALZUF:RItv:p:V:P:C:m:M:2:3:w:r:c:i:u:a:s:f:b:g:",
345 long_options, &option_index);
347 /* Detect the end of the options. */
348 if (c == -1)
349 break;
350 count++;
351 switch (c)
353 case 'R': ResetUSB = 1; break;
354 case 'v': DefaultVendor = strtol(optarg, NULL, 16); break;
355 case 'p': DefaultProduct = strtol(optarg, NULL, 16); break;
356 case 'V': TargetVendor = strtol(optarg, NULL, 16); break;
357 case 'P': TargetProduct = strtol(optarg, NULL, 16); break;
358 case 'C': TargetClass = strtol(optarg, NULL, 16); break;
359 case 'm': MessageEndpoint = strtol(optarg, NULL, 16); break;
360 case 'M': strncpy(MessageContent, optarg, LINE_DIM); break;
361 case '2': strncpy(MessageContent2, optarg, LINE_DIM); break;
362 case '3': strncpy(MessageContent3, optarg, LINE_DIM); break;
363 case 'w': ReleaseDelay = strtol(optarg, NULL, 10); break;
364 case 'n': break;
365 case 'r': ResponseEndpoint = strtol(optarg, NULL, 16); break;
366 case 'K': StandardEject = 1; break;
367 case 'd': ModeMap = ModeMap + DETACHONLY_MODE; break;
368 case 'H': ModeMap = ModeMap + HUAWEI_MODE; break;
369 case 'J': ModeMap = ModeMap + HUAWEINEW_MODE; break;
370 case 'S': ModeMap = ModeMap + SIERRA_MODE; break;
371 case 'O': ModeMap = ModeMap + SONY_MODE; break;; break;
372 case 'B': ModeMap = ModeMap + QISDA_MODE; break;
373 case 'E': ModeMap = ModeMap + QUANTA_MODE; break;
374 case 'G': ModeMap = ModeMap + GCT_MODE; break;
375 case 'T': ModeMap = ModeMap + KOBIL_MODE; break;
376 case 'N': ModeMap = ModeMap + SEQUANS_MODE; break;
377 case 'A': ModeMap = ModeMap + MOBILEACTION_MODE; break;
378 case 'L': ModeMap = ModeMap + CISCO_MODE; break;
379 case 'Z': ModeMap = ModeMap + BLACKBERRY_MODE; break;
380 case 'U': ModeMap = ModeMap + OPTION_MODE; break;
381 case 'F': ModeMap = ModeMap + PANTECH_MODE;
382 PantechMode = strtol(optarg, NULL, 10); break;
383 case 'c': readConfigFile(optarg); break;
384 case 't': readConfigFile("stdin"); break;
385 case 'W': verbose = 1; show_progress = 1; count--; break;
386 case 'Q': show_progress = 0; verbose = 0; count--; break;
387 case 'D': sysmode = 1; count--; break;
388 case 's': CheckSuccess = strtol(optarg, NULL, 10); count--; break;
389 case 'I': break;
390 case 'b': busnum = strtol(optarg, NULL, 10); break;
391 case 'g': devnum = strtol(optarg, NULL, 10); break;
393 case 'i': Interface = strtol(optarg, NULL, 16); break;
394 case 'u': Configuration = strtol(optarg, NULL, 16); break;
395 case 'a': AltSetting = strtol(optarg, NULL, 16); break;
396 case 'j': mbim = 1; break;
398 case 'f':
399 longConfig = malloc(strlen(optarg)+5);
400 strcpy(longConfig,"##\n");
401 strcat(longConfig,optarg);
402 strcat(longConfig,"\n");
403 readConfigFile(longConfig);
404 free(longConfig);
405 break;
407 case 'e':
408 printVersion();
409 exit(0);
410 break;
411 case 'h':
412 printVersion();
413 printHelp();
414 exit(0);
415 break;
417 default: /* Unsupported - error message has already been printed */
418 fprintf (output,"\n");
419 printHelp();
420 exit(1);
423 return count;
427 int main(int argc, char **argv)
429 int ret=0, numDefaults=0, sonySuccess=0;
430 int currentConfigVal=0, defaultClass=0, interfaceClass=0;
431 struct libusb_device_descriptor descriptor;
432 enum libusb_error libusbError;
434 /* Make sure we have empty strings even if not set by config */
435 TargetProductList[0] = '\0';
436 MessageContent[0] = '\0';
437 MessageContent2[0] = '\0';
438 MessageContent3[0] = '\0';
439 DefaultProductList[0] = '\0';
441 /* Useful for debugging during boot */
442 // output=fopen("/dev/console", "w");
443 output=stdout;
445 signal(SIGTERM, release_usb_device);
448 * Parameter parsing, USB preparation/diagnosis, plausibility checks
451 /* Check command arguments, use params instead of config file when given */
452 switch (readArguments(argc, argv)) {
453 case 0: /* no argument or -W, -q or -s */
454 break;
455 default: /* one or more arguments except -W, -q or -s */
456 if (!config_read) /* if arguments contain -c, the config file was already processed */
457 if (verbose) fprintf(output,"Take all parameters from the command line\n\n");
460 if (verbose) {
461 printVersion();
462 printConfig();
463 fprintf(output,"\n");
466 /* Some sanity checks. The default IDs are mandatory */
467 if (!(DefaultVendor && DefaultProduct)) {
468 SHOW_PROGRESS(output,"No default vendor/product ID given. Abort\n\n");
469 exit(1);
472 if (strlen(MessageContent)) {
473 if (strlen(MessageContent) % 2 != 0) {
474 fprintf(stderr, "Error: MessageContent hex string has uneven length. Abort\n\n");
475 exit(1);
477 if ( hexstr2bin(MessageContent, ByteString, strlen(MessageContent)/2) == -1) {
478 fprintf(stderr, "Error: MessageContent %s\n is not a hex string. Abort\n\n",
479 MessageContent);
481 exit(1);
485 if (devnum == -1) {
486 searchMode = SEARCH_DEFAULT;
487 } else {
488 SHOW_PROGRESS(output,"Use given bus/device number: %03d/%03d ...\n", busnum, devnum);
489 searchMode = SEARCH_BUSDEV;
492 if (show_progress)
493 if (CheckSuccess && !(TargetVendor || TargetProduct > -1 || TargetProductList[0] != '\0')
494 && !TargetClass)
496 fprintf(output,"Note: No target parameter given; success check limited\n");
498 if (TargetProduct > -1 && TargetProductList[0] == '\0') {
499 sprintf(TargetProductList,"%04x",TargetProduct);
500 TargetProduct = -1;
503 /* libusb initialization */
504 if ((libusbError = libusb_init(&ctx)) != LIBUSB_SUCCESS) {
505 fprintf(stderr, "Error: Failed to initialize libusb. \n\n");
506 exit(1);
509 if (verbose)
510 libusb_set_debug(ctx, 3);
512 if (mbim) {
513 printf("%d\n", findMBIMConfig(DefaultVendor, DefaultProduct, searchMode) );
514 exit(0);
517 /* Count existing target devices, remember for success check */
518 if (searchMode != SEARCH_BUSDEV && (TargetVendor || TargetClass)) {
519 SHOW_PROGRESS(output,"Look for target devices ...\n");
520 search_devices(&targetDeviceCount, TargetVendor, TargetProductList, TargetClass, 0,
521 SEARCH_TARGET);
523 if (targetDeviceCount) {
524 SHOW_PROGRESS(output," Found devices in target mode or class (%d)\n", targetDeviceCount);
525 } else
526 SHOW_PROGRESS(output," No devices in target mode or class found\n");
529 /* Count default devices, get the last one found */
530 SHOW_PROGRESS(output,"Look for default devices ...\n");
532 sprintf(DefaultProductList,"%04x",DefaultProduct);
533 dev = search_devices(&numDefaults, DefaultVendor, DefaultProductList, TargetClass,
534 Configuration, searchMode);
536 if (numDefaults) {
537 SHOW_PROGRESS(output," Found devices in default mode (%d)\n", numDefaults);
538 } else {
539 SHOW_PROGRESS(output," No devices in default mode found. Nothing to do. Bye!\n\n");
540 close_all();
541 exit(0);
544 if (dev == NULL) {
545 SHOW_PROGRESS(output," No bus/device match. Is device connected? Abort\n\n");
546 close_all();
547 exit(0);
548 } else {
549 if (devnum == -1) {
550 devnum = libusb_get_device_address(dev);
551 busnum = libusb_get_bus_number(dev);
552 SHOW_PROGRESS(output,"Access device %03d on bus %03d\n", devnum, busnum);
554 libusb_open(dev, &devh);
555 if (devh == NULL) {
556 SHOW_PROGRESS(output,"Error opening the device. Abort\n\n");
557 abortExit();
561 /* Get current configuration of default device, note value if Configuration
562 * parameter is set. Also sets active_config
564 currentConfigVal = get_current_config_value(dev);
565 if (Configuration > -1) {
566 SHOW_PROGRESS(output,"Current configuration number is %d\n", currentConfigVal);
567 } else
568 currentConfigVal = 0;
570 libusb_get_device_descriptor(dev, &descriptor);
571 defaultClass = descriptor.bDeviceClass;
572 if (Interface == -1)
573 Interface = active_config->interface[0].altsetting[0].bInterfaceNumber;
574 SHOW_PROGRESS(output,"Use interface number %d\n", Interface);
576 /* Get class of default device/interface */
577 interfaceClass = get_interface_class();
579 /* Check or get endpoints */
580 if (strlen(MessageContent) || StandardEject || ModeMap & CISCO_MODE
581 || ModeMap & HUAWEINEW_MODE || ModeMap & OPTION_MODE) {
583 if (!MessageEndpoint)
584 MessageEndpoint = find_first_bulk_endpoint(LIBUSB_ENDPOINT_OUT);
585 if (!ResponseEndpoint)
586 ResponseEndpoint = find_first_bulk_endpoint(LIBUSB_ENDPOINT_IN);
587 if (!MessageEndpoint) {
588 fprintf(stderr,"Error: message endpoint not given or found. Abort\n\n");
589 abortExit();
591 if (!ResponseEndpoint) {
592 fprintf(stderr,"Error: response endpoint not given or found. Abort\n\n");
593 abortExit();
595 SHOW_PROGRESS(output,"Use endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint,
596 ResponseEndpoint);
600 if (interfaceClass == -1) {
601 fprintf(stderr, "Error: Could not get class of interface %d. Does it exist? Abort\n\n",Interface);
602 abortExit();
605 if (defaultClass == 0)
606 defaultClass = interfaceClass;
607 else
608 if (interfaceClass == LIBUSB_CLASS_MASS_STORAGE && defaultClass != LIBUSB_CLASS_MASS_STORAGE
609 && defaultClass != 0xef && defaultClass != LIBUSB_CLASS_VENDOR_SPEC) {
611 /* Unexpected default class combined with differing interface class */
612 SHOW_PROGRESS(output,"Bogus Class/InterfaceClass: 0x%02x/0x08\n", defaultClass);
613 defaultClass = 8;
616 if (strlen(MessageContent) && strncmp("55534243",MessageContent,8) == 0)
617 if (defaultClass != 8) {
618 fprintf(stderr, "Error: can't use storage command in MessageContent with interface %d;\n"
619 " interface class is %d, expected 8. Abort\n\n", Interface, defaultClass);
620 abortExit();
623 if (show_progress) {
624 fprintf(output,"\nUSB description data (for identification)\n");
625 deviceDescription();
628 /* Special modes are exclusive, so check for illegal combinations.
629 * More than one bit set?
631 if ( ModeMap & (ModeMap-1) ) {
632 fprintf(output,"Multiple special modes selected; check configuration. Abort\n\n");
633 abortExit();
636 if ((strlen(MessageContent) || StandardEject) && ModeMap ) {
637 MessageContent[0] = '\0';
638 StandardEject = 0;
639 fprintf(output,"Warning: MessageContent/StandardEject ignored; can't combine with special mode\n");
642 if (StandardEject && (strlen(MessageContent2) || strlen(MessageContent3))) {
643 fprintf(output,"Warning: MessageContent2/3 ignored; only one allowed with StandardEject\n");
646 if ( !ModeMap && !strlen(MessageContent) && AltSetting == -1 && !Configuration && !StandardEject )
647 SHOW_PROGRESS(output,"Warning: no switching method given. See documentation\n");
650 * The switching actions
653 if (sysmode) {
654 openlog("usb_modeswitch", 0, LOG_SYSLOG);
655 syslog(LOG_NOTICE, "switch device %04x:%04x on %03d/%03d", DefaultVendor, DefaultProduct,
656 busnum, devnum);
660 if (ModeMap & DETACHONLY_MODE) {
661 SHOW_PROGRESS(output,"Detach storage driver as switching method ...\n");
662 ret = detachDriver();
663 if (ret == 2)
664 SHOW_PROGRESS(output," You may want to remove the storage driver manually\n");
667 if(ModeMap & HUAWEI_MODE) {
668 switchHuaweiMode();
670 if(ModeMap & SIERRA_MODE) {
671 switchSierraMode();
673 if(ModeMap & GCT_MODE) {
674 detachDriver();
675 switchGCTMode();
677 if(ModeMap & QISDA_MODE) {
678 switchQisdaMode();
680 if(ModeMap & KOBIL_MODE) {
681 detachDriver();
682 switchKobilMode();
684 if(ModeMap & QUANTA_MODE) {
685 switchQuantaMode();
687 if(ModeMap & SEQUANS_MODE) {
688 switchSequansMode();
690 if(ModeMap & MOBILEACTION_MODE) {
691 switchActionMode();
693 if(ModeMap & CISCO_MODE) {
694 detachDriver();
695 switchCiscoMode();
697 if(ModeMap & BLACKBERRY_MODE) {
698 detachDriver();
699 switchBlackberryMode();
701 if(ModeMap & PANTECH_MODE) {
702 detachDriver();
703 if (PantechMode > 1)
704 switchPantechMode();
705 else
706 SHOW_PROGRESS(output,"Waiting for auto-switch of Pantech modem ...\n");
708 if(ModeMap & SONY_MODE) {
709 if (CheckSuccess)
710 SHOW_PROGRESS(output,"Note: CheckSuccess ignored; Sony mode does separate checks\n");
711 CheckSuccess = 0; /* separate and implied success control */
712 sonySuccess = switchSonyMode();
715 if (StandardEject) {
716 SHOW_PROGRESS(output,"Sending standard EJECT sequence\n");
717 detachDriver();
718 if (MessageContent[0] != '\0')
719 strcpy(MessageContent3, MessageContent);
720 else
721 MessageContent3[0] = '\0';
723 strcpy(MessageContent,"5553424387654321000000000000061e000000000000000000000000000000");
724 strcpy(MessageContent2,"5553424397654321000000000000061b000000020000000000000000000000");
725 switchSendMessage();
726 } else if (ModeMap & HUAWEINEW_MODE) {
727 SHOW_PROGRESS(output,"Using standard Huawei switching message\n");
728 detachDriver();
729 strcpy(MessageContent,"55534243123456780000000000000011062000000101000100000000000000");
730 switchSendMessage();
731 } else if (ModeMap & OPTION_MODE) {
732 SHOW_PROGRESS(output,"Using standard Option switching message\n");
733 detachDriver();
734 // strcpy(MessageContent,"55534243123456780100000080000601000000000000000000000000000000");
735 strcpy(MessageContent,"55534243123456780000000000000601000000000000000000000000000000");
736 switchSendMessage();
737 } else if (strlen(MessageContent)) {
738 detachDriver();
739 switchSendMessage();
742 if (Configuration > 0) {
743 if (currentConfigVal != Configuration) {
744 if (switchConfiguration()) {
745 currentConfigVal = get_current_config_value(dev);
746 if (currentConfigVal == Configuration) {
747 SHOW_PROGRESS(output,"The configuration was set successfully\n");
748 } else {
749 SHOW_PROGRESS(output,"Changing the configuration has failed\n");
752 } else {
753 SHOW_PROGRESS(output,"Target configuration %d found. Do nothing\n", currentConfigVal);
757 if (AltSetting != -1) {
758 switchAltSetting();
761 /* No "removal" check if these are set */
762 if ((Configuration > 0 || AltSetting > -1) && !ResetUSB) {
763 libusb_close(devh);
764 devh = NULL;
767 if (ResetUSB) {
768 resetUSB();
769 devh = NULL;
772 if (searchMode == SEARCH_BUSDEV && sysmode) {
773 printf("ok:busdev\n");
774 close_all();
775 exit(0);
778 if (CheckSuccess) {
779 if (checkSuccess()) {
780 if (sysmode) {
781 if (NoDriverLoading)
782 printf("ok:\n");
783 else
784 if (TargetProduct < 1)
785 printf("ok:no_data\n");
786 else
787 printf("ok:%04x:%04x\n", TargetVendor, TargetProduct);
789 } else
790 if (sysmode)
791 printf("fail:\n");
792 } else {
793 if (ModeMap & SONY_MODE)
794 if (sonySuccess) {
795 if (sysmode) {
796 syslog(LOG_NOTICE, "switched S.E. MD400 to modem mode");
797 printf("ok:\n"); /* ACM device, no driver action */
799 SHOW_PROGRESS(output,"-> device should be stable now. Bye!\n\n");
800 } else {
801 if (sysmode)
802 printf("fail:\n");
803 SHOW_PROGRESS(output,"-> switching was probably not completed. Bye!\n\n");
805 else
806 SHOW_PROGRESS(output,"-> Run lsusb to note any changes. Bye!\n\n");
808 close_all();
809 exit(0);
813 /* Get descriptor strings if available (identification details) */
814 void deviceDescription ()
816 char imanufact[DESCR_MAX], iproduct[DESCR_MAX], iserial[DESCR_MAX];
817 int ret=0;
818 char* c;
819 memset (imanufact, ' ', DESCR_MAX);
820 memset (iproduct, ' ', DESCR_MAX);
821 memset (iserial, ' ', DESCR_MAX);
823 struct libusb_device_descriptor descriptor;
824 libusb_get_device_descriptor(dev, &descriptor);
826 int iManufacturer = descriptor.iManufacturer;
827 int iProduct = descriptor.iProduct;
828 int iSerialNumber = descriptor.iSerialNumber;
830 if (iManufacturer) {
831 ret = libusb_get_string_descriptor_ascii(devh, iManufacturer, (unsigned char *)imanufact, DESCR_MAX);
832 if (ret < 0) {
833 fprintf(stderr, "Error: could not get description string \"manufacturer\"\n");
834 strcpy(imanufact, "read error");
836 } else
837 strcpy(imanufact, "not provided");
838 c = strstr(imanufact, " ");
839 if (c)
840 memset((void*)c, '\0', 1);
842 if (iProduct) {
843 ret = libusb_get_string_descriptor_ascii(devh, iProduct, (unsigned char *)iproduct, DESCR_MAX);
844 if (ret < 0) {
845 fprintf(stderr, "Error: could not get description string \"product\"\n");
846 strcpy(iproduct, "read error");
848 } else
849 strcpy(iproduct, "not provided");
850 c = strstr(iproduct, " ");
851 if (c)
852 memset((void*)c, '\0', 1);
854 if (iSerialNumber) {
855 ret = libusb_get_string_descriptor_ascii(devh, iSerialNumber, (unsigned char *)iserial, DESCR_MAX);
856 if (ret < 0) {
857 fprintf(stderr, "Error: could not get description string \"serial number\"\n");
858 strcpy(iserial, "read error");
860 } else
861 strcpy(iserial, "not provided");
862 c = strstr(iserial, " ");
863 if (c)
864 memset((void*)c, '\0', 1);
865 fprintf(output,"-------------------------\n");
866 fprintf(output,"Manufacturer: %s\n", imanufact);
867 fprintf(output," Product: %s\n", iproduct);
868 fprintf(output," Serial No.: %s\n", iserial);
869 fprintf(output,"-------------------------\n");
873 /* Auxiliary function used by the wrapper */
874 int findMBIMConfig(int vendor, int product, int mode)
876 struct libusb_device **devs;
877 int resultConfig=0;
878 int i=0, j;
880 if (libusb_get_device_list(ctx, &devs) < 0) {
881 perror("Libusb could not access USB. Abort");
882 return 0;
885 SHOW_PROGRESS(output,"Search USB devices ...\n");
886 while ((dev = devs[i++]) != NULL) {
887 struct libusb_device_descriptor descriptor;
888 libusb_get_device_descriptor(dev, &descriptor);
890 if (mode == SEARCH_BUSDEV) {
891 if ((libusb_get_bus_number(dev) != busnum) ||
892 (libusb_get_device_address(dev) != devnum)) {
893 continue;
894 } else {
895 if (descriptor.idVendor != vendor)
896 continue;
897 if (product != descriptor.idProduct)
898 continue;
901 SHOW_PROGRESS(output,"Found device, search for MBIM configuration...\n");
903 // No check if there is only one configuration
904 if (descriptor.bNumConfigurations < 2)
905 return -1;
907 // Checking all interfaces of all configurations
908 for (j=0; j<descriptor.bNumConfigurations; j++) {
909 struct libusb_config_descriptor *config;
911 libusb_get_config_descriptor(dev, j, &config);
912 resultConfig = config->bConfigurationValue;
913 for (i=0; i<config->bNumInterfaces; i++) {
914 if ( config->interface[i].altsetting[0].bInterfaceClass == 2 )
915 if ( config->interface[i].altsetting[0].bInterfaceSubClass == 0x0e ) {
916 // found MBIM interface in this configuration
917 libusb_free_config_descriptor(config);
918 return resultConfig;
921 libusb_free_config_descriptor(config);
923 return -1;
925 return 0;
929 void resetUSB ()
931 int success;
932 int bpoint = 0;
934 if (!devh) {
935 fprintf(output,"Device handle empty, skip USB reset\n");
936 return;
938 if (show_progress) {
939 fprintf(output,"Reset USB device ");
940 fflush(output);
942 sleep( 1 );
943 do {
944 success = libusb_reset_device(devh);
945 if ( ((bpoint % 10) == 0) && show_progress ) {
946 fprintf(output,".");
947 fflush(output);
949 bpoint++;
950 if (bpoint > 100)
951 success = 1;
952 } while (success < 0);
954 if ( success ) {
955 SHOW_PROGRESS(output,"\n Device reset failed.\n");
956 } else
957 SHOW_PROGRESS(output,"\n Device was reset\n");
961 int switchSendMessage ()
963 const char* cmdHead = "55534243";
964 int ret, i;
965 char* msg[3];
966 msg[0] = MessageContent;
967 msg[1] = MessageContent2;
968 msg[2] = MessageContent3;
970 SHOW_PROGRESS(output,"Set up interface %d\n", Interface);
971 ret = libusb_claim_interface(devh, Interface);
972 if (ret != 0) {
973 SHOW_PROGRESS(output," Could not claim interface (error %d). Skip message sending\n", ret);
974 return 0;
976 libusb_clear_halt(devh, MessageEndpoint);
977 SHOW_PROGRESS(output,"Use endpoint 0x%02x for message sending ...\n", MessageEndpoint);
978 if (show_progress)
979 fflush(stdout);
981 for (i=0; i<3; i++) {
982 if ( strlen(msg[i]) == 0)
983 continue;
985 if ( sendMessage(msg[i], i+1) )
986 goto skip;
988 if ( strstr(msg[i],cmdHead) != NULL ) {
989 // UFI command
990 SHOW_PROGRESS(output,"Read the response to message %d (CSW) ...\n", i+1);
991 ret = read_bulk(ResponseEndpoint, ByteString, 13);
992 } else {
993 // Other bulk transfer
994 SHOW_PROGRESS(output,"Read the response to message %d ...\n", i+1);
995 ret = read_bulk(ResponseEndpoint, ByteString, strlen(msg[i])/2 );
997 if (ret < 0)
998 goto skip;
1001 SHOW_PROGRESS(output,"Reset response endpoint 0x%02x\n", ResponseEndpoint);
1002 ret = libusb_clear_halt(devh, ResponseEndpoint);
1003 if (ret)
1004 SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret);
1005 SHOW_PROGRESS(output,"Reset message endpoint 0x%02x\n", MessageEndpoint);
1006 ret = libusb_clear_halt(devh, MessageEndpoint);
1007 if (ret)
1008 SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret);
1009 usleep(50000);
1011 if (ReleaseDelay) {
1012 SHOW_PROGRESS(output,"Wait for %d ms before releasing interface ...\n", ReleaseDelay);
1013 usleep(ReleaseDelay*1000);
1015 ret = libusb_release_interface(devh, Interface);
1016 if (ret)
1017 goto skip;
1018 return 1;
1020 skip:
1021 SHOW_PROGRESS(output," Device is gone, skip any further commands\n");
1022 libusb_close(devh);
1023 devh = NULL;
1024 return 2;
1028 int switchConfiguration ()
1030 int ret, count = SWITCH_CONFIG_MAXTRIES;
1032 SHOW_PROGRESS(output,"Change configuration to %i ...\n", Configuration);
1033 while (((ret = libusb_set_configuration(devh, Configuration)) < 0) && --count) {
1034 SHOW_PROGRESS(output," Device is busy, try to detach kernel driver\n");
1035 detachDriver();
1037 if (ret < 0 ) {
1038 SHOW_PROGRESS(output," Changing the configuration failed (error %d). Try to continue\n", ret);
1039 return 0;
1040 } else {
1041 SHOW_PROGRESS(output," OK, configuration set\n");
1042 return 1;
1047 int switchAltSetting ()
1049 int ret;
1050 SHOW_PROGRESS(output,"Change to alt setting %i ...\n", AltSetting);
1051 ret = libusb_claim_interface(devh, Interface);
1052 if (ret < 0) {
1053 SHOW_PROGRESS(output," Could not claim interface (error %d). Skip AltSetting\n", ret);
1054 return 0;
1056 ret = libusb_set_interface_alt_setting(devh, Interface, AltSetting);
1057 libusb_release_interface(devh, Interface);
1058 if (ret < 0) {
1059 SHOW_PROGRESS(output," Change to alt setting returned error %d. Try to continue\n", ret);
1060 return 0;
1061 } else
1062 return 1;
1066 void switchHuaweiMode ()
1068 int ret;
1069 SHOW_PROGRESS(output,"Send old Huawei control message ...\n");
1070 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
1071 LIBUSB_REQUEST_SET_FEATURE, 00000001, 0, buffer, 0, 1000);
1073 if (ret != 0) {
1074 fprintf(stderr, "Error: Huawei control message failed (error %d). Abort\n\n", ret);
1075 exit(0);
1080 void switchSierraMode ()
1082 int ret;
1083 SHOW_PROGRESS(output,"Send Sierra control message\n");
1084 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
1085 LIBUSB_REQUEST_SET_INTERFACE, 00000001, 0, buffer, 0, 1000);
1086 if (ret == LIBUSB_ERROR_PIPE) {
1087 SHOW_PROGRESS(output," communication with device stopped. May have switched modes anyway\n");
1088 return;
1090 if (ret < 0) {
1091 fprintf(stderr, "Error: Sierra control message failed (error %d). Abort\n\n", ret);
1092 exit(0);
1097 void switchGCTMode ()
1099 int ret;
1100 ret = libusb_claim_interface(devh, Interface);
1101 if (ret != 0) {
1102 SHOW_PROGRESS(output," Could not claim interface (error %d). Skip GCT sequence\n", ret);
1103 return;
1105 SHOW_PROGRESS(output,"Send GCT control message 1 ...\n type (should be 161/0xA1): %d",
1106 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN);
1108 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN,
1109 0xa0, 0, Interface, buffer, 1, 1000);
1111 if (ret < 0) {
1112 SHOW_PROGRESS(output," GCT control message 1 failed (error %d), continue anyway ...\n", ret);
1114 SHOW_PROGRESS(output,"Send GCT control message 2 ...\n");
1115 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN,
1116 0xfe, 0, Interface, buffer, 1, 1000);
1118 if (ret < 0) {
1119 SHOW_PROGRESS(output," GCT control message 2 failed (error %d). Abort\n\n", ret);
1121 libusb_release_interface(devh, Interface);
1122 if (ret < 0)
1123 exit(0);
1127 void switchKobilMode() {
1128 int ret;
1129 SHOW_PROGRESS(output,"Send Kobil control message ...\n");
1130 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
1131 0x88, 0, 0, buffer, 8, 1000);
1133 if (ret < 0) {
1134 fprintf(stderr, "Error: Kobil control message failed (error %d). Abort\n\n", ret);
1135 exit(0);
1140 void switchQisdaMode () {
1141 int ret;
1142 SHOW_PROGRESS(output,"Sending Qisda control message ...\n");
1143 memcpy(buffer, "\x05\x8c\x04\x08\xa0\xee\x20\x00\x5c\x01\x04\x08\x98\xcd\xea\xbf", 16);
1144 ret = libusb_control_transfer(devh, 0x40, 0x04, 0, 0, buffer, 16, 1000);
1145 if (ret < 0) {
1146 fprintf(stderr, "Error: Qisda control message failed (error %d). Abort\n\n", ret);
1147 exit(0);
1152 void switchQuantaMode() {
1153 int ret;
1154 SHOW_PROGRESS(output,"Send Quanta control message ...\n");
1155 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
1156 0xff, 0, 0, buffer, 0, 1000);
1158 if (ret < 0) {
1159 SHOW_PROGRESS(output,"Error: Quanta control message failed (error %d). Abort\n\n", ret);
1160 exit(0);
1165 void switchBlackberryMode ()
1167 int ret;
1168 SHOW_PROGRESS(output,"Send Blackberry control message 1 ...\n");
1169 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
1170 0xb1, 0x0000, 0, buffer, 8, 1000);
1172 if (ret != 8) {
1173 fprintf(stderr, "Error: Blackberry control message 1 failed (result %d)\n", ret);
1175 SHOW_PROGRESS(output,"Send Blackberry control message 2 ...\n");
1176 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
1177 0xa9, 0x000e, 0, buffer, 2, 1000);
1179 if (ret != 2) {
1180 fprintf(stderr, "Error: Blackberry control message 2 failed (result %d). Abort\n\n", ret);
1181 exit(0);
1186 void switchPantechMode()
1188 int ret;
1189 SHOW_PROGRESS(output,"Send Pantech control message, wValue %d ...\n", PantechMode);
1190 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
1191 0x70, PantechMode, 0, buffer, 0, 1000);
1193 if (ret < 0) {
1194 SHOW_PROGRESS(output," Error: Pantech control message failed (error %d). Abort\n\n", ret);
1195 exit(0);
1200 #define EP_OUT 0x02
1201 #define EP_IN 0x81
1202 #define SIZE 0x08
1204 #define MOBILE_ACTION_READLOOP1 63
1205 #define MOBILE_ACTION_READLOOP2 73
1207 /* The code here is statically derived from sniffing (and confirmed working).
1208 * However I bet it could be simplified significantly.
1211 void switchActionMode ()
1213 int ret, i;
1214 SHOW_PROGRESS(output,"Send MobileAction control sequence ...\n");
1215 memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
1216 libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
1217 0x09, 0x0300, 0, buffer, SIZE, 1000);
1219 memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
1220 libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
1221 0x09, 0x0300, 0, buffer, SIZE, 1000);
1223 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1224 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1225 memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
1226 usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
1227 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1228 memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
1229 usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
1230 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1231 memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
1232 usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
1233 for (i=0; i < MOBILE_ACTION_READLOOP1; i++) {
1234 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1236 memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
1237 usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
1238 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1239 memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
1240 usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
1241 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1242 memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
1243 usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
1244 for (i=0; i < MOBILE_ACTION_READLOOP2; i++) {
1245 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1247 memcpy(buffer, "\x33\x04\xfe\x00\xf4\x6c\x1f\xf0", SIZE);
1248 usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
1249 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1250 memcpy(buffer, "\x32\x07\xfe\xf0\x29\xb9\x3a\xf0", SIZE);
1251 ret = usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
1252 usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
1253 if (ret < 0) {
1254 SHOW_PROGRESS(output," MobileAction control sequence did not complete\n Last error was %d\n",ret);
1255 } else {
1256 SHOW_PROGRESS(output," MobileAction control sequence complete\n");
1261 #define SQN_SET_DEVICE_MODE_REQUEST 0x0b
1262 #define SQN_GET_DEVICE_MODE_REQUEST 0x0a
1264 #define SQN_DEFAULT_DEVICE_MODE 0x00
1265 #define SQN_MASS_STORAGE_MODE 0x01
1266 #define SQN_CUSTOM_DEVICE_MODE 0x02
1268 void switchSequansMode()
1271 int ret;
1272 SHOW_PROGRESS(output,"Send Sequans control message\n");
1273 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
1274 SQN_SET_DEVICE_MODE_REQUEST, SQN_CUSTOM_DEVICE_MODE, 0, buffer, 0, 1000);
1276 if (ret < 0) {
1277 fprintf(stderr, "Error: Sequans request failed (error %d). Abort\n\n", ret);
1278 exit(0);
1283 void switchCiscoMode()
1285 int ret, i, j;
1286 char* msg[11];
1288 msg[0] = "55534243f83bcd810002000080000afd000000030000000100000000000000";
1289 msg[1] = "55534243984300820002000080000afd000000070000000100000000000000";
1290 msg[2] = "55534243984300820000000000000afd000100071000000000000000000000";
1291 msg[3] = "55534243984300820002000080000afd000200230000000100000000000000";
1292 msg[4] = "55534243984300820000000000000afd000300238200000000000000000000";
1293 msg[5] = "55534243984300820002000080000afd000200260000000100000000000000";
1294 msg[6] = "55534243984300820000000000000afd00030026c800000000000000000000";
1295 msg[7] = "55534243d84c04820002000080000afd000010730000000100000000000000";
1296 msg[8] = "55534243d84c04820002000080000afd000200240000000100000000000000";
1297 msg[9] = "55534243d84c04820000000000000afd000300241300000000000000000000";
1298 msg[10] = "55534243d84c04820000000000000afd000110732400000000000000000000";
1300 SHOW_PROGRESS(output,"Set up Cisco interface %d\n", Interface);
1301 ret = libusb_claim_interface(devh, Interface);
1302 if (ret < 0) {
1303 SHOW_PROGRESS(output," Could not claim interface (error %d). Abort\n", ret);
1304 abortExit();
1306 // libusb_clear_halt(devh, MessageEndpoint);
1307 if (show_progress)
1308 fflush(output);
1310 // ret = read_bulk(ResponseEndpoint, ByteString, 13);
1311 // SHOW_PROGRESS(output," Extra response (CSW) read, result %d\n",ret);
1313 for (i=0; i<11; i++) {
1314 if ( sendMessage(msg[i], i+1) )
1315 goto skip;
1317 for (j=1; j<4; j++) {
1319 SHOW_PROGRESS(output," Read the CSW for bulk message %d (attempt %d) ...\n",i+1,j);
1320 ret = read_bulk(ResponseEndpoint, ByteString, 13);
1322 if (ret < 0)
1323 goto skip;
1324 if (ret == 13)
1325 break;
1328 libusb_clear_halt(devh, MessageEndpoint);
1329 libusb_clear_halt(devh, ResponseEndpoint);
1331 ReleaseDelay = 2000;
1332 if (ReleaseDelay) {
1333 SHOW_PROGRESS(output,"Wait for %d ms before releasing interface ...\n", ReleaseDelay);
1334 usleep(ReleaseDelay*1000);
1336 ret = libusb_release_interface(devh, Interface);
1337 if (ret < 0)
1338 goto skip;
1339 return;
1341 skip:
1342 SHOW_PROGRESS(output,"Device returned error %d, skip further commands\n", ret);
1343 libusb_close(devh);
1344 devh = NULL;
1348 int switchSonyMode ()
1350 int ret, i, found;
1351 detachDriver();
1353 if (CheckSuccess) {
1354 CheckSuccess = 0;
1357 SHOW_PROGRESS(output,"Send Sony control message\n");
1358 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
1359 0x11, 2, 0, buffer, 3, 100);
1361 if (ret < 0) {
1362 fprintf(stderr, "Error: Sony control message failed (error %d). Abort\n\n", ret);
1363 exit(0);
1364 } else
1365 SHOW_PROGRESS(output," OK, control message sent, wait for device to return ...\n");
1367 libusb_close(devh);
1368 devh = NULL;
1370 /* Now waiting for the device to reappear */
1371 devnum=-1;
1372 busnum=-1;
1373 i=0;
1374 dev = 0;
1375 while ( dev == 0 && i < 30 ) {
1376 if ( i > 5 ) {
1377 dev = search_devices(&found, DefaultVendor, DefaultProductList, TargetClass, 0, SEARCH_TARGET);
1379 if ( dev != 0 )
1380 break;
1381 sleep(1);
1382 if (show_progress) {
1383 fprintf(output,"#");
1384 fflush(stdout);
1386 i++;
1388 SHOW_PROGRESS(output,"\n After %d seconds:",i);
1389 if ( dev ) {
1390 SHOW_PROGRESS(output," device came back, proceed\n");
1391 libusb_open(dev, &devh);
1392 if (devh == 0) {
1393 fprintf(stderr, "Error: could not get handle on device\n");
1394 return 0;
1396 } else {
1397 SHOW_PROGRESS(output," device still gone, abort\n");
1398 return 0;
1400 sleep(1);
1402 SHOW_PROGRESS(output,"Send Sony control message again ...\n");
1403 ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
1404 0x11, 2, 0, buffer, 3, 100);
1406 if (ret < 0) {
1407 fprintf(stderr, "Error: Sony control message (2) failed (error %d)\n", ret);
1408 return 0;
1410 SHOW_PROGRESS(output," OK, control message sent\n");
1411 return 1;
1415 /* Detach driver
1417 int detachDriver()
1420 int ret;
1421 SHOW_PROGRESS(output,"Looking for active driver ...\n");
1422 ret = libusb_kernel_driver_active(devh, 0);
1423 if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
1424 fprintf(output," Can't do driver detection on this platform.\n");
1425 return 2;
1427 if (ret < 0) {
1428 fprintf(output," Driver check failed with error %d. Try to continue\n", ret);
1429 return 2;
1431 if (ret == 0) {
1432 SHOW_PROGRESS(output," No active driver found. Detached before or never attached\n");
1433 return 1;
1436 ret = libusb_detach_kernel_driver(devh, Interface);
1437 if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
1438 fprintf(output," Can't do driver detaching on this platform.\n");
1439 return 2;
1441 if (ret == 0) {
1442 SHOW_PROGRESS(output," OK, driver detached\n");
1443 } else
1444 SHOW_PROGRESS(output," Driver detach failed (error %d). Try to continue\n", ret);
1445 return 1;
1449 int sendMessage(char* message, int count)
1451 int ret, message_length;
1453 if (strlen(message) % 2 != 0) {
1454 fprintf(stderr, "Error: MessageContent %d hex string has uneven length. Skipping ...\n", count);
1455 return 1;
1457 message_length = strlen(message) / 2;
1458 if ( hexstr2bin(message, ByteString, message_length) == -1) {
1459 fprintf(stderr, "Error: MessageContent %d %s\n is not a hex string. Skipping ...\n",
1460 count, MessageContent);
1462 return 1;
1464 SHOW_PROGRESS(output,"Trying to send message %d to endpoint 0x%02x ...\n", count, MessageEndpoint);
1465 fflush(output);
1466 ret = write_bulk(MessageEndpoint, ByteString, message_length);
1467 if (ret == LIBUSB_ERROR_NO_DEVICE)
1468 return 1;
1470 return 0;
1474 int checkSuccess()
1476 int ret, i;
1477 int newTargetCount, success=0;
1479 SHOW_PROGRESS(output,"\nCheck for mode switch (max. %d times, once per second) ...\n", CheckSuccess);
1480 sleep(1);
1482 /* If target parameters are given, don't check for vanished device
1483 * Changed for Cisco AM10 where a new device is added while the install
1484 * storage device stays active
1486 if ((TargetVendor || TargetClass) && devh) {
1487 libusb_close(devh);
1488 devh = NULL;
1491 /* if target ID is not given but target class is, assign default as target;
1492 * it will be needed for sysmode output
1494 if (!TargetVendor && TargetClass) {
1495 TargetVendor = DefaultVendor;
1496 TargetProduct = DefaultProduct;
1499 /* devh is 0 if device vanished during command transmission or if target params were given
1501 if (devh)
1502 for (i=0; i < CheckSuccess; i++) {
1504 /* Test if default device still can be accessed; positive result does
1505 * not necessarily mean failure
1507 SHOW_PROGRESS(output," Wait for original device to vanish ...\n");
1509 ret = libusb_claim_interface(devh, Interface);
1510 libusb_release_interface(devh, Interface);
1511 if (ret < 0) {
1512 SHOW_PROGRESS(output," Original device can't be accessed anymore. Good.\n");
1513 libusb_close(devh);
1514 devh = NULL;
1515 break;
1517 if (i == CheckSuccess-1) {
1518 SHOW_PROGRESS(output," Original device still present after the timeout\n\n"
1519 "Mode switch most likely failed. Bye!\n\n");
1520 } else
1521 sleep(1);
1524 if ( TargetVendor && (TargetProduct > -1 || TargetProductList[0] != '\0') ) {
1526 /* Recount target devices (compare with previous count) if target data is given.
1527 * Target device on the same bus with higher device number is returned,
1528 * description is read for syslog message
1530 for (i=i; i < CheckSuccess; i++) {
1531 SHOW_PROGRESS(output," Search for target devices ...\n");
1532 dev = search_devices(&newTargetCount, TargetVendor, TargetProductList, TargetClass,
1533 0, SEARCH_TARGET);
1535 if (dev && (newTargetCount > targetDeviceCount)) {
1536 if (verbose) {
1537 libusb_open(dev, &devh);
1538 fprintf(output,"\nFound target device %03d on bus %03d\n",
1539 libusb_get_device_address(dev), libusb_get_bus_number(dev));
1541 fprintf(output,"\nTarget device description data\n");
1542 deviceDescription();
1543 libusb_close(devh);
1544 devh = NULL;
1546 SHOW_PROGRESS(output," Found correct target device\n\n"
1547 "Mode switch succeeded. Bye!\n\n");
1549 success = 2;
1550 break;
1552 if (i == CheckSuccess-1) {
1553 SHOW_PROGRESS(output," No new devices in target mode or class found\n\n"
1554 "Mode switch has failed. Bye!\n\n");
1555 } else
1556 sleep(1);
1558 } else
1559 /* No target data given, rely on the vanished device */
1560 if (!devh) {
1561 SHOW_PROGRESS(output," (For a better success check provide target IDs or class)\n");
1562 SHOW_PROGRESS(output," Original device vanished after switching\n\n"
1563 "Mode switch most likely succeeded. Bye!\n\n");
1564 success = 1;
1567 switch (success) {
1568 case 3:
1569 if (sysmode)
1570 syslog(LOG_NOTICE, "switched to new device, but hit libusb1 bug");
1571 TargetProduct = -1;
1572 success = 1;
1573 break;
1574 case 2:
1575 if (sysmode)
1576 syslog(LOG_NOTICE, "switched to %04x:%04x on %03d/%03d", TargetVendor,
1577 TargetProduct, busnum, devnum);
1579 success = 1;
1580 break;
1581 case 1:
1582 if (sysmode)
1583 syslog(LOG_NOTICE, "device seems to have switched");
1584 default:
1587 if (sysmode)
1588 closelog();
1590 return success;
1595 int write_bulk(int endpoint, unsigned char *message, int length)
1597 int ret = usb_bulk_io(devh, endpoint, message, length, 3000);
1598 if (ret >= 0 ) {
1599 SHOW_PROGRESS(output," OK, message successfully sent\n");
1600 } else
1601 if (ret == LIBUSB_ERROR_NO_DEVICE) {
1602 SHOW_PROGRESS(output," Device seems to have vanished right after sending. Good.\n");
1603 } else
1604 SHOW_PROGRESS(output," Sending the message returned error %d. Try to continue\n", ret);
1605 return ret;
1610 int read_bulk(int endpoint, unsigned char *buffer, int length)
1612 int ret = usb_bulk_io(devh, endpoint, buffer, length, 3000);
1613 if (ret >= 0 ) {
1614 SHOW_PROGRESS(output," Response successfully read (%d bytes).\n", ret);
1615 } else
1616 if (ret == LIBUSB_ERROR_NO_DEVICE) {
1617 SHOW_PROGRESS(output," Device seems to have vanished after reading. Good.\n");
1618 } else
1619 SHOW_PROGRESS(output," Response reading failed (error %d)\n", ret);
1620 return ret;
1625 void release_usb_device(int __attribute__((unused)) dummy)
1627 SHOW_PROGRESS(output,"Program cancelled by system. Bye!\n\n");
1628 if (devh)
1629 libusb_release_interface(devh, Interface);
1630 close_all();
1631 exit(0);
1636 /* Iterates over busses and devices, counts the ones which match the given
1637 * parameters and returns the last one of them
1639 struct libusb_device* search_devices( int *numFound, int vendor, char* productList,
1640 int targetClass, int configuration, int mode)
1642 char *listcopy=NULL, *token;
1643 unsigned char buffer[2];
1644 int devClass, product;
1645 struct libusb_device* right_dev = NULL;
1646 // struct libusb_device_handle *testdevh;
1647 struct libusb_device **devs;
1648 int i=0;
1650 /* only target class given, target vendor and product assumed unchanged */
1651 if ( targetClass && !(vendor || strlen(productList)) ) {
1652 vendor = DefaultVendor;
1653 productList = DefaultProductList;
1655 *numFound = 0;
1657 /* Sanity check */
1658 if (!vendor || productList == '\0')
1659 return NULL;
1661 listcopy = malloc(strlen(productList)+1);
1663 if (libusb_get_device_list(ctx, &devs) < 0) {
1664 perror("Libusb failed to get USB access!");
1665 return 0;
1668 while ((dev = devs[i++]) != NULL) {
1669 struct libusb_device_descriptor descriptor;
1670 libusb_get_device_descriptor(dev, &descriptor);
1672 if (mode == SEARCH_BUSDEV) {
1673 if ((libusb_get_bus_number(dev) != busnum) ||
1674 (libusb_get_device_address(dev) != devnum))
1675 continue;
1676 else
1677 SHOW_PROGRESS(output," bus/device number matched\n");
1680 if (verbose)
1681 fprintf (output," found USB ID %04x:%04x\n",
1682 descriptor.idVendor, descriptor.idProduct);
1683 if (descriptor.idVendor != vendor)
1684 continue;
1685 if (verbose)
1686 fprintf (output," vendor ID matched\n");
1688 strcpy(listcopy, productList);
1689 token = strtok(listcopy, ",");
1690 while (token != NULL) {
1691 if (strlen(token) != 4) {
1692 SHOW_PROGRESS(output,"Error: entry in product ID list has wrong length: %s. "
1693 "Ignored\n", token);
1695 goto NextToken;
1697 if ( hexstr2bin(token, buffer, strlen(token)/2) == -1) {
1698 SHOW_PROGRESS(output,"Error: entry in product ID list is not a hex string: %s. "
1699 "Ignored\n", token);
1701 goto NextToken;
1703 product = 0;
1704 product += (unsigned char)buffer[0];
1705 product <<= 8;
1706 product += (unsigned char)buffer[1];
1707 if (product == descriptor.idProduct) {
1708 SHOW_PROGRESS(output," product ID matched\n");
1710 if (targetClass != 0) {
1711 // TargetClass is set, check class of first interface
1712 struct libusb_device_descriptor descriptor;
1713 libusb_get_device_descriptor(dev, &descriptor);
1714 devClass = descriptor.bDeviceClass;
1715 struct libusb_config_descriptor *config;
1716 libusb_get_config_descriptor(dev, 0, &config);
1717 int ifaceClass = config->interface[0].altsetting[0].bInterfaceClass;
1718 libusb_free_config_descriptor(config);
1719 if (devClass == 0)
1720 devClass = ifaceClass;
1721 else
1722 /* Check for some quirky devices */
1723 if (devClass != ifaceClass)
1724 devClass = ifaceClass;
1725 if (devClass == targetClass) {
1726 if (verbose)
1727 fprintf (output," target class %02x matches\n", targetClass);
1728 if (mode == SEARCH_TARGET) {
1729 (*numFound)++;
1730 right_dev = dev;
1731 if (verbose)
1732 fprintf (output," count device\n");
1733 } else
1734 if (verbose)
1735 fprintf (output," device not counted, target class reached\n");
1736 } else {
1737 if (verbose)
1738 fprintf (output," device class %02x not matching target\n", devClass);
1739 if (mode == SEARCH_DEFAULT || mode == SEARCH_BUSDEV) {
1740 (*numFound)++;
1741 right_dev = dev;
1742 if (verbose)
1743 fprintf (output," count device\n");
1746 } else if (configuration > 0) {
1747 // Configuration parameter is set, check device configuration
1748 int testconfig = get_current_config_value(dev);
1749 if (testconfig != configuration) {
1750 if (verbose)
1751 fprintf (output," device configuration %d not matching target\n",
1752 testconfig);
1754 (*numFound)++;
1755 right_dev = dev;
1756 if (verbose)
1757 fprintf (output," count device\n");
1758 } else
1759 if (verbose)
1760 fprintf (output," device not counted, target configuration reached\n");
1761 } else {
1762 // Neither TargetClass nor Configuration are set
1763 (*numFound)++;
1764 right_dev = dev;
1765 if (mode == SEARCH_BUSDEV)
1766 break;
1770 NextToken:
1771 token = strtok(NULL, ",");
1774 if (listcopy != NULL)
1775 free(listcopy);
1776 return right_dev;
1780 /* Autodetect bulk endpoints (ab) */
1782 int find_first_bulk_endpoint(int direction)
1784 int i, j;
1785 const struct libusb_interface_descriptor *alt;
1786 const struct libusb_endpoint_descriptor *ep;
1788 for (j=0; j < active_config->bNumInterfaces; j++) {
1789 alt = &(active_config->interface[j].altsetting[0]);
1790 if (alt->bInterfaceNumber == Interface) {
1791 for (i=0; i < alt->bNumEndpoints; i++) {
1792 ep = &(alt->endpoint[i]);
1793 if ( ( (ep->bmAttributes & LIBUSB_ENDPOINT_ADDRESS_MASK) == LIBUSB_TRANSFER_TYPE_BULK)
1794 && ( (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == direction ) ) {
1796 return ep->bEndpointAddress;
1801 return 0;
1805 int get_current_config_value()
1807 SHOW_PROGRESS(output,"Get the current device configuration ...\n");
1808 if (active_config != NULL) {
1809 libusb_free_config_descriptor(active_config);
1810 active_config = NULL;
1812 int ret = libusb_get_active_config_descriptor(dev, &active_config);
1813 if (ret < 0) {
1814 SHOW_PROGRESS(output," Determining the active configuration failed (error %d). Abort\n", ret);
1815 abortExit();
1817 return active_config->bConfigurationValue;
1821 int get_interface_class()
1823 int i;
1824 for (i=0; i < active_config->bNumInterfaces; i++) {
1825 if (active_config->interface[i].altsetting[0].bInterfaceNumber == Interface)
1826 return active_config->interface[i].altsetting[0].bInterfaceClass;
1828 return -1;
1832 /* Parameter parsing */
1834 char* ReadParseParam(const char* FileName, char *VariableName)
1836 static int numLines = 0;
1837 static char* ConfigBuffer[MAXLINES];
1838 char *VarName, *Comment=NULL, *Equal=NULL;
1839 char *FirstQuote, *LastQuote, *P1, *P2;
1840 int Line=0;
1841 unsigned Len=0, Pos=0;
1842 char Str[LINE_DIM], *token, *configPos;
1843 FILE *file = NULL;
1845 // Reading and storing input during the first call
1846 if (numLines==0) {
1847 if (strncmp(FileName,"##",2) == 0) {
1848 if (verbose) fprintf(output,"\nRead long config from command line\n");
1849 // "Embedded" configuration data
1850 configPos = (char*)FileName;
1851 token = strtok(configPos, "\n");
1852 strncpy(Str,token,LINE_DIM-1);
1853 } else {
1854 if (strcmp(FileName, "stdin")==0) {
1855 if (verbose) fprintf(output,"\nRead long config from stdin\n");
1856 file = stdin;
1857 } else {
1858 if (verbose) fprintf(output,"\nRead config file: %s\n", FileName);
1859 file=fopen(FileName, "r");
1861 if (file==NULL) {
1862 fprintf(stderr, "Error: Could not find file %s. Abort\n\n", FileName);
1863 abortExit();
1864 } else {
1865 token = fgets(Str, LINE_DIM-1, file);
1868 while (token != NULL && numLines < MAXLINES) {
1869 // Line++;
1870 Len=strlen(Str);
1871 if (Len==0)
1872 goto NextLine;
1873 if (Str[Len-1]=='\n' or Str[Len-1]=='\r')
1874 Str[--Len]='\0';
1875 Equal = strchr (Str, '='); // search for equal sign
1876 Pos = strcspn (Str, ";#!"); // search for comment
1877 Comment = (Pos==Len) ? NULL : Str+Pos;
1878 if (Equal==NULL or ( Comment!=NULL and Comment<=Equal))
1879 goto NextLine; // Comment or irrelevant, don't save
1880 Len=strlen(Str)+1;
1881 ConfigBuffer[numLines] = malloc(Len*sizeof(char));
1882 strcpy(ConfigBuffer[numLines],Str);
1883 numLines++;
1884 NextLine:
1885 if (file == NULL) {
1886 token = strtok(NULL, "\n");
1887 if (token != NULL)
1888 strncpy(Str,token,LINE_DIM-1);
1889 } else
1890 token = fgets(Str, LINE_DIM-1, file);
1892 if (file != NULL)
1893 fclose(file);
1896 // Now checking for parameters
1897 Line=0;
1898 while (Line < numLines) {
1899 strcpy(Str,ConfigBuffer[Line]);
1900 Equal = strchr (Str, '='); // search for equal sign
1901 *Equal++ = '\0';
1903 // String
1904 FirstQuote=strchr (Equal, '"'); // search for double quote char
1905 LastQuote=strrchr (Equal, '"');
1906 if (FirstQuote!=NULL) {
1907 if (LastQuote==NULL) {
1908 fprintf(stderr, "Error reading parameters from file %s - "
1909 "Missing end quote:\n%s\n", FileName, Str);
1911 goto Next;
1913 *FirstQuote=*LastQuote='\0';
1914 Equal=FirstQuote+1;
1917 // removes leading/trailing spaces
1918 Pos=strspn (Str, " \t");
1919 if (Pos==strlen(Str)) {
1920 fprintf(stderr, "Error reading parameters from file %s - "
1921 "Missing variable name:\n%s\n", FileName, Str);
1923 goto Next;
1925 while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '\t'))!=NULL)
1926 if (P1!=NULL) *P1='\0';
1927 else if (P2!=NULL) *P2='\0';
1928 VarName=Str+Pos;
1930 Pos=strspn (Equal, " \t");
1931 if (Pos==strlen(Equal)) {
1932 fprintf(stderr, "Error reading parameter from file %s - "
1933 "Missing value:\n%s\n", FileName, Str);
1935 goto Next;
1937 Equal+=Pos;
1939 if (strcmp(VarName, VariableName)==0) { // Found it
1940 return Equal;
1942 Next:
1943 Line++;
1946 return NULL;
1950 int hex2num(char c)
1952 if (c >= '0' && c <= '9')
1953 return c - '0';
1954 if (c >= 'a' && c <= 'f')
1955 return c - 'a' + 10;
1956 if (c >= 'A' && c <= 'F')
1957 return c - 'A' + 10;
1958 return -1;
1962 int hex2byte(const char *hex)
1964 int a, b;
1965 a = hex2num(*hex++);
1966 if (a < 0)
1967 return -1;
1968 b = hex2num(*hex++);
1969 if (b < 0)
1970 return -1;
1971 return (a << 4) | b;
1975 int hexstr2bin(const char *hex, unsigned char *buffer, int len)
1977 int i;
1978 int a;
1979 const char *ipos = hex;
1980 unsigned char *opos = buffer;
1982 for (i = 0; i < len; i++) {
1983 a = hex2byte(ipos);
1984 if (a < 0)
1985 return -1;
1986 *opos++ = (unsigned char) a;
1987 ipos += 2;
1989 return 0;
1993 void close_all()
1995 if (active_config)
1996 libusb_free_config_descriptor(active_config);
1997 if (devh)
1998 libusb_close(devh);
1999 // libusb_exit will crash on Raspbian 7, crude protection
2000 #ifndef __ARMEL__
2001 libusb_exit(NULL);
2002 #endif
2003 if (sysmode)
2004 closelog();
2008 void abortExit()
2010 close_all();
2011 exit(1);
2015 void printVersion()
2017 char* version = VERSION;
2018 fprintf(output,"\n * usb_modeswitch: handle USB devices with multiple modes\n"
2019 " * Version %s (C) Josua Dietze 2015\n"
2020 " * Based on libusb1/libusbx\n\n"
2021 " ! PLEASE REPORT NEW CONFIGURATIONS !\n\n", version);
2025 void printHelp()
2027 fprintf(output,"\nUsage: usb_modeswitch [<params>] [-c filename]\n\n"
2028 " -h, --help this help\n"
2029 " -e, --version print version information and exit\n"
2030 " -j, --find-mbim return config no. with MBIM interface, exit\n\n"
2031 " -v, --default-vendor NUM vendor ID of original mode (mandatory)\n"
2032 " -p, --default-product NUM product ID of original mode (mandatory)\n"
2033 " -V, --target-vendor NUM target mode vendor ID (optional)\n"
2034 " -P, --target-product NUM target mode product ID (optional)\n"
2035 " -C, --target-class NUM target mode device class (optional)\n"
2036 " -b, --bus-num NUM system bus number of device (for hard ID)\n"
2037 " -g, --device-num NUM system device number (for hard ID)\n"
2038 " -m, --message-endpoint NUM direct the message transfer there (optional)\n"
2039 " -M, --message-content <msg> message to send (hex number as string)\n"
2040 " -2 <msg>, -3 <msg> additional messages to send (-n recommended)\n"
2041 " -w, --release-delay NUM wait NUM ms before releasing the interface\n"
2042 " -n, --need-response obsolete, no effect (always on)\n"
2043 " -r, --response-endpoint NUM read response from there (optional)\n"
2044 " -K, --std-eject send standard EJECT sequence\n"
2045 " -d, --detach-only detach the active driver, no further action\n"
2046 " -H, --huawei-mode apply a special procedure\n"
2047 " -J, --huawei-new-mode apply a special procedure\n"
2048 " -S, --sierra-mode apply a special procedure\n"
2049 " -O, --sony-mode apply a special procedure\n"
2050 " -G, --gct-mode apply a special procedure\n"
2051 " -N, --sequans-mode apply a special procedure\n"
2052 " -A, --mobileaction-mode apply a special procedure\n"
2053 " -T, --kobil-mode apply a special procedure\n"
2054 " -L, --cisco-mode apply a special procedure\n"
2055 " -B, --qisda-mode apply a special procedure\n"
2056 " -E, --quanta-mode apply a special procedure\n"
2057 " -F, --pantech-mode NUM apply a special procedure, pass NUM through\n"
2058 " -Z, --blackberry-mode apply a special procedure\n"
2059 " -U, --option-mode apply a special procedure\n"
2060 " -R, --reset-usb reset the device after all other actions\n"
2061 " -Q, --quiet don't show progress or error messages\n"
2062 " -W, --verbose print all settings and debug output\n"
2063 " -D, --sysmode specific result and syslog message\n"
2064 " -s, --success <seconds> switching result check with timeout\n"
2065 " -I, --inquire obsolete, no effect\n\n"
2066 " -c, --config-file <filename> load long configuration from file\n\n"
2067 " -t, --stdinput read long configuration from stdin\n\n"
2068 " -f, --long-config <text> get long configuration from string\n\n"
2069 " -i, --interface NUM select initial USB interface (default 0)\n"
2070 " -u, --configuration NUM select USB configuration\n"
2071 " -a, --altsetting NUM select alternative USB interface setting\n\n");