summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2008-12-15 16:02:45 -0500
committerDan Williams <dcbw@redhat.com>2008-12-15 16:02:45 -0500
commitbcb7f24b97c246e55960c362a70e2c6f485ecf4e (patch)
treeedfb642173862cdce7fcd1547dabd7ec78b2bc94
initial bits
-rw-r--r--Makefile.am5
-rwxr-xr-xautogen.sh21
-rw-r--r--configure.ac96
-rw-r--r--probe-modem/62-probe-modem-capabilities.rules12
-rw-r--r--probe-modem/Makefile75
-rw-r--r--probe-modem/Makefile.am12
-rw-r--r--probe-modem/probe-modem.826
-rw-r--r--probe-modem/probe-modem.c408
8 files changed, 655 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..e3041e4
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = probe-modem option-zerocd
+
+EXTRA_DIST = \
+ CONTRIBUTING
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..8eede66
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+REQUIRED_AUTOMAKE_VERSION=1.9
+PKG_NAME=udev-extras
+
+(test -f $srcdir/configure.ac \
+ && test -f $srcdir/src/NetworkManager.c) || {
+ echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+ echo " top-level $PKG_NAME directory"
+ exit 1
+}
+
+(cd $srcdir;
+ autoreconf --install --symlink &&
+ autoreconf &&
+ ./configure --enable-maintainer-mode $@
+)
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..489e9b1
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,96 @@
+AC_PREREQ(2.52)
+
+AC_INIT(udev-extras, 0.1, dcbw@redhat.com, udev-extras)
+AM_INIT_AUTOMAKE([1.9 subdir-objects tar-ustar])
+AM_MAINTAINER_MODE
+
+AC_CONFIG_HEADERS(config.h)
+
+dnl
+dnl Require programs
+dnl
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+dnl ensure that when the Automake generated makefile calls aclocal,
+dnl it honours the $ACLOCAL_FLAGS environment variable
+ACLOCAL_AMFLAGS="\${ACLOCAL_FLAGS}"
+if test -n "$ac_macro_dir"; then
+ ACLOCAL_AMFLAGS="-I $ac_macro_dir $ACLOCAL_AMFLAGS"
+fi
+AC_SUBST([ACLOCAL_AMFLAGS])
+
+dnl maintainer mode stuff
+if test $USE_MAINTAINER_MODE = yes; then
+ DISABLE_DEPRECATED="-DG_DISABLE_DEPRECATED"
+else
+ DISABLE_DEPRECATED=""
+fi
+AC_SUBST(DISABLE_DEPRECATED)
+
+dnl
+dnl Required headers
+dnl
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h paths.h sys/ioctl.h sys/time.h syslog.h unistd.h)
+
+dnl
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl
+AC_TYPE_MODE_T
+AC_TYPE_PID_T
+AC_HEADER_TIME
+
+dnl
+dnl Checks for library functions.
+dnl
+AC_PROG_GCC_TRADITIONAL
+AC_FUNC_MEMCMP
+AC_CHECK_FUNCS(select socket uname)
+
+dnl
+dnl Make sha1.c happy on big endian systems
+dnl
+AC_C_BIGENDIAN
+
+PKG_CHECK_MODULES(GLIB, glib-2 >= 2.12)
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+AC_ARG_ENABLE(more-warnings,
+AS_HELP_STRING([--enable-more-warnings], [Maximum compiler warnings]), set_more_warnings="$enableval",set_more_warnings=yes)
+AC_MSG_CHECKING(for more warnings, including -Werror)
+if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then
+ AC_MSG_RESULT(yes)
+ CFLAGS="-Wall -Werror -std=gnu89 $CFLAGS"
+
+ for option in -Wshadow -Wmissing-declarations -Wmissing-prototypes \
+ -Wdeclaration-after-statement -Wstrict-prototypes \
+ -Wfloat-equal -Wno-unused-parameter -Wno-sign-compare \
+ -fno-strict-aliasing; do
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $option"
+ AC_MSG_CHECKING([whether gcc understands $option])
+ AC_TRY_COMPILE([], [],
+ has_option=yes,
+ has_option=no,)
+ if test $has_option = no; then
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ AC_MSG_RESULT($has_option)
+ unset has_option
+ unset SAVE_CFLAGS
+ done
+ unset option
+else
+ AC_MSG_RESULT(no)
+fi
+
+AC_CONFIG_FILES([
+Makefile
+probe-modem/Makefile
+])
+AC_OUTPUT
+
diff --git a/probe-modem/62-probe-modem-capabilities.rules b/probe-modem/62-probe-modem-capabilities.rules
new file mode 100644
index 0000000..b430fe9
--- /dev/null
+++ b/probe-modem/62-probe-modem-capabilities.rules
@@ -0,0 +1,12 @@
+# do not edit this file, it will be overwritten on update
+
+ACTION!="add", GOTO="persistent_storage_edd_end"
+SUBSYSTEM!="block", GOTO="persistent_storage_edd_end"
+KERNEL!="sd*|hd*", GOTO="persistent_storage_edd_end"
+
+# BIOS Enhanced Disk Device
+ENV{DEVTYPE}=="disk", IMPORT{program}="edd_id --export $tempnode"
+ENV{DEVTYPE}=="disk", ENV{ID_EDD}=="?*", SYMLINK+="disk/by-id/edd-$env{ID_EDD}"
+ENV{DEVTYPE}=="partition", ENV{ID_EDD}=="?*", SYMLINK+="disk/by-id/edd-$env{ID_EDD}-part%n"
+
+LABEL="persistent_storage_edd_end"
diff --git a/probe-modem/Makefile b/probe-modem/Makefile
new file mode 100644
index 0000000..d6bf459
--- /dev/null
+++ b/probe-modem/Makefile
@@ -0,0 +1,75 @@
+# Makefile for udev extra invoked from the udev main Makefile
+#
+# Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
+#
+# Released under the GNU General Public License, version 2.
+#
+
+PROG = modem_caps
+OBJ =
+HEADERS =
+GEN_HEADERS =
+MAN_PAGES =
+
+prefix =
+etcdir = ${prefix}/etc
+sbindir = ${prefix}/sbin
+usrbindir = ${prefix}/usr/bin
+usrsbindir = ${prefix}/usr/sbin
+libudevdir = ${prefix}/lib/udev
+mandir = ${prefix}/usr/share/man
+configdir = ${etcdir}/udev/
+
+INSTALL = install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL}
+
+all: $(PROG) $(MAN_PAGES)
+.PHONY: all
+.DEFAULT: all
+
+%.o: %.c $(GEN_HEADERS)
+ $(E) " CC " $@
+ $(Q) $(CC) -c $(CFLAGS) $< -o $@
+
+$(PROG): %: $(HEADERS) %.o $(OBJS)
+ $(E) " LD " $@
+ $(Q) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
+
+# man pages
+%.8: %.xml
+ $(E) " XMLTO " $@
+ $(Q) xmlto man $?
+.PRECIOUS: %.8
+
+clean:
+ $(E) " CLEAN "
+ $(Q) rm -f $(PROG) $(OBJS) $(GEN_HEADERS)
+.PHONY: clean
+
+install-bin: all
+ $(INSTALL) -d $(DESTDIR)$(libudevdir)
+ $(INSTALL_PROGRAM) $(PROG) $(DESTDIR)$(libudevdir)/$(PROG)
+ $(INSTALL) -d $(DESTDIR)$(configdir)/rules.d/
+ $(INSTALL_DATA) 62-probe-modem-capabilities.rules $(DESTDIR)$(configdir)/rules.d/62-probe-modem-capabilities.rules
+.PHONY: install-bin
+
+uninstall-bin:
+ - rm $(DESTDIR)$(libudevdir)/$(PROG)
+ - rm $(DESTDIR)$(configdir)/rules.d/62-probe-modem-capabilities.rules
+.PHONY: uninstall-bin
+
+install-man:
+ $(INSTALL) -d $(DESTDIR)$(mandir)/man8
+ $(INSTALL_DATA) $(PROG).8 $(DESTDIR)$(mandir)/man8/$(PROG).8
+.PHONY: install-man
+
+uninstall-man:
+ -rm -f $(DESTDIR)$(mandir)/man8/$(PROG).8
+.PHONY: uninstall-man
+
+install-config:
+ @echo "no config file to install"
+.PHONY: install-config
+
diff --git a/probe-modem/Makefile.am b/probe-modem/Makefile.am
new file mode 100644
index 0000000..7872d7d
--- /dev/null
+++ b/probe-modem/Makefile.am
@@ -0,0 +1,12 @@
+libudevdir = $(prefix)/lib/udev
+
+libudev_PROGRAMS = probe-modem
+probe_modem_SOURCES = probe-modem.c
+probe_modem_CPPFLAGS = $(GLIB_CFLAGS)
+probe_modem_LDADD = $(GLIB_LDFLAGS)
+
+rulesdir = $(sysconfdir)/udev/
+rules_DATA = 62-probe-modem-capabilities.rules
+
+man_MANS = probe-modem.8
+
diff --git a/probe-modem/probe-modem.8 b/probe-modem/probe-modem.8
new file mode 100644
index 0000000..158bac0
--- /dev/null
+++ b/probe-modem/probe-modem.8
@@ -0,0 +1,26 @@
+.TH EDD_ID 8 "November 2005" "" "Linux Administrator's Manual"
+.SH NAME
+modem_caps \- udev callout to identify Hayes-compatible modem capabilities
+.SH SYNOPSIS
+.BI modem_caps
+[\fI--export\fP] \fI<devpath>\fP
+.SH "DESCRIPTION"
+.B modem_caps
+is normally called from a udev rule, to provide udev with the modem
+capabilities for Hayes-compatible modems.
+.SH USAGE
+.B modem_caps
+opens the tty node specified at the commandline and prints the
+discovered modem capabilities.
+.SH OPTIONS
+The following commandline switches are supported to specify what modem_caps
+should print:
+.TP
+.BI --export
+print values as environment keys
+.RE
+.SH SEE ALSO
+.BR udev (7)
+.SH AUTHORS
+Developed by Dan Williams <dcbw@redhat.com>.
+
diff --git a/probe-modem/probe-modem.c b/probe-modem/probe-modem.c
new file mode 100644
index 0000000..8ffe964
--- /dev/null
+++ b/probe-modem/probe-modem.c
@@ -0,0 +1,408 @@
+/*
+ * 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 version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#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 <glib.h>
+
+#include "../../udev.h"
+
+#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;
+
+struct modem_caps {
+ char *name;
+ guint32 bits;
+};
+
+static struct modem_caps modem_caps[] = {
+ {"+CGSM", MODEM_CAP_GSM},
+ {"+CIS707-A", MODEM_CAP_IS707_A},
+ {"+CIS707", MODEM_CAP_IS707_A},
+ {"+CIS707P", MODEM_CAP_IS707_P},
+ {"CIS-856", MODEM_CAP_IS856},
+ {"CIS-856-A", MODEM_CAP_IS856_A},
+ {"+DS", MODEM_CAP_DS},
+ {"+ES", MODEM_CAP_ES},
+ {"+MS", MODEM_CAP_MS},
+ {"+FCLASS", MODEM_CAP_FCLASS},
+ {NULL}
+};
+
+#define debug(fmt, args...) \
+if (verbose) { \
+ g_printerr ("%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;
+
+ debug ("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
+
+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);
+
+ debug ("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));
+
+ g_string_free (result, TRUE);
+ return reply_index;
+}
+
+#define GCAP_TAG "+GCAP:"
+#define GMM_TAG "+GMM:"
+
+static int
+parse_gcap (const char *buf)
+{
+ const char *p = buf + strlen (GCAP_TAG);
+ char **caps, **iter;
+ int ret = 0;
+
+ caps = g_strsplit_set (p, " ,\t", 0);
+ if (!caps)
+ return -1;
+
+ 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_gmm (const char *buf)
+{
+ const char *p = buf + strlen (GMM_TAG);
+ char **gmm, **iter;
+ gboolean gsm = FALSE;
+
+ gmm = g_strsplit_set (p, " ,\t", 0);
+ if (!gmm)
+ return -1;
+
+ /* BUSlink SCWi275u USB GPRS modem */
+ for (iter = gmm; *iter && !gsm; iter++) {
+ if (strstr (*iter, "GSM900") || strstr (*iter, "GSM1800") ||
+ strstr (*iter, "GSM1900") || strstr (*iter, "GSM850"))
+ gsm = TRUE;
+ }
+
+ g_strfreev (gmm);
+ return gsm ? MODEM_CAP_GSM : 0;
+}
+
+static int modem_probe_caps(int fd)
+{
+ const char *gcap_responses[] = { GCAP_TAG, NULL };
+ const char *terminators[] = { "OK", "ERROR", "ERR", NULL };
+ char *reply = NULL;
+ int idx, term_idx, ret = -1;
+
+ if (!modem_send_command (fd, "AT+GCAP\r\n"))
+ return -1;
+
+ idx = modem_wait_reply (fd, 3, gcap_responses, terminators, &term_idx, &reply);
+ if (0 == term_idx && 0 == idx) {
+ /* Success */
+ debug ("GCAP response: %s", reply);
+ ret = parse_gcap (reply);
+ } else if (1 == term_idx || 2 == term_idx) {
+ const char *ati_responses[] = { GCAP_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;
+
+ 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) {
+ debug ("ATI response: %s", reply);
+ ret = parse_gcap (reply);
+ }
+ }
+ }
+ g_free (reply);
+ reply = NULL;
+
+ /* Try an alternate method on some hardware (ex BUSlink SCWi275u) */
+ if (!(ret & MODEM_CAP_GSM) && !(ret & MODEM_CAP_IS707_A)) {
+ const char *gmm_responses[] = { GMM_TAG, NULL };
+
+ if (modem_send_command (fd, "AT+GMM\r\n")) {
+ idx = modem_wait_reply (fd, 5, gmm_responses, terminators, &term_idx, &reply);
+ if (0 == term_idx && 0 == idx) {
+ debug ("GMM response: %s", reply);
+ ret |= parse_gmm (reply);
+ }
+ g_free (reply);
+ }
+ }
+
+ return ret;
+}
+
+void
+print_usage (void)
+{
+ printf("Usage: modem_caps [options] <device>\n"
+ " --export export key/value pairs\n"
+ " --verbose print verbose debugging output\n"
+ " --help\n\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ static const struct option options[] = {
+ { "export", 0, NULL, 'x' },
+ { "verbose", 0, NULL, 'v' },
+ { "help", 0, NULL, 'h' },
+ {}
+ };
+
+ const char *device = NULL;
+ int i;
+ gboolean export = 0;
+ struct termios orig, attrs;
+ char *udi;
+ int fd, caps;
+
+ while (1) {
+ int option;
+
+ option = getopt_long(argc, argv, "xvh", options, NULL);
+ if (option == -1)
+ break;
+
+ switch (option) {
+ case 'x':
+ export = TRUE;
+ break;
+ case 'v':
+ verbose = TRUE;
+ break;
+ case 'h':
+ print_usage ();
+ return 1;
+ default:
+ return 1;
+ }
+ }
+
+ device = argv[optind];
+ if (device == NULL) {
+ g_printerr ("no node specified\n");
+ return 2;
+ }
+
+ fd = open (device, O_RDWR | O_EXCL | O_NONBLOCK);
+ if (fd < 0) {
+ g_printerr ("open(%s) failed: %d\n", device, errno);
+ return 3;
+ }
+
+ if (tcgetattr (fd, &orig)) {
+ g_printerr ("tcgetattr(%s): failed %d\n", device, errno);
+ return 4;
+ }
+
+ 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 | 0 | 0 | 0);
+
+ tcsetattr (fd, TCSANOW, &attrs);
+ caps = modem_probe_caps (fd);
+ tcsetattr (fd, TCSANOW, &orig);
+
+ if (caps < 0) {
+ g_printerr ("%s: couldn't get modem capabilities\n", device);
+ return 5;
+ }
+
+ if (export) {
+ if (caps & MODEM_CAP_GSM)
+ g_print ("ID_MODEM_GSM=1\n");
+ if (caps & MODEM_CAP_IS707_A)
+ g_print ("ID_MODEM_IS707_A=1\n");
+ if (caps & MODEM_CAP_IS707P)
+ g_print ("ID_MODEM_IS707P=1\n");
+ if (caps & MODEM_CAP_IS856)
+ g_print ("ID_MODEM_IS856=1\n");
+ if (caps & MODEM_CAP_IS856_A)
+ g_print ("ID_MODEM_IS856_A=1\n");
+ } else {
+ g_print ("%s: caps 0x%X%s%s%s%s\n", device, caps,
+ caps & MODEM_CAP_GSM ? " GSM" : "",
+ caps & (MODEM_CAP_IS707_A | MODEM_CAP_IS707P) ? " CDMA-1x" : "",
+ caps & MODEM_CAP_IS856 ? " EVDOr0" : "",
+ caps & MODEM_CAP_IS856_A ? " EVDOrA" : "");
+ }
+
+ return 0;
+}
+