diff --git a/callouts/77-nm-probe-modem-capabilities.rules b/callouts/77-nm-probe-modem-capabilities.rules index 261a5351d3..a134bc9204 100644 --- a/callouts/77-nm-probe-modem-capabilities.rules +++ b/callouts/77-nm-probe-modem-capabilities.rules @@ -4,7 +4,8 @@ ACTION!="add|change", GOTO="nm_modem_probe_end" SUBSYSTEM!="tty", GOTO="nm_modem_probe_end" KERNEL!="tty*", GOTO="nm_modem_probe_end" -DRIVERS=="option|sierra|hso|serial_cs|cdc_acm", IMPORT{program}="nm-modem-probe --delay 3000 --export $tempnode" +DRIVERS=="serial_cs", IMPORT{program}="nm-modem-probe --delay 3000 --export $tempnode", GOTO="nm_modem_probe_end" +DRIVERS=="option|sierra|hso|cdc_acm", IMPORT{program}="nm-modem-probe --vid 0x$attr{idVendor} --pid 0x$attr{idProduct} --usb-interface $attr{bInterfaceNumber} --driver $attr{driver} --delay 3000 --export $tempnode", GOTO="nm_modem_probe_end" LABEL="nm_modem_probe_end" diff --git a/callouts/nm-modem-probe.c b/callouts/nm-modem-probe.c index 52906cc0f3..b795aeac33 100644 --- a/callouts/nm-modem-probe.c +++ b/callouts/nm-modem-probe.c @@ -30,6 +30,9 @@ #include +#define HUAWEI_VENDOR_ID 0x12D1 +#define SIERRA_VENDOR_ID 0x1199 + #define MODEM_CAP_GSM 0x0001 /* GSM */ #define MODEM_CAP_IS707_A 0x0002 /* CDMA Circuit Switched Data */ #define MODEM_CAP_IS707_P 0x0004 /* CDMA Packet Switched Data */ @@ -311,7 +314,7 @@ g_timeval_subtract (GTimeVal *result, GTimeVal *x, GTimeVal *y) static int modem_probe_caps(int fd, glong timeout_ms) { const char *gcap_responses[] = { GCAP_TAG, NULL }; - const char *terminators[] = { "OK", "ERROR", "ERR", NULL }; + const char *terminators[] = { "OK", "ERROR", "ERR", "+CME ERROR", NULL }; char *reply = NULL; int idx = -1, term_idx = -1, ret = 0; gboolean try_ati = FALSE; @@ -354,6 +357,10 @@ static int modem_probe_caps(int fd, glong timeout_ms) /* Just returned "OK" but no GCAP (Sierra) */ try_ati = TRUE; break; + } else if (3 == term_idx && -1 == idx) { + /* No SIM (Huawei) */ + try_ati = TRUE; + break; } else if (1 == term_idx || 2 == term_idx) { try_ati = TRUE; } else @@ -410,10 +417,15 @@ static void print_usage (void) { printf("Usage: probe-modem [options] \n" - " --export export key/value pairs\n" - " --delay delay before probing (1 to 3000 ms inclusive)\n" - " --verbose print verbose debugging output\n" - " --log log all output\n" + " --export export key/value pairs\n" + " --delay delay before probing (1 to 3000 ms inclusive)\n" + " --verbose print verbose debugging output\n" + " --quiet suppress logging to stdout (does not affect logfile output)\n" + " --log log all output\n" + " --vid USB Vendor ID (optional)\n" + " --pid USB Product ID (optional)\n" + " --usb-interface USB device interface number (optional)\n" + " --driver Linux kernel device driver (optional)\n" " --help\n\n"); } @@ -426,17 +438,23 @@ main(int argc, char *argv[]) { "verbose", 0, NULL, 'v' }, { "quiet", 0, NULL, 'q' }, { "log", required_argument, NULL, 'l' }, + { "vid", required_argument, NULL, 'e' }, + { "pid", required_argument, NULL, 'p' }, + { "usb-interface", required_argument, NULL, 'i' }, + { "driver", required_argument, NULL, 'd' }, { "help", 0, NULL, 'h' }, {} }; const char *device = NULL; const char *logpath = NULL; - const char *delay_str = NULL; + const char *driver = NULL; gboolean export = 0; struct termios orig, attrs; int fd = -1, caps, ret = 0; guint32 delay_ms = 0; + unsigned int vid = 0, pid = 0, usbif = 0; + unsigned long int tmp; while (1) { int option; @@ -450,7 +468,12 @@ main(int argc, char *argv[]) export = TRUE; break; case 'a': - delay_str = optarg; + tmp = strtoul (optarg, NULL, 10); + if (tmp < 1 || tmp > 3000) { + fprintf (stderr, "Invalid delay: %s\n", optarg); + return 1; + } + delay_ms = (guint32) tmp; break; case 'v': verbose = TRUE; @@ -458,6 +481,30 @@ main(int argc, char *argv[]) case 'l': logpath = optarg; break; + case 'e': + vid = strtoul (optarg, NULL, 0); + if (vid == 0) { + fprintf (stderr, "Could not parse USB Vendor ID '%s'", optarg); + return 1; + } + break; + case 'p': + pid = strtoul (optarg, NULL, 0); + if (pid > G_MAXUINT32) { + fprintf (stderr, "Could not parse USB Product ID '%s'", optarg); + return 1; + } + break; + case 'i': + usbif = strtoul (optarg, NULL, 0); + if (usbif > 50) { + fprintf (stderr, "Could not parse USB interface number '%s'", optarg); + return 1; + } + break; + case 'd': + driver = optarg; + break; case 'q': quiet = TRUE; break; @@ -491,20 +538,19 @@ main(int argc, char *argv[]) goto exit; } - verbose ("probing %s", device); + verbose ("(%s): usb-vid 0x%04x usb-pid 0x%04x usb-intf %d driver '%s'", + device, vid, pid, usbif, driver); - if (delay_str) { - unsigned long int tmp; - - tmp = strtoul (delay_str, NULL, 10); - if (tmp < 1 || tmp > 3000) { - g_printerr ("Invalid delay: %s\n", delay_str); - ret = 3; - goto exit; - } - delay_ms = (guint32) tmp; + /* Some devices just shouldn't be touched */ + if (vid == HUAWEI_VENDOR_ID && usbif != 0) { + verbose ("(%s) ignoring Huawei USB interface #1", device); + if (export) + printf ("ID_NM_MODEM_PROBED=1\n"); + goto exit; } + verbose ("probing %s", device); + fd = open (device, O_RDWR | O_EXCL | O_NONBLOCK); if (fd < 0) { g_printerr ("open(%s) failed: %d\n", device, errno); @@ -536,7 +582,8 @@ main(int argc, char *argv[]) if (caps < 0) { g_printerr ("%s: couldn't get modem capabilities\n", device); - printf ("ID_NM_MODEM_PROBED=1\n"); + if (export) + printf ("ID_NM_MODEM_PROBED=1\n"); goto exit; }