aboutsummaryrefslogtreecommitdiff
path: root/callouts
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2009-06-28 14:05:05 -0400
committerDan Williams <dcbw@redhat.com>2009-06-28 14:05:05 -0400
commit6077763d90b69cfc60b23f383c4529f966facaaf (patch)
tree81ae20133a6ea116d58ddc2ee86644f4e1c9eb0a /callouts
parent112f2da19dbe8dcd8f32b998459298e7c1884c67 (diff)
asynchronous and deferred port detection
Allow plugins to perform asynchronous port detection, and to defer port detection until later. This moves the prober bits into MMPluginBase so that all plugins can take adavantage of it only when needed; the probing is not done at udev time. Furthermore, plugins like Novatel can flip the secondary ports over the AT mode through deferred detection, by deferring the secondary ports until the main port has been detected and AT$NWDMAT has been sent. This commit also finishes the port of the rest of the plugins (except mbm) over to the new port detection methods and plugin API.
Diffstat (limited to 'callouts')
-rw-r--r--callouts/77-mm-modem-probe-capabilities.rules23
-rw-r--r--callouts/Makefile.am13
-rw-r--r--callouts/mm-modem-probe.c639
3 files changed, 0 insertions, 675 deletions
diff --git a/callouts/77-mm-modem-probe-capabilities.rules b/callouts/77-mm-modem-probe-capabilities.rules
deleted file mode 100644
index ba86cc2c..00000000
--- a/callouts/77-mm-modem-probe-capabilities.rules
+++ /dev/null
@@ -1,23 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-ACTION!="add|change", GOTO="mm_modem_probe_end"
-SUBSYSTEM!="tty", GOTO="mm_modem_probe_end"
-
-DRIVERS=="serial_cs|nozomi", IMPORT{program}="mm-modem-probe --delay 3000 --export $tempnode", GOTO="mm_modem_probe_end"
-
-# Only probe known mobile broadband drivers
-DRIVERS=="option|sierra|hso|cdc_acm|qcserial|moto-modem", GOTO="probe"
-
-GOTO="mm_modem_probe_end"
-
-LABEL="probe"
-
-# Don't probe new-style beagleboard cdc-acm ports
-SUBSYSTEMS=="usb", ATTRS{idVendor}=="0525", GOTO="mm_modem_probe_end"
-
-SUBSYSTEM=="tty", SUBSYSTEMS=="usb", DRIVERS=="?*", ENV{MM_MODEM_DRIVER}="$attr{driver}"
-SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{MM_MODEM_USB_INTERFACE_NUMBER}="$attr{bInterfaceNumber}"
-SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="?*", ATTRS{idProduct}=="?*", IMPORT{program}="mm-modem-probe --vid 0x$attr{idVendor} --pid 0x$attr{idProduct} --usb-interface $env{MM_MODEM_USB_INTERFACE_NUMBER} --driver $env{MM_MODEM_DRIVER} --delay 3000 --export $tempnode", GOTO="mm_modem_probe_end"
-
-LABEL="mm_modem_probe_end"
-
diff --git a/callouts/Makefile.am b/callouts/Makefile.am
deleted file mode 100644
index 6a3f3b24..00000000
--- a/callouts/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-udevdir = $(UDEV_BASE_DIR)
-udev_PROGRAMS = mm-modem-probe
-
-mm_modem_probe_SOURCES = mm-modem-probe.c
-mm_modem_probe_CPPFLAGS = $(MM_CFLAGS)
-mm_modem_probe_LDADD = $(MM_LIBS)
-
-udevrulesdir = $(UDEV_BASE_DIR)/rules.d
-udevrules_DATA = 77-mm-modem-probe-capabilities.rules
-
-EXTRA_DIST = \
- $(udevrules_DATA)
-
diff --git a/callouts/mm-modem-probe.c b/callouts/mm-modem-probe.c
deleted file mode 100644
index 93f84f8d..00000000
--- a/callouts/mm-modem-probe.c
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * modem_caps - probe Hayes-compatible modem capabilities
- *
- * Copyright (C) 2008 Dan Williams <dcbw@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details:
- */
-
-#include <termios.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <time.h>
-
-#include <glib.h>
-
-#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 */
-#define MODEM_CAP_DS 0x0008 /* Data compression selection (v.42bis) */
-#define MODEM_CAP_ES 0x0010 /* Error control selection (v.42) */
-#define MODEM_CAP_FCLASS 0x0020 /* Group III Fax */
-#define MODEM_CAP_MS 0x0040 /* Modulation selection */
-#define MODEM_CAP_W 0x0080 /* Wireless commands */
-#define MODEM_CAP_IS856 0x0100 /* CDMA 3G EVDO rev 0 */
-#define MODEM_CAP_IS856_A 0x0200 /* CDMA 3G EVDO rev A */
-
-static gboolean verbose = FALSE;
-static gboolean quiet = FALSE;
-static FILE *logfile = NULL;
-
-struct modem_caps {
- char *name;
- guint32 bits;
-};
-
-static struct modem_caps modem_caps[] = {
- {"+CGSM", MODEM_CAP_GSM},
- {"+CIS707-A", MODEM_CAP_IS707_A},
- {"+CIS707A", MODEM_CAP_IS707_A}, /* Cmotech */
- {"+CIS707", MODEM_CAP_IS707_A},
- {"CIS707", MODEM_CAP_IS707_A}, /* Qualcomm Gobi */
- {"+CIS707P", MODEM_CAP_IS707_P},
- {"CIS-856", MODEM_CAP_IS856},
- {"+IS-856", MODEM_CAP_IS856}, /* Cmotech */
- {"CIS-856-A", MODEM_CAP_IS856_A},
- {"CIS-856A", MODEM_CAP_IS856_A}, /* Kyocera KPC680 */
- {"+DS", MODEM_CAP_DS},
- {"+ES", MODEM_CAP_ES},
- {"+MS", MODEM_CAP_MS},
- {"+FCLASS", MODEM_CAP_FCLASS},
- {NULL}
-};
-
-static void
-printerr_handler (const char *string)
-{
- if (logfile)
- fprintf (logfile, "E: %s", string);
- if (!quiet)
- fprintf (stderr, "E: %s", string);
-}
-
-static void
-print_handler (const char *string)
-{
- if (logfile)
- fprintf (logfile, "L: %s", string);
- if (!quiet)
- fprintf (stdout, "L: %s", string);
-}
-
-#define verbose(fmt, args...) \
-if (verbose) { \
- g_print ("%s(): " fmt "\n", G_STRFUNC, ##args); \
-}
-
-static gboolean
-modem_send_command (int fd, const char *cmd)
-{
- int eagain_count = 1000;
- guint32 i;
- ssize_t written;
-
- verbose ("Sending: '%s'", cmd);
-
- for (i = 0; i < strlen (cmd) && eagain_count > 0;) {
- written = write (fd, cmd + i, 1);
-
- if (written > 0)
- i += written;
- else {
- /* Treat written == 0 as EAGAIN to ensure we break out of the
- * for() loop eventually.
- */
- if ((written < 0) && (errno != EAGAIN)) {
- g_printerr ("error writing command: %d\n", errno);
- return FALSE;
- }
- eagain_count--;
- g_usleep (G_USEC_PER_SEC / 10000);
- }
- }
-
- return eagain_count <= 0 ? FALSE : TRUE;
-}
-
-static int
-find_terminator (const char *line, const char **terminators)
-{
- int i;
-
- for (i = 0; terminators[i]; i++) {
- if (!strncasecmp (line, terminators[i], strlen (terminators[i])))
- return i;
- }
- return -1;
-}
-
-static const char *
-find_response (const char *line, const char **responses, int *idx)
-{
- int i;
-
- /* Don't look for a result again if we got one previously */
- for (i = 0; responses[i]; i++) {
- if (strstr (line, responses[i])) {
- *idx = i;
- return line;
- }
- }
- return NULL;
-}
-
-#define RESPONSE_LINE_MAX 128
-#define SERIAL_BUF_SIZE 2048
-
-/* Return values:
- *
- * -2: timeout
- * -1: read error or response not found
- * 0...N: response index in **needles array
- */
-static int
-modem_wait_reply (int fd,
- guint32 timeout_secs,
- const char **needles,
- const char **terminators,
- int *out_terminator,
- char **out_response)
-{
- char buf[SERIAL_BUF_SIZE + 1];
- int reply_index = -1, bytes_read;
- GString *result = g_string_sized_new (RESPONSE_LINE_MAX * 2);
- time_t end;
- const char *response = NULL;
- gboolean done = FALSE;
-
- *out_terminator = -1;
- end = time (NULL) + timeout_secs;
- do {
- bytes_read = read (fd, buf, SERIAL_BUF_SIZE);
- if (bytes_read < 0 && errno != EAGAIN) {
- g_string_free (result, TRUE);
- g_printerr ("read error: %d\n", errno);
- return -1;
- }
-
- if (bytes_read == 0)
- break; /* EOF */
- else if (bytes_read > 0) {
- char **lines, **iter, *tmp;
-
- buf[bytes_read] = 0;
- g_string_append (result, buf);
-
- verbose ("Got: '%s'", result->str);
-
- lines = g_strsplit_set (result->str, "\n\r", 0);
-
- /* Find response terminators */
- for (iter = lines; *iter && !done; iter++) {
- tmp = g_strstrip (*iter);
- if (tmp && strlen (tmp)) {
- *out_terminator = find_terminator (tmp, terminators);
- if (*out_terminator >= 0)
- done = TRUE;
- }
- }
-
- /* If the terminator is found, look for expected responses */
- if (done) {
- for (iter = lines; *iter && (reply_index < 0); iter++) {
- tmp = g_strstrip (*iter);
- if (tmp && strlen (tmp)) {
- response = find_response (tmp, needles, &reply_index);
- if (response) {
- g_free (*out_response);
- *out_response = g_strdup (response);
- }
- }
- }
- }
- g_strfreev (lines);
- }
-
- if (!done)
- g_usleep (1000);
- } while (!done && (time (NULL) < end) && (result->len <= SERIAL_BUF_SIZE));
-
- /* Handle timeout */
- if (*out_terminator < 0 && !*out_response)
- reply_index = -2;
-
- g_string_free (result, TRUE);
- return reply_index;
-}
-
-#define GCAP_TAG "+GCAP:"
-#define CGMM_TAG "+CGMM:"
-#define HUAWEI_EC121_TAG "+CIS707-A"
-
-static int
-parse_gcap (const char *tag, gboolean strip_tag, const char *buf)
-{
- const char *p = buf;
- char **caps, **iter;
- int ret = 0;
-
- if (strip_tag)
- p += strlen (tag);
-
- caps = g_strsplit_set (p, " ,\t", 0);
- if (!caps)
- return 0;
-
- for (iter = caps; *iter; iter++) {
- struct modem_caps *cap = modem_caps;
-
- while (cap->name) {
- if (!strcmp(cap->name, *iter)) {
- ret |= cap->bits;
- break;
- }
- cap++;
- }
- }
-
- g_strfreev (caps);
- return ret;
-}
-
-static int
-parse_cgmm (const char *buf)
-{
- const char *p = buf + strlen (CGMM_TAG);
- char **cgmm, **iter;
- gboolean gsm = FALSE;
-
- cgmm = g_strsplit_set (p, " ,\t", 0);
- if (!cgmm)
- return 0;
-
- /* BUSlink SCWi275u USB GPRS modem and some Motorola phones */
- for (iter = cgmm; *iter && !gsm; iter++) {
- if (strstr (*iter, "GSM900") || strstr (*iter, "GSM1800") ||
- strstr (*iter, "GSM1900") || strstr (*iter, "GSM850"))
- gsm = TRUE;
- }
-
- g_strfreev (cgmm);
- return gsm ? MODEM_CAP_GSM : 0;
-}
-
-static int
-g_timeval_subtract (GTimeVal *result, GTimeVal *x, GTimeVal *y)
-{
- int nsec;
-
- /* Perform the carry for the later subtraction by updating y. */
- if (x->tv_usec < y->tv_usec) {
- nsec = (y->tv_usec - x->tv_usec) / G_USEC_PER_SEC + 1;
- y->tv_usec -= G_USEC_PER_SEC * nsec;
- y->tv_sec += nsec;
- }
- if (x->tv_usec - y->tv_usec > G_USEC_PER_SEC) {
- nsec = (x->tv_usec - y->tv_usec) / G_USEC_PER_SEC;
- y->tv_usec += G_USEC_PER_SEC * nsec;
- y->tv_sec -= nsec;
- }
-
- /* Compute the time remaining to wait.
- tv_usec is certainly positive. */
- result->tv_sec = x->tv_sec - y->tv_sec;
- result->tv_usec = x->tv_usec - y->tv_usec;
-
- /* Return 1 if result is negative. */
- return x->tv_sec < y->tv_sec;
-}
-
-static int modem_probe_caps(int fd, glong timeout_ms)
-{
- const char *gcap_responses[] = { GCAP_TAG, HUAWEI_EC121_TAG, 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;
- GTimeVal start, end;
- gboolean send_success;
-
- /* If a delay was specified, start a bit later */
- if (timeout_ms > 500) {
- g_usleep (500000);
- timeout_ms -= 500;
- }
-
- /* Standard response timeout case */
- timeout_ms += 3000;
-
- while (timeout_ms > 0) {
- GTimeVal diff;
- gulong sleep_time = 100000;
-
- g_get_current_time (&start);
-
- idx = term_idx = 0;
- send_success = modem_send_command (fd, "AT+GCAP\r\n");
- if (send_success)
- idx = modem_wait_reply (fd, 2, gcap_responses, terminators, &term_idx, &reply);
- else
- sleep_time = 300000;
-
- g_get_current_time (&end);
- g_timeval_subtract (&diff, &end, &start);
- timeout_ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
-
- if (send_success) {
- if (0 == term_idx && 0 == idx) {
- /* Success */
- verbose ("GCAP response: %s", reply);
- ret = parse_gcap (gcap_responses[idx], TRUE, reply);
- break;
- } else if (0 == term_idx && 1 == idx) {
- /* Stupid Huawei EC121 that doesn't prefix response with +GCAP: */
- verbose ("GCAP response: %s", reply);
- ret = parse_gcap (gcap_responses[idx], FALSE, reply);
- break;
- } else if (0 == term_idx && -1 == idx) {
- /* 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
- verbose ("timed out waiting for GCAP reply (idx %d, term_idx %d)", idx, term_idx);
- g_free (reply);
- reply = NULL;
- }
-
- g_usleep (sleep_time);
- timeout_ms -= sleep_time / 1000;
- }
-
- if (!ret && try_ati) {
- const char *ati_responses[] = { GCAP_TAG, HUAWEI_EC121_TAG, NULL };
-
- /* Many cards (ex Sierra 860 & 875) won't accept AT+GCAP but
- * accept ATI when the SIM is missing. Often the GCAP info is
- * in the ATI response too.
- */
- g_free (reply);
- reply = NULL;
-
- verbose ("GCAP failed, trying ATI...");
- if (modem_send_command (fd, "ATI\r\n")) {
- idx = modem_wait_reply (fd, 3, ati_responses, terminators, &term_idx, &reply);
- if (0 == term_idx && 0 == idx) {
- verbose ("ATI response: %s", reply);
- ret = parse_gcap (ati_responses[idx], TRUE, reply);
- } else if (0 == term_idx && 1 == idx) {
- verbose ("ATI response: %s", reply);
- ret = parse_gcap (ati_responses[idx], FALSE, reply);
- }
- }
- }
-
- g_free (reply);
- reply = NULL;
-
- /* Try an alternate method on some hardware (ex BUSlink SCWi275u) */
- if ((idx != -2) && !(ret & MODEM_CAP_GSM) && !(ret & MODEM_CAP_IS707_A)) {
- const char *cgmm_responses[] = { CGMM_TAG, NULL };
-
- if (modem_send_command (fd, "AT+CGMM\r\n")) {
- idx = modem_wait_reply (fd, 5, cgmm_responses, terminators, &term_idx, &reply);
- if (0 == term_idx && 0 == idx) {
- verbose ("CGMM response: %s", reply);
- ret |= parse_cgmm (reply);
- }
- g_free (reply);
- }
- }
-
- return ret;
-}
-
-static void
-print_usage (void)
-{
- printf("Usage: probe-modem [options] <device>\n"
- " --export export key/value pairs\n"
- " --delay <ms> 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 <file> log all output\n"
- " --vid <vid> USB Vendor ID (optional)\n"
- " --pid <pid> USB Product ID (optional)\n"
- " --usb-interface <num> USB device interface number (optional)\n"
- " --driver <name> Linux kernel device driver (optional)\n"
- " --help\n\n");
-}
-
-int
-main(int argc, char *argv[])
-{
- static const struct option options[] = {
- { "export", 0, NULL, 'x' },
- { "delay", required_argument, NULL, 'a' },
- { "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 *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, last_err = 0;
- unsigned long int tmp;
-
- while (1) {
- int option;
-
- option = getopt_long (argc, argv, "xvl:qh", options, NULL);
- if (option == -1)
- break;
-
- switch (option) {
- case 'x':
- export = TRUE;
- break;
- case 'a':
- 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;
- break;
- 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;
- case 'h':
- print_usage ();
- return 0;
- default:
- return 1;
- }
- }
-
- if (logpath) {
- time_t t = time (NULL);
-
- logfile = fopen (logpath, "a+");
- if (!logfile) {
- fprintf (stderr, "Couldn't open/create logfile %s", logpath);
- return 2;
- }
-
- fprintf (logfile, "\n**** Started: %s\n", ctime (&t));
- g_set_printerr_handler (printerr_handler);
- }
-
- g_set_print_handler (print_handler);
-
- device = argv[optind];
- if (device == NULL) {
- g_printerr ("no node specified\n");
- ret = 3;
- goto exit;
- }
-
- verbose ("(%s): usb-vid 0x%04x usb-pid 0x%04x usb-intf %d driver '%s'",
- device, vid, pid, usbif, driver);
-
- /* 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_MM_MODEM_PROBED=1\n");
- goto exit;
- }
-
- verbose ("probing %s", device);
-
- /* If a delay was specified, retry opening the serial port for that
- * amount of time. Some devices (nozomi) aren't ready to be opened
- * even though their device node is created by udev already.
- */
- do {
- fd = open (device, O_RDWR | O_EXCL | O_NONBLOCK);
- if (fd < 0) {
- last_err = errno;
- g_usleep (500000);
- delay_ms -= 500;
- }
- } while (fd < 0 && delay_ms > 0);
-
- if (fd < 0) {
- g_printerr ("open(%s) failed: %d\n", device, last_err);
- ret = 4;
- goto exit;
- }
-
- if (tcgetattr (fd, &orig)) {
- g_printerr ("tcgetattr(%s): failed %d\n", device, errno);
- ret = 5;
- goto exit;
- }
-
- memcpy (&attrs, &orig, sizeof (attrs));
- attrs.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR);
- attrs.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
- attrs.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
- attrs.c_lflag &= ~(ECHO | ECHOE);
- attrs.c_cc[VMIN] = 1;
- attrs.c_cc[VTIME] = 0;
- attrs.c_cc[VEOF] = 1;
-
- attrs.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
- attrs.c_cflag |= (B9600 | CS8 | CREAD | PARENB);
-
- tcsetattr (fd, TCSANOW, &attrs);
- caps = modem_probe_caps (fd, delay_ms);
- tcsetattr (fd, TCSANOW, &orig);
-
- if (caps < 0) {
- g_printerr ("%s: couldn't get modem capabilities\n", device);
- if (export)
- printf ("ID_MM_MODEM_PROBED=1\n");
- goto exit;
- }
-
- if (export) {
- if (caps & MODEM_CAP_GSM)
- printf ("ID_MM_MODEM_GSM=1\n");
- if (caps & MODEM_CAP_IS707_A)
- printf ("ID_MM_MODEM_IS707_A=1\n");
- if (caps & MODEM_CAP_IS707_P)
- printf ("ID_MM_MODEM_IS707P=1\n");
- if (caps & MODEM_CAP_IS856)
- printf ("ID_MM_MODEM_IS856=1\n");
- if (caps & MODEM_CAP_IS856_A)
- printf ("ID_MM_MODEM_IS856_A=1\n");
- printf ("ID_MM_MODEM_PROBED=1\n");
- }
-
- verbose ("%s: caps (0x%X)%s%s%s%s\n", device, caps,
- caps & MODEM_CAP_GSM ? " GSM" : "",
- caps & (MODEM_CAP_IS707_A | MODEM_CAP_IS707_P) ? " CDMA-1x" : "",
- caps & MODEM_CAP_IS856 ? " EVDOr0" : "",
- caps & MODEM_CAP_IS856_A ? " EVDOrA" : "");
-
-exit:
- if (fd >= 0)
- close (fd);
- if (logfile)
- fclose (logfile);
- return ret;
-}
-