aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--callouts/77-mm-modem-probe-capabilities.rules23
-rw-r--r--callouts/Makefile.am13
-rw-r--r--callouts/mm-modem-probe.c639
-rw-r--r--marshallers/mm-marshal.list1
-rw-r--r--plugins/Makefile.am66
-rw-r--r--plugins/mm-modem-hso.c1
-rw-r--r--plugins/mm-modem-huawei.c6
-rw-r--r--plugins/mm-modem-nokia.c69
-rw-r--r--plugins/mm-modem-nokia.h19
-rw-r--r--plugins/mm-modem-novatel-cdma.c73
-rw-r--r--plugins/mm-modem-novatel-cdma.h28
-rw-r--r--plugins/mm-modem-novatel-gsm.c103
-rw-r--r--plugins/mm-modem-novatel-gsm.h19
-rw-r--r--plugins/mm-modem-option.c42
-rw-r--r--plugins/mm-modem-option.h19
-rw-r--r--plugins/mm-modem-sierra.c80
-rw-r--r--plugins/mm-modem-sierra.h19
-rw-r--r--plugins/mm-modem-zte.c129
-rw-r--r--plugins/mm-modem-zte.h19
-rw-r--r--plugins/mm-plugin-generic.c288
-rw-r--r--plugins/mm-plugin-gobi.c298
-rw-r--r--plugins/mm-plugin-hso.c240
-rw-r--r--plugins/mm-plugin-huawei.c405
-rw-r--r--plugins/mm-plugin-moto-c.c241
-rw-r--r--plugins/mm-plugin-nokia.c223
-rw-r--r--plugins/mm-plugin-nokia.h21
-rw-r--r--plugins/mm-plugin-novatel.c253
-rw-r--r--plugins/mm-plugin-novatel.h20
-rw-r--r--plugins/mm-plugin-option.c219
-rw-r--r--plugins/mm-plugin-option.h20
-rw-r--r--plugins/mm-plugin-sierra.c246
-rw-r--r--plugins/mm-plugin-sierra.h20
-rw-r--r--plugins/mm-plugin-zte.c219
-rw-r--r--plugins/mm-plugin-zte.h20
-rw-r--r--src/mm-generic-cdma.c1
-rw-r--r--src/mm-generic-gsm.c1
-rw-r--r--src/mm-manager.c313
-rw-r--r--src/mm-modem-base.c2
-rw-r--r--src/mm-modem.c3
-rw-r--r--src/mm-modem.h2
-rw-r--r--src/mm-plugin-base.c796
-rw-r--r--src/mm-plugin-base.h89
-rw-r--r--src/mm-plugin.c21
-rw-r--r--src/mm-plugin.h61
-rw-r--r--src/mm-serial-parsers.c8
-rw-r--r--src/mm-serial-port.c1
47 files changed, 2888 insertions, 2513 deletions
diff --git a/Makefile.am b/Makefile.am
index 0964e1bb..f7e7f7de 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,7 +20,7 @@ clean:
rm -f $(GENERATED_FILES)
endif
-SUBDIRS = marshallers callouts src plugins introspection test
+SUBDIRS = marshallers src plugins introspection test
dbusservicedir = $(DBUS_SYS_DIR)
dbusservice_DATA = org.freedesktop.ModemManager.conf
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;
-}
-
diff --git a/marshallers/mm-marshal.list b/marshallers/mm-marshal.list
index 48b99135..ad6a4a10 100644
--- a/marshallers/mm-marshal.list
+++ b/marshallers/mm-marshal.list
@@ -1,2 +1,3 @@
VOID:UINT,STRING,STRING
VOID:STRING,STRING,UINT
+VOID:OBJECT,UINT
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 11cdfd0b..3d8f6167 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -4,12 +4,12 @@ pkglib_LTLIBRARIES = \
libmm-plugin-gobi.la \
libmm-plugin-huawei.la \
libmm-plugin-hso.la \
- libmm-plugin-mbm.la \
libmm-plugin-option.la \
libmm-plugin-sierra.la \
libmm-plugin-novatel.la \
libmm-plugin-nokia.la \
- libmm-plugin-zte.la
+ libmm-plugin-zte.la \
+ libmm-plugin-mbm.la
# Generic
@@ -120,74 +120,92 @@ libmm_plugin_mbm_la_LDFLAGS = -module -avoid-version
# Option
libmm_plugin_option_la_SOURCES = \
- mm-modem-option.c \
- mm-modem-option.h \
mm-plugin-option.c \
- mm-plugin-option.h
+ mm-plugin-option.h \
+ mm-modem-option.c \
+ mm-modem-option.h
libmm_plugin_option_la_CPPFLAGS = \
$(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
-I$(top_srcdir)/src
-libmm_plugin_option_la_LDFLAGS = -module -avoid-version
+libmm_plugin_option_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
# Sierra
libmm_plugin_sierra_la_SOURCES = \
- mm-modem-sierra.c \
- mm-modem-sierra.h \
mm-plugin-sierra.c \
- mm-plugin-sierra.h
+ mm-plugin-sierra.h \
+ mm-modem-sierra.c \
+ mm-modem-sierra.h
libmm_plugin_sierra_la_CPPFLAGS = \
$(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
-I$(top_srcdir)/src
-libmm_plugin_sierra_la_LDFLAGS = -module -avoid-version
+libmm_plugin_sierra_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
# Novatel
libmm_plugin_novatel_la_SOURCES = \
- mm-modem-novatel-cdma.c \
- mm-modem-novatel-cdma.h \
- mm-modem-novatel-gsm.c \
- mm-modem-novatel-gsm.h \
mm-plugin-novatel.c \
- mm-plugin-novatel.h
+ mm-plugin-novatel.h \
+ mm-modem-novatel-gsm.c \
+ mm-modem-novatel-gsm.h
libmm_plugin_novatel_la_CPPFLAGS = \
$(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
-I$(top_srcdir)/src
-libmm_plugin_novatel_la_LDFLAGS = -module -avoid-version
+libmm_plugin_novatel_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
# Nokia
libmm_plugin_nokia_la_SOURCES = \
- mm-modem-nokia.c \
- mm-modem-nokia.h \
mm-plugin-nokia.c \
- mm-plugin-nokia.h
+ mm-plugin-nokia.h \
+ mm-modem-nokia.c \
+ mm-modem-nokia.h
libmm_plugin_nokia_la_CPPFLAGS = \
$(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
-I$(top_srcdir)/src
-libmm_plugin_nokia_la_LDFLAGS = -module -avoid-version
+libmm_plugin_nokia_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
# Zte
libmm_plugin_zte_la_SOURCES = \
- mm-modem-zte.c \
- mm-modem-zte.h \
mm-plugin-zte.c \
- mm-plugin-zte.h
+ mm-plugin-zte.h \
+ mm-modem-zte.c \
+ mm-modem-zte.h
libmm_plugin_zte_la_CPPFLAGS = \
$(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
-I$(top_srcdir)/src
-libmm_plugin_zte_la_LDFLAGS = -module -avoid-version
+libmm_plugin_zte_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
BUILT_SOURCES = \
diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c
index 10800184..39c3e42b 100644
--- a/plugins/mm-modem-hso.c
+++ b/plugins/mm-modem-hso.c
@@ -564,6 +564,7 @@ static gboolean
grab_port (MMModem *modem,
const char *subsys,
const char *name,
+ gpointer user_data,
GError **error)
{
MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
diff --git a/plugins/mm-modem-huawei.c b/plugins/mm-modem-huawei.c
index 67d4d812..43ee34d1 100644
--- a/plugins/mm-modem-huawei.c
+++ b/plugins/mm-modem-huawei.c
@@ -496,10 +496,12 @@ handle_status_change (MMSerialPort *port,
/*****************************************************************************/
+/* user_data != NULL means the port is a secondary port */
static gboolean
grab_port (MMModem *modem,
const char *subsys,
const char *name,
+ gpointer user_data,
GError **error)
{
MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
@@ -531,7 +533,7 @@ grab_port (MMModem *modem,
if (usbif == 0) {
if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
ptype = MM_PORT_TYPE_PRIMARY;
- } else if (usbif == 1) {
+ } else if (user_data) {
if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
ptype = MM_PORT_TYPE_SECONDARY;
}
@@ -545,8 +547,6 @@ grab_port (MMModem *modem,
if (ptype == MM_PORT_TYPE_SECONDARY) {
GRegex *regex;
- g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL);
-
mm_generic_gsm_set_unsolicited_registration (MM_GENERIC_GSM (modem), TRUE);
regex = g_regex_new ("\\r\\n\\^RSSI:(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
diff --git a/plugins/mm-modem-nokia.c b/plugins/mm-modem-nokia.c
index 8a81cbeb..a37c1143 100644
--- a/plugins/mm-modem-nokia.c
+++ b/plugins/mm-modem-nokia.c
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <stdlib.h>
#include <stdio.h>
@@ -10,28 +24,59 @@
static gpointer mm_modem_nokia_parent_class = NULL;
MMModem *
-mm_modem_nokia_new (const char *data_device,
- const char *driver)
+mm_modem_nokia_new (const char *device,
+ const char *driver,
+ const char *plugin)
{
- g_return_val_if_fail (data_device != NULL, NULL);
+ g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_NOKIA,
- MM_SERIAL_DEVICE, data_device,
+ MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
- MM_MODEM_TYPE, MM_MODEM_TYPE_GSM,
+ MM_MODEM_PLUGIN, plugin,
NULL));
}
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ gpointer user_data,
+ GError **error)
+{
+ MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
+ MMPortType ptype = MM_PORT_TYPE_IGNORED;
+ MMPort *port = NULL;
+
+ if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ ptype = MM_PORT_TYPE_SECONDARY;
+
+ port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
+ if (port && MM_IS_SERIAL_PORT (port)) {
+ mm_serial_port_set_response_parser (MM_SERIAL_PORT (port),
+ mm_serial_parser_v1_e1_parse,
+ mm_serial_parser_v1_e1_new (),
+ mm_serial_parser_v1_e1_destroy);
+ }
+
+ return !!port;
+}
+
/*****************************************************************************/
static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->grab_port = grab_port;
+}
+
+static void
mm_modem_nokia_init (MMModemNokia *self)
{
- mm_serial_set_response_parser (MM_SERIAL (self),
- mm_serial_parser_v1_e1_parse,
- mm_serial_parser_v1_e1_new (),
- mm_serial_parser_v1_e1_destroy);
}
static void
@@ -58,7 +103,13 @@ mm_modem_nokia_get_type (void)
(GInstanceInitFunc) mm_modem_nokia_init,
};
+ static const GInterfaceInfo modem_iface_info = {
+ (GInterfaceInitFunc) modem_init
+ };
+
modem_nokia_type = g_type_register_static (MM_TYPE_GENERIC_GSM, "MMModemNokia", &modem_nokia_type_info, 0);
+
+ g_type_add_interface_static (modem_nokia_type, MM_TYPE_MODEM, &modem_iface_info);
}
return modem_nokia_type;
diff --git a/plugins/mm-modem-nokia.h b/plugins/mm-modem-nokia.h
index b287b164..0e24619f 100644
--- a/plugins/mm-modem-nokia.h
+++ b/plugins/mm-modem-nokia.h
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_MODEM_NOKIA_H
#define MM_MODEM_NOKIA_H
@@ -22,7 +36,8 @@ typedef struct {
GType mm_modem_nokia_get_type (void);
-MMModem *mm_modem_nokia_new (const char *data_device,
- const char *driver);
+MMModem *mm_modem_nokia_new (const char *data,
+ const char *driver,
+ const char *plugin);
#endif /* MM_MODEM_NOKIA_H */
diff --git a/plugins/mm-modem-novatel-cdma.c b/plugins/mm-modem-novatel-cdma.c
deleted file mode 100644
index 4b6b9b2e..00000000
--- a/plugins/mm-modem-novatel-cdma.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include "mm-modem-novatel-cdma.h"
-#include "mm-errors.h"
-#include "mm-callback-info.h"
-
-static gpointer mm_modem_novatel_cdma_parent_class = NULL;
-
-MMModem *
-mm_modem_novatel_cdma_new (const char *data_device,
- const char *driver)
-{
- g_return_val_if_fail (data_device != NULL, NULL);
- g_return_val_if_fail (driver != NULL, NULL);
-
- return MM_MODEM (g_object_new (MM_TYPE_MODEM_NOVATEL_CDMA,
- MM_SERIAL_DEVICE, data_device,
- MM_SERIAL_CARRIER_DETECT, FALSE,
- MM_MODEM_DRIVER, driver,
- MM_MODEM_TYPE, MM_MODEM_TYPE_CDMA,
- NULL));
-}
-
-/*****************************************************************************/
-
-static void
-modem_init (MMModem *modem_class)
-{
-}
-
-static void
-mm_modem_novatel_cdma_init (MMModemNovatelCdma *self)
-{
-}
-
-static void
-mm_modem_novatel_cdma_class_init (MMModemNovatelCdmaClass *klass)
-{
- mm_modem_novatel_cdma_parent_class = g_type_class_peek_parent (klass);
-}
-
-GType
-mm_modem_novatel_cdma_get_type (void)
-{
- static GType modem_novatel_cdma_type = 0;
-
- if (G_UNLIKELY (modem_novatel_cdma_type == 0)) {
- static const GTypeInfo modem_novatel_cdma_type_info = {
- sizeof (MMModemNovatelCdmaClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) mm_modem_novatel_cdma_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (MMModemNovatelCdma),
- 0, /* n_preallocs */
- (GInstanceInitFunc) mm_modem_novatel_cdma_init,
- };
-
- static const GInterfaceInfo modem_iface_info = {
- (GInterfaceInitFunc) modem_init
- };
-
- modem_novatel_cdma_type = g_type_register_static (MM_TYPE_GENERIC_CDMA, "MMModemNovatelCdma", &modem_novatel_cdma_type_info, 0);
- g_type_add_interface_static (modem_novatel_cdma_type, MM_TYPE_MODEM, &modem_iface_info);
- }
-
- return modem_novatel_cdma_type;
-}
diff --git a/plugins/mm-modem-novatel-cdma.h b/plugins/mm-modem-novatel-cdma.h
deleted file mode 100644
index d9b9d33a..00000000
--- a/plugins/mm-modem-novatel-cdma.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-
-#ifndef MM_MODEM_NOVATEL_CDMA_H
-#define MM_MODEM_NOVATEL_CDMA_H
-
-#include "mm-generic-cdma.h"
-
-#define MM_TYPE_MODEM_NOVATEL_CDMA (mm_modem_novatel_cdma_get_type ())
-#define MM_MODEM_NOVATEL_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_NOVATEL_CDMA, MMModemNovatelCdma))
-#define MM_MODEM_NOVATEL_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_NOVATEL_CDMA, MMModemNovatelCdmaClass))
-#define MM_IS_MODEM_NOVATEL_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_NOVATEL_CDMA))
-#define MM_IS_MODEM_NOVATEL_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_NOVATEL_CDMA))
-#define MM_MODEM_NOVATEL_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_NOVATEL_CDMA, MMModemNovatelCdmaClass))
-
-typedef struct {
- MMGenericCdma parent;
-} MMModemNovatelCdma;
-
-typedef struct {
- MMGenericCdmaClass parent;
-} MMModemNovatelCdmaClass;
-
-GType mm_modem_novatel_cdma_get_type (void);
-
-MMModem *mm_modem_novatel_cdma_new (const char *data_device,
- const char *driver);
-
-#endif /* MM_MODEM_NOVATEL_CDMA_H */
diff --git a/plugins/mm-modem-novatel-gsm.c b/plugins/mm-modem-novatel-gsm.c
index 9c569264..265810c3 100644
--- a/plugins/mm-modem-novatel-gsm.c
+++ b/plugins/mm-modem-novatel-gsm.c
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <stdlib.h>
#include <stdio.h>
@@ -11,16 +25,18 @@
static gpointer mm_modem_novatel_gsm_parent_class = NULL;
MMModem *
-mm_modem_novatel_gsm_new (const char *data_device,
- const char *driver)
+mm_modem_novatel_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin)
{
- g_return_val_if_fail (data_device != NULL, NULL);
+ g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_NOVATEL_GSM,
- MM_SERIAL_DEVICE, data_device,
+ MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
- MM_MODEM_TYPE, MM_MODEM_TYPE_GSM,
+ MM_MODEM_PLUGIN, plugin,
NULL));
}
@@ -29,7 +45,7 @@ mm_modem_novatel_gsm_new (const char *data_device,
/*****************************************************************************/
static void
-init_modem_done (MMSerial *serial,
+init_modem_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -46,17 +62,21 @@ static void
pin_check_done (MMModem *modem, GError *error, gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMSerialPort *primary;
if (error) {
info->error = g_error_copy (error);
mm_callback_info_schedule (info);
- } else
+ } else {
/* Finish the initialization */
- mm_serial_queue_command (MM_SERIAL (modem), "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1", 10, init_modem_done, info);
+ primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+ mm_serial_port_queue_command (primary, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1", 10, init_modem_done, info);
+ }
}
static void
-pre_init_done (MMSerial *serial,
+pre_init_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -74,25 +94,25 @@ pre_init_done (MMSerial *serial,
}
static void
-enable_flash_done (MMSerial *serial, gpointer user_data)
+enable_flash_done (MMSerialPort *port, gpointer user_data)
{
- mm_serial_queue_command (serial, "E0 V1", 3, pre_init_done, user_data);
+ mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data);
}
static void
-disable_done (MMSerial *serial,
+disable_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
- mm_serial_close (serial);
+ mm_serial_port_close (port);
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
}
static void
-disable_flash_done (MMSerial *serial, gpointer user_data)
+disable_flash_done (MMSerialPort *port, gpointer user_data)
{
- mm_serial_queue_command (serial, "+CFUN=0", 5, disable_done, user_data);
+ mm_serial_port_queue_command (port, "+CFUN=0", 5, disable_done, user_data);
}
static void
@@ -102,32 +122,75 @@ enable (MMModem *modem,
gpointer user_data)
{
MMCallbackInfo *info;
+ MMSerialPort *primary;
/* First, reset the previously used CID */
mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
info = mm_callback_info_new (modem, callback, user_data);
+ primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
if (!do_enable) {
- if (mm_serial_is_connected (MM_SERIAL (modem)))
- mm_serial_flash (MM_SERIAL (modem), 1000, disable_flash_done, info);
+ if (mm_serial_port_is_connected (primary))
+ mm_serial_port_flash (primary, 1000, disable_flash_done, info);
else
- disable_flash_done (MM_SERIAL (modem), info);
+ disable_flash_done (primary, info);
} else {
- if (mm_serial_open (MM_SERIAL (modem), &info->error))
- mm_serial_flash (MM_SERIAL (modem), 100, enable_flash_done, info);
+ if (mm_serial_port_open (primary, &info->error))
+ mm_serial_port_flash (primary, 100, enable_flash_done, info);
if (info->error)
mm_callback_info_schedule (info);
}
}
+static void
+dmat_callback (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ mm_serial_port_close (port);
+}
+
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ gpointer user_data,
+ GError **error)
+{
+ MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
+ MMPortType ptype = MM_PORT_TYPE_IGNORED;
+ MMPort *port = NULL;
+
+ if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ ptype = MM_PORT_TYPE_SECONDARY;
+
+ port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
+ if (!port)
+ return FALSE;
+
+ if (MM_IS_SERIAL_PORT (port) && (ptype == MM_PORT_TYPE_PRIMARY)) {
+ /* Flip secondary ports to AT mode */
+ if (mm_serial_port_open (MM_SERIAL_PORT (port), NULL))
+ mm_serial_port_queue_command (MM_SERIAL_PORT (port), "$NWDMAT=1", 2, dmat_callback, NULL);
+ }
+
+ return !!port;
+}
+
/*****************************************************************************/
static void
modem_init (MMModem *modem_class)
{
modem_class->enable = enable;
+ modem_class->grab_port = grab_port;
}
static void
diff --git a/plugins/mm-modem-novatel-gsm.h b/plugins/mm-modem-novatel-gsm.h
index cfb0c007..c2e11387 100644
--- a/plugins/mm-modem-novatel-gsm.h
+++ b/plugins/mm-modem-novatel-gsm.h
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_MODEM_NOVATEL_GSM_H
#define MM_MODEM_NOVATEL_GSM_H
@@ -22,7 +36,8 @@ typedef struct {
GType mm_modem_novatel_gsm_get_type (void);
-MMModem *mm_modem_novatel_gsm_new (const char *data_device,
- const char *driver);
+MMModem *mm_modem_novatel_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin_name);
#endif /* MM_MODEM_NOVATEL_GSM_H */
diff --git a/plugins/mm-modem-option.c b/plugins/mm-modem-option.c
index 0c77c892..f0a3bcbf 100644
--- a/plugins/mm-modem-option.c
+++ b/plugins/mm-modem-option.c
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <stdlib.h>
#include <stdio.h>
@@ -11,19 +25,23 @@
static gpointer mm_modem_option_parent_class = NULL;
MMModem *
-mm_modem_option_new (const char *data_device,
- const char *driver)
+mm_modem_option_new (const char *device,
+ const char *driver,
+ const char *plugin)
{
- g_return_val_if_fail (data_device != NULL, NULL);
+ g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_OPTION,
- MM_SERIAL_DEVICE, data_device,
+ MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
- MM_MODEM_TYPE, MM_MODEM_TYPE_GSM,
+ MM_MODEM_PLUGIN, plugin,
NULL));
}
+/*****************************************************************************/
+
static void
pin_check_done (MMModem *modem, GError *error, gpointer user_data)
{
@@ -80,7 +98,7 @@ enable (MMModem *modem,
}
static void
-get_network_mode_done (MMSerial *serial,
+get_network_mode_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -131,13 +149,16 @@ get_network_mode (MMModemGsmNetwork *modem,
gpointer user_data)
{
MMCallbackInfo *info;
+ MMSerialPort *primary;
info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- mm_serial_queue_command (MM_SERIAL (modem), "AT_OPSYS?", 3, get_network_mode_done, info);
+ primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+ mm_serial_port_queue_command (primary, "AT_OPSYS?", 3, get_network_mode_done, info);
}
static void
-set_network_mode_done (MMSerial *serial,
+set_network_mode_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -157,6 +178,7 @@ set_network_mode (MMModemGsmNetwork *modem,
gpointer user_data)
{
MMCallbackInfo *info;
+ MMSerialPort *primary;
char *command;
int i;
@@ -188,7 +210,9 @@ set_network_mode (MMModemGsmNetwork *modem,
}
command = g_strdup_printf ("AT_OPSYS=%d,2", i);
- mm_serial_queue_command (MM_SERIAL (modem), command, 3, set_network_mode_done, info);
+ primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+ mm_serial_port_queue_command (primary, command, 3, set_network_mode_done, info);
g_free (command);
}
diff --git a/plugins/mm-modem-option.h b/plugins/mm-modem-option.h
index 386be455..4e88607e 100644
--- a/plugins/mm-modem-option.h
+++ b/plugins/mm-modem-option.h
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_MODEM_OPTION_H
#define MM_MODEM_OPTION_H
@@ -22,7 +36,8 @@ typedef struct {
GType mm_modem_option_get_type (void);
-MMModem *mm_modem_option_new (const char *data_device,
- const char *driver);
+MMModem *mm_modem_option_new (const char *device,
+ const char *driver,
+ const char *plugin_name);
#endif /* MM_MODEM_OPTION_H */
diff --git a/plugins/mm-modem-sierra.c b/plugins/mm-modem-sierra.c
index 4040ed84..d3f12629 100644
--- a/plugins/mm-modem-sierra.c
+++ b/plugins/mm-modem-sierra.c
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <stdlib.h>
#include <stdio.h>
@@ -11,16 +25,18 @@
static gpointer mm_modem_sierra_parent_class = NULL;
MMModem *
-mm_modem_sierra_new (const char *data_device,
- const char *driver)
+mm_modem_sierra_new (const char *device,
+ const char *driver,
+ const char *plugin)
{
- g_return_val_if_fail (data_device != NULL, NULL);
+ g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_SIERRA,
- MM_SERIAL_DEVICE, data_device,
+ MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
- MM_MODEM_TYPE, MM_MODEM_TYPE_GSM,
+ MM_MODEM_PLUGIN, plugin,
NULL));
}
@@ -51,7 +67,7 @@ sierra_enabled (gpointer data)
}
static void
-init_done (MMSerial *serial,
+init_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -68,15 +84,15 @@ init_done (MMSerial *serial,
}
static void
-enable_flash_done (MMSerial *serial, gpointer user_data)
+enable_flash_done (MMSerialPort *port, gpointer user_data)
{
- mm_serial_queue_command (serial, "Z E0 V1 X4 &C1 +CMEE=1", 3, init_done, user_data);
+ mm_serial_port_queue_command (port, "Z E0 V1 X4 &C1 +CMEE=1", 3, init_done, user_data);
}
static void
-disable_flash_done (MMSerial *serial, gpointer user_data)
+disable_flash_done (MMSerialPort *port, gpointer user_data)
{
- mm_serial_close (serial);
+ mm_serial_port_close (port);
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
}
@@ -87,6 +103,7 @@ enable (MMModem *modem,
gpointer user_data)
{
MMCallbackInfo *info;
+ MMSerialPort *primary;
/* First, reset the previously used CID */
mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
@@ -94,25 +111,58 @@ enable (MMModem *modem,
info = mm_callback_info_new (modem, callback, user_data);
mm_callback_info_set_data (info, "sierra-enable", GINT_TO_POINTER (do_enable), NULL);
+ primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
if (!do_enable) {
- if (mm_serial_is_connected (MM_SERIAL (modem)))
- mm_serial_flash (MM_SERIAL (modem), 1000, disable_flash_done, info);
+ if (mm_serial_port_is_connected (primary))
+ mm_serial_port_flash (primary, 1000, disable_flash_done, info);
else
- disable_flash_done (MM_SERIAL (modem), info);
+ disable_flash_done (primary, info);
} else {
- if (mm_serial_open (MM_SERIAL (modem), &info->error))
- mm_serial_flash (MM_SERIAL (modem), 100, enable_flash_done, info);
+ if (mm_serial_port_open (primary, &info->error))
+ mm_serial_port_flash (primary, 100, enable_flash_done, info);
if (info->error)
mm_callback_info_schedule (info);
}
}
+
+/* user_data != NULL means the port is a secondary port */
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ gpointer user_data,
+ GError **error)
+{
+ MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
+ MMPortType ptype = MM_PORT_TYPE_IGNORED;
+ MMPort *port;
+
+ if (user_data) {
+ if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ ptype = MM_PORT_TYPE_SECONDARY;
+ } else {
+ if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ }
+
+ port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
+
+ if (MM_IS_SERIAL_PORT (port))
+ g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL);
+
+ return !!port;
+}
+
/*****************************************************************************/
static void
modem_init (MMModem *modem_class)
{
modem_class->enable = enable;
+ modem_class->grab_port = grab_port;
}
static void
diff --git a/plugins/mm-modem-sierra.h b/plugins/mm-modem-sierra.h
index 6e95b984..308eb494 100644
--- a/plugins/mm-modem-sierra.h
+++ b/plugins/mm-modem-sierra.h
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_MODEM_SIERRA_H
#define MM_MODEM_SIERRA_H
@@ -22,7 +36,8 @@ typedef struct {
GType mm_modem_sierra_get_type (void);
-MMModem *mm_modem_sierra_new (const char *data_device,
- const char *driver);
+MMModem *mm_modem_sierra_new (const char *device,
+ const char *driver,
+ const char *plugin_name);
#endif /* MM_MODEM_SIERRA_H */
diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c
index 28c74ad6..f2c0a342 100644
--- a/plugins/mm-modem-zte.c
+++ b/plugins/mm-modem-zte.c
@@ -1,26 +1,43 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "mm-modem-zte.h"
-#include "mm-serial.h"
+#include "mm-serial-port.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
static gpointer mm_modem_zte_parent_class = NULL;
MMModem *
-mm_modem_zte_new (const char *data_device,
- const char *driver)
+mm_modem_zte_new (const char *device,
+ const char *driver,
+ const char *plugin)
{
- g_return_val_if_fail (data_device != NULL, NULL);
+ g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_ZTE,
- MM_SERIAL_DEVICE, data_device,
+ MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
NULL));
}
@@ -29,7 +46,7 @@ mm_modem_zte_new (const char *data_device,
/*****************************************************************************/
static void
-init_modem_done (MMSerial *serial,
+init_modem_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -46,17 +63,21 @@ static void
pin_check_done (MMModem *modem, GError *error, gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMSerialPort *primary;
if (error) {
info->error = g_error_copy (error);
mm_callback_info_schedule (info);
- } else
+ } else {
/* Finish the initialization */
- mm_serial_queue_command (MM_SERIAL (modem), "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;", 10, init_modem_done, info);
+ primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+ mm_serial_port_queue_command (primary, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;", 10, init_modem_done, info);
+ }
}
static void
-pre_init_done (MMSerial *serial,
+pre_init_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -74,25 +95,25 @@ pre_init_done (MMSerial *serial,
}
static void
-enable_flash_done (MMSerial *serial, gpointer user_data)
+enable_flash_done (MMSerialPort *port, gpointer user_data)
{
- mm_serial_queue_command (serial, "E0 V1", 3, pre_init_done, user_data);
+ mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data);
}
static void
-disable_done (MMSerial *serial,
+disable_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
- mm_serial_close (serial);
+ mm_serial_port_close (port);
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
}
static void
-disable_flash_done (MMSerial *serial, gpointer user_data)
+disable_flash_done (MMSerialPort *port, gpointer user_data)
{
- mm_serial_queue_command (serial, "+CFUN=0", 5, disable_done, user_data);
+ mm_serial_port_queue_command (port, "+CFUN=0", 5, disable_done, user_data);
}
static void
@@ -102,57 +123,85 @@ enable (MMModem *modem,
gpointer user_data)
{
MMCallbackInfo *info;
+ MMSerialPort *primary;
/* First, reset the previously used CID */
mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
info = mm_callback_info_new (modem, callback, user_data);
+ primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
if (!do_enable) {
- if (mm_serial_is_connected (MM_SERIAL (modem)))
- mm_serial_flash (MM_SERIAL (modem), 1000, disable_flash_done, info);
+ if (mm_serial_port_is_connected (primary))
+ mm_serial_port_flash (primary, 1000, disable_flash_done, info);
else
- disable_flash_done (MM_SERIAL (modem), info);
+ disable_flash_done (primary, info);
} else {
- if (mm_serial_open (MM_SERIAL (modem), &info->error))
- mm_serial_flash (MM_SERIAL (modem), 100, enable_flash_done, info);
+ if (mm_serial_port_open (primary, &info->error))
+ mm_serial_port_flash (primary, 100, enable_flash_done, info);
if (info->error)
mm_callback_info_schedule (info);
}
}
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ gpointer user_data,
+ GError **error)
+{
+ MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
+ MMPortType ptype = MM_PORT_TYPE_IGNORED;
+ MMPort *port = NULL;
+
+ if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ ptype = MM_PORT_TYPE_SECONDARY;
+
+ port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
+ if (port && MM_IS_SERIAL_PORT (port)) {
+ GRegex *regex;
+
+ mm_generic_gsm_set_unsolicited_registration (gsm, TRUE);
+ g_object_set (port, MM_PORT_CARRIER_DETECT, FALSE, NULL);
+
+ regex = g_regex_new ("\\r\\n\\+ZUSIMR:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ g_regex_unref (regex);
+
+ regex = g_regex_new ("\\r\\n\\+ZDONR: (.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ g_regex_unref (regex);
+
+ regex = g_regex_new ("\\r\\n\\+ZPASR: (.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ g_regex_unref (regex);
+
+ regex = g_regex_new ("\\r\\n\\+ZEND\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ g_regex_unref (regex);
+ }
+
+ return !!port;
+}
+
/*****************************************************************************/
static void
modem_init (MMModem *modem_class)
{
modem_class->enable = enable;
+ modem_class->grab_port = grab_port;
}
static void
mm_modem_zte_init (MMModemZte *self)
{
- GRegex *regex;
-
- mm_generic_gsm_set_unsolicited_registration (MM_GENERIC_GSM (self), TRUE);
- g_object_set (G_OBJECT (self), MM_SERIAL_CARRIER_DETECT, FALSE, NULL);
-
- regex = g_regex_new ("\\r\\n\\+ZUSIMR:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_add_unsolicited_msg_handler (MM_SERIAL (self), regex, NULL, NULL, NULL);
- g_regex_unref (regex);
-
- regex = g_regex_new ("\\r\\n\\+ZDONR: (.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_add_unsolicited_msg_handler (MM_SERIAL (self), regex, NULL, NULL, NULL);
- g_regex_unref (regex);
-
- regex = g_regex_new ("\\r\\n\\+ZPASR: (.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_add_unsolicited_msg_handler (MM_SERIAL (self), regex, NULL, NULL, NULL);
- g_regex_unref (regex);
-
- regex = g_regex_new ("\\r\\n\\+ZEND\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_add_unsolicited_msg_handler (MM_SERIAL (self), regex, NULL, NULL, NULL);
- g_regex_unref (regex);
}
static void
diff --git a/plugins/mm-modem-zte.h b/plugins/mm-modem-zte.h
index 285dc938..112bae00 100644
--- a/plugins/mm-modem-zte.h
+++ b/plugins/mm-modem-zte.h
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_MODEM_ZTE_H
#define MM_MODEM_ZTE_H
@@ -22,7 +36,8 @@ typedef struct {
GType mm_modem_zte_get_type (void);
-MMModem *mm_modem_zte_new (const char *data_device,
- const char *driver);
+MMModem *mm_modem_zte_new (const char *device,
+ const char *driver,
+ const char *plugin);
#endif /* MM_MODEM_ZTE_H */
diff --git a/plugins/mm-plugin-generic.c b/plugins/mm-plugin-generic.c
index e8fdb9ef..fbd99079 100644
--- a/plugins/mm-plugin-generic.c
+++ b/plugins/mm-plugin-generic.c
@@ -25,291 +25,163 @@
#include <time.h>
#include <gmodule.h>
-#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
-#include <gudev/gudev.h>
#include "mm-plugin-generic.h"
#include "mm-generic-gsm.h"
#include "mm-generic-cdma.h"
+#include "mm-errors.h"
+#include "mm-serial-parsers.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginGeneric, mm_plugin_generic, MM_TYPE_PLUGIN_BASE,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginGeneric, mm_plugin_generic, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
-#define MM_PLUGIN_GENERIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_GENERIC, MMPluginGenericPrivate))
-
-typedef struct {
- GUdevClient *client;
-} MMPluginGenericPrivate;
-
-
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_GENERIC, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_GENERIC,
+ MM_PLUGIN_BASE_NAME, MM_PLUGIN_GENERIC_NAME,
+ NULL));
}
/*****************************************************************************/
-static char *
-get_driver_name (GUdevDevice *device)
-{
- GUdevDevice *parent = NULL;
- const char *driver;
- char *ret;
-
- driver = g_udev_device_get_driver (device);
- if (!driver) {
- parent = g_udev_device_get_parent (device);
- if (parent)
- driver = g_udev_device_get_driver (parent);
- }
-
- if (driver)
- ret = g_strdup (driver);
- if (parent)
- g_object_unref (parent);
+#define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
+ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856_A)
- return ret;
-}
-
-static GUdevDevice *
-find_physical_device (GUdevDevice *child)
+static guint32
+get_level_for_capabilities (guint32 capabilities)
{
- GUdevDevice *iter, *old = NULL;
- const char *bus, *type;
-
- g_return_val_if_fail (child != NULL, NULL);
-
- bus = g_udev_device_get_property (child, "ID_BUS");
- if (!bus)
- return NULL;
-
- if (!strcmp (bus, "usb")) {
- /* Walk the parents to find the 'usb_device' for this device. */
- iter = g_object_ref (child);
- while (iter) {
- type = g_udev_device_get_devtype (iter);
- if (type && !strcmp (type, "usb_device"))
- return iter;
-
- old = iter;
- iter = g_udev_device_get_parent (old);
- g_object_unref (old);
- }
- g_object_unref (child);
- } else if (!strcmp (bus, "pci")) {
- return g_udev_device_get_parent (child);
- }
-
- // FIXME: pci and pcmcia/cardbus? (like Sierra 850/860)
- return NULL;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 5;
+ if (capabilities & CAP_CDMA)
+ return 5;
+ return 0;
}
-#define PROP_GSM "ID_MM_MODEM_GSM"
-#define PROP_CDMA "ID_MM_MODEM_IS707_A"
-#define PROP_EVDO1 "ID_MM_MODEM_IS856"
-#define PROP_EVDOA "ID_MM_MODEM_IS856_A"
-
-static GUdevDevice *
-get_device_type (MMPlugin *plugin,
- const char *subsys,
- const char *name,
- gboolean *gsm,
- gboolean *cdma)
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- MMPluginGenericPrivate *priv = MM_PLUGIN_GENERIC_GET_PRIVATE (plugin);
- GUdevDevice *device;
-
- g_return_val_if_fail (plugin != NULL, NULL);
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
- g_return_val_if_fail (subsys != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- device = g_udev_client_query_by_subsystem_and_name (priv->client, subsys, name);
- if (!device)
- return NULL;
-
- if (g_udev_device_get_property_as_boolean (device, PROP_GSM))
- *gsm = TRUE;
- if ( g_udev_device_get_property_as_boolean (device, PROP_CDMA)
- || g_udev_device_get_property_as_boolean (device, PROP_EVDO1)
- || g_udev_device_get_property_as_boolean (device, PROP_EVDOA))
- *cdma = TRUE;
-
- return device;
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
-static guint32
-supports_port (MMPlugin *plugin,
- const char *subsys,
- const char *name)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- GUdevDevice *device, *physdev = NULL;
- gboolean gsm = FALSE, cdma = FALSE;
- guint32 level = 0;
-
- g_return_val_if_fail (plugin != NULL, 0);
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), 0);
- g_return_val_if_fail (subsys != NULL, 0);
- g_return_val_if_fail (name != NULL, 0);
+ GUdevDevice *port;
+ guint32 cached = 0, level;
/* Can't do anything with non-serial ports */
- if (strcmp (subsys, "tty"))
- return 0;
-
- device = get_device_type (plugin, subsys, name, &gsm, &cdma);
- if (!device)
- return 0;
-
- if (!gsm && !cdma)
- goto out;
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
- physdev = find_physical_device (device);
- if (!physdev)
- goto out;
- g_object_unref (physdev);
- level = 5;
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
-out:
- return level;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-grab_port (MMPlugin *plugin,
- const char *subsys,
- const char *name,
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
GError **error)
{
- MMPluginGeneric *self = MM_PLUGIN_GENERIC (plugin);
- GUdevDevice *device = NULL, *physdev = NULL;
- const char *devfile, *sysfs_path;
- char *driver = NULL;
+ GUdevDevice *port = NULL, *physdev = NULL;
MMModem *modem = NULL;
- gboolean gsm = FALSE, cdma = FALSE;
-
- g_return_val_if_fail (subsys != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- /* Can't do anything with non-serial ports */
- if (strcmp (subsys, "tty"))
- return NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
- device = get_device_type (plugin, subsys, name, &gsm, &cdma);
- if (!device) {
- g_set_error (error, 0, 0, "Could not get port's udev device.");
- return NULL;
- }
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
- if (!gsm && !cdma) {
- g_set_error (error, 0, 0, "Modem unsupported (not GSM or CDMA).");
- goto out;
- }
-
- physdev = find_physical_device (device);
- if (!physdev) {
- g_set_error (error, 0, 0, "Could not get ports's physical device.");
- goto out;
- }
-
- devfile = g_udev_device_get_device_file (device);
+ devfile = g_udev_device_get_device_file (port);
if (!devfile) {
g_set_error (error, 0, 0, "Could not get port's sysfs file.");
- goto out;
- }
-
- driver = get_driver_name (device);
- if (!driver) {
- g_set_error (error, 0, 0, "Could not get port's driver name.");
- goto out;
+ return NULL;
}
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
sysfs_path = g_udev_device_get_sysfs_path (physdev);
if (!sysfs_path) {
g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- goto out;
+ return NULL;
}
- modem = mm_plugin_base_find_modem (MM_PLUGIN_BASE (self), sysfs_path);
- if (!modem) {
- if (gsm) {
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_generic_gsm_new (sysfs_path,
- driver,
- mm_plugin_get_name (plugin));
- } else if (cdma) {
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path,
- driver,
- mm_plugin_get_name (plugin));
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
}
if (modem) {
- if (!mm_modem_grab_port (modem, subsys, name, error)) {
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
g_object_unref (modem);
- modem = NULL;
+ return NULL;
}
}
-
- if (modem)
- mm_plugin_base_add_modem (MM_PLUGIN_BASE (self), modem);
} else {
- if (gsm || cdma) {
- if (!mm_modem_grab_port (modem, subsys, name, error))
- modem = NULL;
+ if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
+ return NULL;
}
}
-out:
- g_free (driver);
- g_object_unref (device);
- g_object_unref (physdev);
return modem;
}
-static const char *
-get_name (MMPlugin *plugin)
-{
- return "Generic";
-}
-
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->supports_port = supports_port;
- plugin_class->grab_port = grab_port;
-}
-
-static void
mm_plugin_generic_init (MMPluginGeneric *self)
{
- MMPluginGenericPrivate *priv = MM_PLUGIN_GENERIC_GET_PRIVATE (self);
- const char *subsys[2] = { "tty", NULL };
-
- priv->client = g_udev_client_new (subsys);
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
dispose (GObject *object)
{
- MMPluginGenericPrivate *priv = MM_PLUGIN_GENERIC_GET_PRIVATE (object);
-
- g_object_unref (priv->client);
}
static void
mm_plugin_generic_class_init (MMPluginGenericClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (object_class, sizeof (MMPluginGenericPrivate));
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
object_class->dispose = dispose;
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
}
diff --git a/plugins/mm-plugin-gobi.c b/plugins/mm-plugin-gobi.c
index 128ba838..6e5bfd9c 100644
--- a/plugins/mm-plugin-gobi.c
+++ b/plugins/mm-plugin-gobi.c
@@ -23,287 +23,147 @@
#include "mm-modem-gobi-gsm.h"
#include "mm-generic-cdma.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginGobi, mm_plugin_gobi, MM_TYPE_PLUGIN_BASE,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginGobi, mm_plugin_gobi, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
-#define MM_PLUGIN_GOBI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_GOBI, MMPluginGobiPrivate))
-
-typedef struct {
- GUdevClient *client;
-} MMPluginGobiPrivate;
-
-
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_GOBI, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_GOBI,
+ MM_PLUGIN_BASE_NAME, "Gobi",
+ NULL));
}
/*****************************************************************************/
-static char *
-get_driver_name (GUdevDevice *device)
-{
- GUdevDevice *parent = NULL;
- const char *driver;
- char *ret = NULL;
-
- driver = g_udev_device_get_driver (device);
- if (!driver) {
- parent = g_udev_device_get_parent (device);
- if (parent)
- driver = g_udev_device_get_driver (parent);
- }
-
- if (driver)
- ret = g_strdup (driver);
- if (parent)
- g_object_unref (parent);
+#define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
+ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856_A)
- return ret;
-}
-
-static GUdevDevice *
-find_physical_device (GUdevDevice *child)
+static guint32
+get_level_for_capabilities (guint32 capabilities)
{
- GUdevDevice *iter, *old = NULL;
- const char *bus, *type;
-
- g_return_val_if_fail (child != NULL, NULL);
-
- bus = g_udev_device_get_property (child, "ID_BUS");
- if (!bus)
- return NULL;
-
- if (strcmp (bus, "usb"))
- return NULL;
-
- /* Walk the parents to find the 'usb_device' for this device. */
- iter = g_object_ref (child);
- while (iter) {
- type = g_udev_device_get_devtype (iter);
- if (type && !strcmp (type, "usb_device"))
- return iter;
-
- old = iter;
- iter = g_udev_device_get_parent (old);
- g_object_unref (old);
- }
- g_object_unref (child);
-
- return NULL;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ if (capabilities & CAP_CDMA)
+ return 10;
+ return 0;
}
-#define PROP_GSM "ID_MM_MODEM_GSM"
-#define PROP_CDMA "ID_MM_MODEM_IS707_A"
-#define PROP_EVDO1 "ID_MM_MODEM_IS856"
-#define PROP_EVDOA "ID_MM_MODEM_IS856_A"
-
-static GUdevDevice *
-get_device_type (MMPlugin *plugin,
- const char *subsys,
- const char *name,
- gboolean *gsm,
- gboolean *cdma)
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- MMPluginGobiPrivate *priv = MM_PLUGIN_GOBI_GET_PRIVATE (plugin);
- GUdevDevice *device;
-
- g_return_val_if_fail (plugin != NULL, NULL);
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
- g_return_val_if_fail (subsys != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- device = g_udev_client_query_by_subsystem_and_name (priv->client, subsys, name);
- if (!device)
- return NULL;
-
- if (g_udev_device_get_property_as_boolean (device, PROP_GSM))
- *gsm = TRUE;
- if ( g_udev_device_get_property_as_boolean (device, PROP_CDMA)
- || g_udev_device_get_property_as_boolean (device, PROP_EVDO1)
- || g_udev_device_get_property_as_boolean (device, PROP_EVDOA))
- *cdma = TRUE;
-
- return device;
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
-static guint32
-supports_port (MMPlugin *plugin,
- const char *subsys,
- const char *name)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- GUdevDevice *device, *physdev = NULL;
- guint32 level = 0;
- gboolean gsm = FALSE, cdma = FALSE;
- char *driver = NULL;
-
- g_return_val_if_fail (plugin != NULL, 0);
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), 0);
- g_return_val_if_fail (subsys != NULL, 0);
- g_return_val_if_fail (name != NULL, 0);
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *driver;
/* Can't do anything with non-serial ports */
- if (strcmp (subsys, "tty"))
- return 0;
-
- device = get_device_type (plugin, subsys, name, &gsm, &cdma);
- if (!device)
- return 0;
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- if (!gsm && !cdma)
- goto out;
-
- driver = get_driver_name (device);
+ driver = mm_plugin_base_supports_task_get_driver (task);
if (!driver || strcmp (driver, "qcserial"))
- goto out;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
- physdev = find_physical_device (device);
- if (!physdev)
- goto out;
- g_object_unref (physdev);
- level = 10;
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
-out:
- g_object_unref (device);
- return level;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-grab_port (MMPlugin *plugin,
- const char *subsys,
- const char *name,
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
GError **error)
{
- MMPluginGobi *self = MM_PLUGIN_GOBI (plugin);
- GUdevDevice *device = NULL, *physdev = NULL;
- const char *devfile, *sysfs_path;
- char *driver = NULL;
+ GUdevDevice *port = NULL, *physdev = NULL;
MMModem *modem = NULL;
- gboolean gsm = FALSE, cdma = FALSE;
-
- g_return_val_if_fail (subsys != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
+ const char *name, *subsys, *sysfs_path;
+ guint32 caps;
- /* Can't do anything with non-serial ports */
- if (strcmp (subsys, "tty"))
- return NULL;
-
- device = get_device_type (plugin, subsys, name, &gsm, &cdma);
- if (!device) {
- g_set_error (error, 0, 0, "Could not get port's udev device.");
- return NULL;
- }
-
- if (!gsm && !cdma) {
- g_set_error (error, 0, 0, "Modem unsupported (not GSM or CDMA).");
- goto out;
- }
-
- physdev = find_physical_device (device);
- if (!physdev) {
- g_set_error (error, 0, 0, "Could not get ports's physical device.");
- goto out;
- }
-
- devfile = g_udev_device_get_device_file (device);
- if (!devfile) {
- g_set_error (error, 0, 0, "Could not get port's sysfs file.");
- goto out;
- }
-
- driver = get_driver_name (device);
- if (!driver) {
- g_set_error (error, 0, 0, "Could not get port's driver name.");
- goto out;
- }
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
sysfs_path = g_udev_device_get_sysfs_path (physdev);
if (!sysfs_path) {
g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- goto out;
+ return NULL;
}
- modem = mm_plugin_base_find_modem (MM_PLUGIN_BASE (self), sysfs_path);
- if (!modem) {
- if (gsm) {
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_modem_gobi_gsm_new (sysfs_path,
- driver,
- mm_plugin_get_name (plugin));
- } else if (cdma) {
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path,
- driver,
- mm_plugin_get_name (plugin));
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
}
if (modem) {
- if (!mm_modem_grab_port (modem, subsys, name, error)) {
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
g_object_unref (modem);
- modem = NULL;
+ return NULL;
}
}
-
- if (modem)
- mm_plugin_base_add_modem (MM_PLUGIN_BASE (self), modem);
} else {
- if (gsm || cdma) {
- if (!mm_modem_grab_port (modem, subsys, name, error))
- modem = NULL;
+ if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
+ return NULL;
}
}
-out:
- g_free (driver);
- g_object_unref (device);
- g_object_unref (physdev);
return modem;
}
-static const char *
-get_name (MMPlugin *plugin)
-{
- return "Gobi";
-}
-
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->supports_port = supports_port;
- plugin_class->grab_port = grab_port;
-}
-
-static void
mm_plugin_gobi_init (MMPluginGobi *self)
{
- MMPluginGobiPrivate *priv = MM_PLUGIN_GOBI_GET_PRIVATE (self);
- const char *subsys[2] = { "tty", NULL };
-
- priv->client = g_udev_client_new (subsys);
-}
-
-static void
-dispose (GObject *object)
-{
- MMPluginGobiPrivate *priv = MM_PLUGIN_GOBI_GET_PRIVATE (object);
-
- g_object_unref (priv->client);
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
mm_plugin_gobi_class_init (MMPluginGobiClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
- g_type_class_add_private (object_class, sizeof (MMPluginGobiPrivate));
-
- object_class->dispose = dispose;
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
}
+
diff --git a/plugins/mm-plugin-hso.c b/plugins/mm-plugin-hso.c
index 9481bbf4..edcabab2 100644
--- a/plugins/mm-plugin-hso.c
+++ b/plugins/mm-plugin-hso.c
@@ -23,165 +23,89 @@
#include "mm-plugin-hso.h"
#include "mm-modem-hso.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginHso, mm_plugin_hso, MM_TYPE_PLUGIN_BASE,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginHso, mm_plugin_hso, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
-#define MM_PLUGIN_HSO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_HSO, MMPluginHsoPrivate))
-
-typedef struct {
- GUdevClient *client;
-} MMPluginHsoPrivate;
-
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_HSO, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_HSO,
+ MM_PLUGIN_BASE_NAME, "Option High-Speed",
+ NULL));
}
/*****************************************************************************/
-static char *
-get_driver_name (GUdevDevice *device)
+static guint32
+get_level_for_capabilities (guint32 capabilities)
{
- GUdevDevice *parent = NULL;
- const char *driver;
- char *ret;
-
- driver = g_udev_device_get_driver (device);
- if (!driver) {
- parent = g_udev_device_get_parent (device);
- if (parent)
- driver = g_udev_device_get_driver (parent);
- }
-
- if (driver)
- ret = g_strdup (driver);
- if (parent)
- g_object_unref (parent);
-
- return ret;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ return 0;
}
-static GUdevDevice *
-find_physical_device (GUdevDevice *child)
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- GUdevDevice *iter, *old = NULL;
- const char *type;
-
- g_return_val_if_fail (child != NULL, NULL);
-
- /* Walk the parents to find the first 'usb_device' for this device. */
- iter = g_object_ref (child);
- while (iter) {
- type = g_udev_device_get_devtype (iter);
- if (type && !strcmp (type, "usb_device"))
- return iter;
-
- old = iter;
- iter = g_udev_device_get_parent (old);
- g_object_unref (old);
- }
- g_object_unref (child);
-
- return NULL;
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
-static GUdevDevice *
-get_device (GUdevClient *client,
- const char *subsys,
- const char *name,
- GUdevDevice **physdev,
- char **driver,
- GError **error)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- GUdevDevice *device = NULL;
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *driver;
- if (strcmp (subsys, "tty") && strcmp (subsys, "net")) {
- g_set_error (error, 0, 0, "Unsupported subsystem.");
- return NULL;
- }
+ port = mm_plugin_base_supports_task_get_port (task);
- device = g_udev_client_query_by_subsystem_and_name (client, subsys, name);
- if (!device) {
- g_set_error (error, 0, 0, "Coud not get port's udev device.");
- return NULL;
- }
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || strcmp (driver, "hso"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- *driver = get_driver_name (device);
- if (!*driver || strcmp (*driver, "hso")) {
- g_set_error (error, 0, 0, "Unsupported driver (not 'hso').");
- g_object_unref (device);
- device = NULL;
- goto out;
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
- *physdev = find_physical_device (device);
- if (!*physdev) {
- g_set_error (error, 0, 0, "Could not get port's physical udev device.");
- g_object_unref (device);
- device = NULL;
- }
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
-out:
- return device;
-}
-
-static guint32
-supports_port (MMPlugin *plugin,
- const char *subsys,
- const char *name)
-{
- MMPluginHsoPrivate *priv = MM_PLUGIN_HSO_GET_PRIVATE (plugin);
- GUdevDevice *device, *physdev = NULL;
- guint32 level = 0;
- char *driver = NULL;
-
- g_return_val_if_fail (plugin != NULL, 0);
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), 0);
- g_return_val_if_fail (subsys != NULL, 0);
- g_return_val_if_fail (name != NULL, 0);
-
- device = get_device (priv->client, subsys, name, &physdev, &driver, NULL);
- if (device)
- level = 10;
-
- g_free (driver);
- if (physdev)
- g_object_unref (physdev);
- if (device)
- g_object_unref (device);
- return level;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-grab_port (MMPlugin *plugin,
- const char *subsys,
- const char *name,
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
GError **error)
{
- MMPluginHso *self = MM_PLUGIN_HSO (plugin);
- MMPluginHsoPrivate *priv = MM_PLUGIN_HSO_GET_PRIVATE (plugin);
- GUdevDevice *device = NULL, *physdev = NULL;
- const char *sysfs_path = NULL;
- char *driver = NULL, *devfile = NULL;
+ GUdevDevice *port = NULL, *physdev = NULL;
MMModem *modem = NULL;
+ const char *name, *subsys, *sysfs_path;
+ char *devfile;
+ guint32 caps;
- g_return_val_if_fail (subsys != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
- device = get_device (priv->client, subsys, name, &physdev, &driver, error);
- if (!device) {
- g_set_error (error, 0, 0, "Could not get port's udev device.");
- return NULL;
- }
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
- devfile = g_strdup (g_udev_device_get_device_file (device));
+ devfile = g_strdup (g_udev_device_get_device_file (port));
if (!devfile) {
if (!strcmp (subsys, "net")) {
/* Apparently 'hso' doesn't set up the right links for the netdevice,
@@ -200,80 +124,54 @@ grab_port (MMPlugin *plugin,
}
}
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
sysfs_path = g_udev_device_get_sysfs_path (physdev);
if (!sysfs_path) {
g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
goto out;
}
- modem = mm_plugin_base_find_modem (MM_PLUGIN_BASE (self), sysfs_path);
- if (!modem) {
- modem = mm_modem_hso_new (sysfs_path,
- driver,
- mm_plugin_get_name (plugin));
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_hso_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ }
if (modem) {
- if (!mm_modem_grab_port (modem, subsys, name, error)) {
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
g_object_unref (modem);
- modem = NULL;
+ return NULL;
}
}
-
- if (modem)
- mm_plugin_base_add_modem (MM_PLUGIN_BASE (self), modem);
} else {
- if (!mm_modem_grab_port (modem, subsys, name, error))
- modem = NULL;
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
+ return NULL;
+ }
}
out:
g_free (devfile);
- g_free (driver);
- g_object_unref (device);
- g_object_unref (physdev);
return modem;
}
-static const char *
-get_name (MMPlugin *plugin)
-{
- return "HSO";
-}
-
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->supports_port = supports_port;
- plugin_class->grab_port = grab_port;
-}
-
-static void
mm_plugin_hso_init (MMPluginHso *self)
{
- MMPluginHsoPrivate *priv = MM_PLUGIN_HSO_GET_PRIVATE (self);
- const char *subsys[] = { "tty", "net", NULL };
-
- priv->client = g_udev_client_new (subsys);
-}
-
-static void
-dispose (GObject *object)
-{
- MMPluginHsoPrivate *priv = MM_PLUGIN_HSO_GET_PRIVATE (object);
-
- g_object_unref (priv->client);
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
mm_plugin_hso_class_init (MMPluginHsoClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (object_class, sizeof (MMPluginHsoPrivate));
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
- object_class->dispose = dispose;
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
}
diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c
index 3ea70865..4ef8c578 100644
--- a/plugins/mm-plugin-huawei.c
+++ b/plugins/mm-plugin-huawei.c
@@ -22,269 +22,316 @@
#include "mm-plugin-huawei.h"
#include "mm-generic-gsm.h"
+#include "mm-generic-cdma.h"
#include "mm-modem-huawei.h"
+#include "mm-serial-parsers.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
-#define MM_PLUGIN_HUAWEI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuaweiPrivate))
-
-typedef struct {
- GUdevClient *client;
-} MMPluginHuaweiPrivate;
-
-
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_HUAWEI, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_HUAWEI,
+ MM_PLUGIN_BASE_NAME, "Huawei",
+ NULL));
}
/*****************************************************************************/
-static char *
-get_driver_name (GUdevDevice *device)
-{
- GUdevDevice *parent = NULL;
- const char *driver;
- char *ret;
-
- driver = g_udev_device_get_driver (device);
- if (!driver) {
- parent = g_udev_device_get_parent (device);
- if (parent)
- driver = g_udev_device_get_driver (parent);
- }
+#define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
+ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856_A)
- if (driver)
- ret = g_strdup (driver);
- if (parent)
- g_object_unref (parent);
-
- return ret;
+static guint32
+get_level_for_capabilities (guint32 capabilities)
+{
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ if (capabilities & CAP_CDMA)
+ return 10;
+ return 0;
}
-static GUdevDevice *
-find_physical_device (GUdevDevice *child)
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- GUdevDevice *iter, *old = NULL;
- const char *bus, *type;
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
- g_return_val_if_fail (child != NULL, NULL);
+#define TAG_SUPPORTS_INFO "huawei-supports-info"
- bus = g_udev_device_get_property (child, "ID_BUS");
- if (!bus)
- return NULL;
+typedef struct {
+ MMSerialPort *serial;
+ guint id;
+ gboolean secondary;
+} HuaweiSupportsInfo;
- if (strcmp (bus, "usb"))
- return NULL;
+static void
+huawei_supports_info_destroy (gpointer user_data)
+{
+ HuaweiSupportsInfo *info = user_data;
+
+ if (info->id)
+ g_source_remove (info->id);
+ if (info->serial)
+ g_object_unref (info->serial);
+ memset (info, 0, sizeof (HuaweiSupportsInfo));
+ g_free (info);
+}
- /* Walk the parents to find the 'usb_device' for this device. */
- iter = g_object_ref (child);
- while (iter) {
- type = g_udev_device_get_devtype (iter);
- if (type && !strcmp (type, "usb_device"))
- return iter;
+static gboolean
+probe_secondary_supported (gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = user_data;
+ HuaweiSupportsInfo *info;
- old = iter;
- iter = g_udev_device_get_parent (old);
- g_object_unref (old);
- }
- g_object_unref (child);
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
- return NULL;
-}
+ info->id = 0;
+ g_object_unref (info->serial);
+ info->serial = NULL;
-#define PROP_GSM "ID_MM_MODEM_GSM"
+ /* Yay, supported, we got an unsolicited message */
+ info->secondary = TRUE;
+ mm_plugin_base_supports_task_complete (task, 10);
+ return FALSE;
+}
-static GUdevDevice *
-get_device (GUdevClient *client,
- const char *subsys,
- const char *name,
- GUdevDevice **physdev)
+static void
+probe_secondary_handle_msg (MMSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
{
- GUdevDevice *device;
- const char *tmp;
+ MMPluginBaseSupportsTask *task = user_data;
+ HuaweiSupportsInfo *info;
- /* Can't do anything with non-serial ports */
- if (strcmp (subsys, "tty"))
- return NULL;
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
+ g_source_remove (info->id);
+ info->id = g_idle_add (probe_secondary_supported, task);
+}
- device = g_udev_client_query_by_subsystem_and_name (client, subsys, name);
- if (!device)
- return NULL;
+static gboolean
+probe_secondary_timeout (gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = user_data;
+ HuaweiSupportsInfo *info;
- tmp = g_udev_device_get_property (device, "ID_BUS");
- if (!tmp || strcmp (tmp, "usb"))
- goto error;
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
+ info->id = 0;
+ g_object_unref (info->serial);
+ info->serial = NULL;
- if (!g_udev_device_get_property_as_boolean (device, PROP_GSM))
- goto error;
+ /* Not supported by this plugin */
+ mm_plugin_base_supports_task_complete (task, 0);
+ return FALSE;
+}
- *physdev = find_physical_device (device);
- if (*physdev)
- return device;
+static void
+add_regex (MMSerialPort *port, const char *match, gpointer user_data)
+{
+ GRegex *regex;
-error:
- g_object_unref (device);
- return NULL;
+ regex = g_regex_new (match, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_serial_port_add_unsolicited_msg_handler (port, regex, probe_secondary_handle_msg, user_data, NULL);
+ g_regex_unref (regex);
}
-static guint32
-supports_port (MMPlugin *plugin,
- const char *subsys,
- const char *name)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- MMPluginHuaweiPrivate *priv = MM_PLUGIN_HUAWEI_GET_PRIVATE (plugin);
- GUdevDevice *device, *physdev = NULL;
- guint32 level = 0;
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *subsys, *name;
+ int usbif;
guint16 vendor = 0, product = 0;
+ guint32 existing_type = MM_MODEM_TYPE_UNKNOWN;
- device = get_device (priv->client, subsys, name, &physdev);
- if (!device)
- goto out;
- g_object_unref (physdev);
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- if (!mm_plugin_base_get_device_ids (MM_PLUGIN_BASE (plugin), subsys, name, &vendor, &product))
- goto out;
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
if (vendor != 0x12d1)
- goto out;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ usbif = g_udev_device_get_property_as_int (port, "ID_USB_INTERFACE_NUM");
+ if (usbif < 0)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ /* The secondary ports don't necessarily respond correctly to probing, so
+ * we need to use the first port that does respond to probing to create the
+ * right type of mode (GSM or CDMA), and then re-check the other interfaces.
+ */
+ if (!existing && usbif != 0)
+ return MM_PLUGIN_SUPPORTS_PORT_DEFER;
+
+ /* CDMA devices don't have problems with the secondary ports, so after
+ * ensuring we have a device by probing the first port, probe the secondary
+ * ports on CDMA devices too.
+ */
+ if (existing)
+ g_object_get (G_OBJECT (existing), MM_MODEM_TYPE, &existing_type, NULL);
+
+ if (usbif == 0 || (existing_type == MM_MODEM_TYPE_CDMA)) {
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
+
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ } else {
+ HuaweiSupportsInfo *info;
+ GError *error = NULL;
+
+ /* Listen for Huawei-specific unsolicited messages */
+ info = g_malloc0 (sizeof (HuaweiSupportsInfo));
+
+ info->serial = mm_serial_port_new (name, MM_PORT_TYPE_PRIMARY);
+ g_object_set (G_OBJECT (info->serial), MM_PORT_CARRIER_DETECT, FALSE, NULL);
+
+ mm_serial_port_set_response_parser (info->serial,
+ mm_serial_parser_v1_parse,
+ mm_serial_parser_v1_new (),
+ mm_serial_parser_v1_destroy);
+
+ add_regex (info->serial, "\\r\\n\\^RSSI:(\\d+)\\r\\n", task);
+ add_regex (info->serial, "\\r\\n\\^MODE:(\\d),(\\d)\\r\\n", task);
+ add_regex (info->serial, "\\r\\n\\^DSFLOWRPT:(.+)\\r\\n", task);
+ add_regex (info->serial, "\\r\\n\\^BOOT:.+\\r\\n", task);
+
+ info->id = g_timeout_add (5000, probe_secondary_timeout, task);
+
+ g_object_set_data_full (G_OBJECT (task), TAG_SUPPORTS_INFO,
+ info, huawei_supports_info_destroy);
+
+ if (!mm_serial_port_open (info->serial, &error)) {
+ g_warning ("%s: (Huawei) %s: couldn't open serial port: (%d) %s",
+ __func__, name,
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ g_clear_error (&error);
+ huawei_supports_info_destroy (info);
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
- if (product == 0x1001 || product == 0x1003 || product == 0x1004)
- level = 10;
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
-out:
- if (device)
- g_object_unref (device);
- return level;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-grab_port (MMPlugin *plugin,
- const char *subsys,
- const char *name,
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
GError **error)
{
- MMPluginHuawei *self = MM_PLUGIN_HUAWEI (plugin);
- MMPluginHuaweiPrivate *priv = MM_PLUGIN_HUAWEI_GET_PRIVATE (plugin);
- GUdevDevice *device = NULL, *physdev = NULL;
- const char *devfile, *sysfs_path;
- char *driver = NULL;
+ GUdevDevice *port = NULL, *physdev = NULL;
MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
guint16 product = 0;
- g_return_val_if_fail (subsys != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- device = get_device (priv->client, subsys, name, &physdev);
- if (!device)
- goto out;
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
- devfile = g_udev_device_get_device_file (device);
+ devfile = g_udev_device_get_device_file (port);
if (!devfile) {
g_set_error (error, 0, 0, "Could not get port's sysfs file.");
- goto out;
- }
-
- driver = get_driver_name (device);
- if (!driver) {
- g_set_error (error, 0, 0, "Could not get port's driver name.");
- goto out;
+ return NULL;
}
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
sysfs_path = g_udev_device_get_sysfs_path (physdev);
if (!sysfs_path) {
g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- goto out;
+ return NULL;
}
- if (!mm_plugin_base_get_device_ids (MM_PLUGIN_BASE (plugin), subsys, name, NULL, &product)) {
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, NULL, &product)) {
g_set_error (error, 0, 0, "Could not get modem product ID.");
- goto out;
+ return NULL;
}
- modem = mm_plugin_base_find_modem (MM_PLUGIN_BASE (self), sysfs_path);
- if (!modem) {
- if (product == 0x1001) {
- /* This modem is handled by generic GSM driver */
- modem = mm_generic_gsm_new (sysfs_path,
- driver,
- mm_plugin_get_name (plugin));
- } else {
- modem = mm_modem_huawei_new (sysfs_path,
- driver,
- mm_plugin_get_name (plugin));
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ if (product == 0x1001) {
+ /* This modem is handled by generic GSM driver */
+ modem = mm_generic_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else {
+ modem = mm_modem_huawei_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ }
+ } else if (caps & CAP_CDMA) {
+ modem = mm_generic_cdma_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
}
if (modem) {
- if (!mm_modem_grab_port (modem, subsys, name, error)) {
-g_message ("%s: couldn't grab port", __func__);
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
g_object_unref (modem);
- modem = NULL;
- goto out;
+ return NULL;
}
- mm_plugin_base_add_modem (MM_PLUGIN_BASE (self), modem);
}
} else {
- if (!mm_modem_grab_port (modem, subsys, name, error))
- modem = NULL;
+ HuaweiSupportsInfo *info;
+ gboolean huawei_is_secondary = FALSE;
+
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
+ if (info && (product != 0x1001))
+ huawei_is_secondary = info->secondary;
+
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, GUINT_TO_POINTER (huawei_is_secondary), error))
+ return NULL;
}
-out:
- g_free (driver);
- g_object_unref (device);
- g_object_unref (physdev);
-g_message ("%s: port %s / %s modem %p", __func__, subsys, name, modem);
return modem;
}
-static const char *
-get_name (MMPlugin *plugin)
-{
- return "Huawei";
-}
-
-
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->supports_port = supports_port;
- plugin_class->grab_port = grab_port;
-}
-
-static void
mm_plugin_huawei_init (MMPluginHuawei *self)
{
- MMPluginHuaweiPrivate *priv = MM_PLUGIN_HUAWEI_GET_PRIVATE (self);
- const char *subsys[2] = { "tty", NULL };
-
- priv->client = g_udev_client_new (subsys);
-}
-
-static void
-dispose (GObject *object)
-{
- MMPluginHuaweiPrivate *priv = MM_PLUGIN_HUAWEI_GET_PRIVATE (object);
-
- g_object_unref (priv->client);
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
mm_plugin_huawei_class_init (MMPluginHuaweiClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (object_class, sizeof (MMPluginHuaweiPrivate));
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
- object_class->dispose = dispose;
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
}
diff --git a/plugins/mm-plugin-moto-c.c b/plugins/mm-plugin-moto-c.c
index 693dd61d..a77e65a8 100644
--- a/plugins/mm-plugin-moto-c.c
+++ b/plugins/mm-plugin-moto-c.c
@@ -22,255 +22,144 @@
#include "mm-plugin-moto-c.h"
#include "mm-modem-moto-c-gsm.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginMotoC, mm_plugin_moto_c, MM_TYPE_PLUGIN_BASE,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginMotoC, mm_plugin_moto_c, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
-#define MM_PLUGIN_MOTO_C_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_MOTO_C, MMPluginMotoCPrivate))
-
-typedef struct {
- GUdevClient *client;
-} MMPluginMotoCPrivate;
-
-
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_MOTO_C, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_MOTO_C,
+ MM_PLUGIN_BASE_NAME, "MotoC",
+ NULL));
}
/*****************************************************************************/
-static char *
-get_driver_name (GUdevDevice *device)
-{
- GUdevDevice *parent = NULL;
- const char *driver;
- char *ret;
-
- driver = g_udev_device_get_driver (device);
- if (!driver) {
- parent = g_udev_device_get_parent (device);
- if (parent)
- driver = g_udev_device_get_driver (parent);
- }
-
- if (driver)
- ret = g_strdup (driver);
- if (parent)
- g_object_unref (parent);
-
- return ret;
-}
-
-static GUdevDevice *
-find_physical_device (GUdevDevice *child)
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- GUdevDevice *iter, *old = NULL;
- const char *bus, *type;
-
- g_return_val_if_fail (child != NULL, NULL);
-
- bus = g_udev_device_get_property (child, "ID_BUS");
- if (!bus)
- return NULL;
-
- if (strcmp (bus, "usb"))
- return NULL;
-
- /* Walk the parents to find the 'usb_device' for this device. */
- iter = g_object_ref (child);
- while (iter) {
- type = g_udev_device_get_devtype (iter);
- if (type && !strcmp (type, "usb_device"))
- return iter;
+ guint32 level = 0;
- old = iter;
- iter = g_udev_device_get_parent (old);
- g_object_unref (old);
- }
- g_object_unref (child);
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ level = 10;
- return NULL;
+ mm_plugin_base_supports_task_complete (task, level);
}
-#define PROP_GSM "ID_MM_MODEM_GSM"
-
-static guint32
-supports_port (MMPlugin *plugin,
- const char *subsys,
- const char *name)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- MMPluginMotoCPrivate *priv = MM_PLUGIN_MOTO_C_GET_PRIVATE (plugin);
- GUdevDevice *device, *physdev = NULL;
- guint32 level = 0;
+ GUdevDevice *port;
const char *tmp;
-
- g_return_val_if_fail (plugin != NULL, 0);
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), 0);
- g_return_val_if_fail (subsys != NULL, 0);
- g_return_val_if_fail (name != NULL, 0);
+ guint32 cached = 0;
/* Can't do anything with non-serial ports */
- if (strcmp (subsys, "tty"))
- return 0;
-
- device = g_udev_client_query_by_subsystem_and_name (priv->client, subsys, name);
- if (!device)
- return 0;
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- tmp = g_udev_device_get_property (device, "ID_BUS");
+ tmp = g_udev_device_get_property (port, "ID_BUS");
if (!tmp || strcmp (tmp, "usb"))
- goto out;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- tmp = g_udev_device_get_property (device, "ID_VENDOR_ID");
+ tmp = g_udev_device_get_property (port, "ID_VENDOR_ID");
if (!tmp || strcmp (tmp, "22b8"))
- goto out;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- tmp = g_udev_device_get_property (device, "ID_MODEL_ID");
+ tmp = g_udev_device_get_property (port, "ID_MODEL_ID");
if (!tmp || strcmp (tmp, "3802"))
- goto out;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- if (!g_udev_device_get_property_as_boolean (device, PROP_GSM))
- goto out;
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ if (cached & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ mm_plugin_base_supports_task_complete (task, 10);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
- physdev = find_physical_device (device);
- if (!physdev)
- goto out;
- g_object_unref (physdev);
- level = 10;
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
-out:
- g_object_unref (device);
- return level;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-grab_port (MMPlugin *plugin,
- const char *subsys,
- const char *name,
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
GError **error)
{
- MMPluginMotoC *self = MM_PLUGIN_MOTO_C (plugin);
- MMPluginMotoCPrivate *priv = MM_PLUGIN_MOTO_C_GET_PRIVATE (plugin);
- GUdevDevice *device = NULL, *physdev = NULL;
- const char *devfile, *sysfs_path;
- char *driver = NULL;
+ GUdevDevice *port = NULL, *physdev = NULL;
MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
- g_return_val_if_fail (subsys != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- /* Can't do anything with non-serial ports */
- if (strcmp (subsys, "tty"))
- return NULL;
-
- device = g_udev_client_query_by_subsystem_and_name (priv->client, subsys, name);
- if (!device) {
- g_set_error (error, 0, 0, "Could not get port's udev device.");
- return NULL;
- }
-
- if (!g_udev_device_get_property_as_boolean (device, PROP_GSM)) {
- g_set_error (error, 0, 0, "Modem unsupported (not GSM).");
- goto out;
- }
-
- physdev = find_physical_device (device);
- if (!physdev) {
- g_set_error (error, 0, 0, "Could not get ports's physical device.");
- goto out;
- }
-
- devfile = g_udev_device_get_device_file (device);
+ devfile = g_udev_device_get_device_file (port);
if (!devfile) {
g_set_error (error, 0, 0, "Could not get port's sysfs file.");
- goto out;
- }
-
- driver = get_driver_name (device);
- if (!driver) {
- g_set_error (error, 0, 0, "Could not get port's driver name.");
- goto out;
+ return NULL;
}
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
sysfs_path = g_udev_device_get_sysfs_path (physdev);
if (!sysfs_path) {
g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- goto out;
+ return NULL;
}
- modem = mm_plugin_base_find_modem (MM_PLUGIN_BASE (self), sysfs_path);
- if (!modem) {
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!existing) {
modem = mm_modem_moto_c_gsm_new (sysfs_path,
- driver,
- mm_plugin_get_name (plugin));
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
if (modem) {
- if (!mm_modem_grab_port (modem, subsys, name, error)) {
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
g_object_unref (modem);
- modem = NULL;
+ return NULL;
}
}
-
- if (modem)
- mm_plugin_base_add_modem (MM_PLUGIN_BASE (self), modem);
} else {
- if (!mm_modem_grab_port (modem, subsys, name, error))
- modem = NULL;
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
+ return NULL;
}
-out:
- g_free (driver);
- g_object_unref (device);
- g_object_unref (physdev);
return modem;
}
-static const char *
-get_name (MMPlugin *plugin)
-{
- return "MotoC";
-}
-
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->supports_port = supports_port;
- plugin_class->grab_port = grab_port;
-}
-
-static void
mm_plugin_moto_c_init (MMPluginMotoC *self)
{
- MMPluginMotoCPrivate *priv = MM_PLUGIN_MOTO_C_GET_PRIVATE (self);
- const char *subsys[2] = { "tty", NULL };
-
- priv->client = g_udev_client_new (subsys);
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
dispose (GObject *object)
{
- MMPluginMotoCPrivate *priv = MM_PLUGIN_MOTO_C_GET_PRIVATE (object);
-
- g_object_unref (priv->client);
}
static void
mm_plugin_moto_c_class_init (MMPluginMotoCClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (object_class, sizeof (MMPluginMotoCPrivate));
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
object_class->dispose = dispose;
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
}
diff --git a/plugins/mm-plugin-nokia.c b/plugins/mm-plugin-nokia.c
index 4d1dc955..06232209 100644
--- a/plugins/mm-plugin-nokia.c
+++ b/plugins/mm-plugin-nokia.c
@@ -1,14 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <string.h>
#include <gmodule.h>
#include "mm-plugin-nokia.h"
#include "mm-modem-nokia.h"
+#include "mm-generic-cdma.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginNokia, mm_plugin_nokia, G_TYPE_OBJECT,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginNokia, mm_plugin_nokia, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -16,111 +28,133 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_NOKIA, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_NOKIA,
+ MM_PLUGIN_BASE_NAME, "Nokia",
+ NULL));
}
/*****************************************************************************/
-static const char *
-get_name (MMPlugin *plugin)
+#define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
+ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856_A)
+
+static guint32
+get_level_for_capabilities (guint32 capabilities)
{
- return "Nokia";
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ if (capabilities & CAP_CDMA)
+ return 10;
+ return 0;
}
-static char **
-list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx)
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- char **supported = NULL;
- char **devices;
- int num_devices;
- int i;
-
- devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL);
- if (devices) {
- GPtrArray *array;
-
- array = g_ptr_array_new ();
-
- for (i = 0; i < num_devices; i++) {
- char *udi = devices[i];
-
- if (mm_plugin_supports_udi (plugin, hal_ctx, udi))
- g_ptr_array_add (array, g_strdup (udi));
- }
-
- if (array->len > 0) {
- g_ptr_array_add (array, NULL);
- supported = (char **) g_ptr_array_free (array, FALSE);
- } else
- g_ptr_array_free (array, TRUE);
- }
-
- g_strfreev (devices);
-
- return supported;
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
-static gboolean
-supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- char **capabilities;
- char **iter;
- gboolean supported = FALSE;
-
- capabilities = libhal_device_get_property_strlist (hal_ctx, udi, "modem.command_sets", NULL);
- for (iter = capabilities; iter && *iter && !supported; iter++) {
- if (!strcmp (*iter, "GSM-07.07")) {
- char *parent_udi;
-
- parent_udi = libhal_device_get_property_string (hal_ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- int vendor;
-
- vendor = libhal_device_get_property_int (hal_ctx, parent_udi, "usb.vendor_id", NULL);
- if (vendor == 0x0421)
- supported = TRUE;
-
- libhal_free_string (parent_udi);
- }
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *subsys, *name;
+ guint16 vendor = 0;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x0421)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
}
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
- g_strfreev (capabilities);
- return supported;
-}
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
-static char *
-get_driver_name (LibHalContext *ctx, const char *udi)
-{
- char *parent_udi;
- char *driver = NULL;
-
- parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL);
- libhal_free_string (parent_udi);
- }
-
- return driver;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
+ GError **error)
{
- char *data_device;
- char *driver;
- MMModem *modem;
-
- data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL);
- g_return_val_if_fail (data_device != NULL, NULL);
+ GUdevDevice *port = NULL, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
- driver = get_driver_name (hal_ctx, udi);
- g_return_val_if_fail (driver != NULL, NULL);
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
+ sysfs_path = g_udev_device_get_sysfs_path (physdev);
+ if (!sysfs_path) {
+ g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
+ return NULL;
+ }
- modem = MM_MODEM (mm_modem_nokia_new (data_device, driver));
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_nokia_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else if (caps & CAP_CDMA) {
+ modem = mm_generic_cdma_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ }
- libhal_free_string (data_device);
- libhal_free_string (driver);
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else {
+ if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
+ return NULL;
+ }
+ }
return modem;
}
@@ -128,21 +162,16 @@ create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->list_supported_udis = list_supported_udis;
- plugin_class->supports_udi = supports_udi;
- plugin_class->create_modem = create_modem;
-}
-
-static void
mm_plugin_nokia_init (MMPluginNokia *self)
{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
mm_plugin_nokia_class_init (MMPluginNokiaClass *klass)
{
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
}
diff --git a/plugins/mm-plugin-nokia.h b/plugins/mm-plugin-nokia.h
index 014e3022..fdc0f417 100644
--- a/plugins/mm-plugin-nokia.h
+++ b/plugins/mm-plugin-nokia.h
@@ -1,10 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_PLUGIN_NOKIA_H
#define MM_PLUGIN_NOKIA_H
-#include "mm-plugin.h"
-#include "mm-generic-gsm.h"
+#include "mm-plugin-base.h"
#define MM_TYPE_PLUGIN_NOKIA (mm_plugin_nokia_get_type ())
#define MM_PLUGIN_NOKIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_NOKIA, MMPluginNokia))
@@ -14,11 +27,11 @@
#define MM_PLUGIN_NOKIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_NOKIA, MMPluginNokiaClass))
typedef struct {
- GObject parent;
+ MMPluginBase parent;
} MMPluginNokia;
typedef struct {
- GObjectClass parent;
+ MMPluginBaseClass parent;
} MMPluginNokiaClass;
GType mm_plugin_nokia_get_type (void);
diff --git a/plugins/mm-plugin-novatel.c b/plugins/mm-plugin-novatel.c
index 0957c7d5..33ab393b 100644
--- a/plugins/mm-plugin-novatel.c
+++ b/plugins/mm-plugin-novatel.c
@@ -1,15 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <string.h>
#include <gmodule.h>
#include "mm-plugin-novatel.h"
-#include "mm-modem-novatel-cdma.h"
#include "mm-modem-novatel-gsm.h"
+#include "mm-generic-cdma.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginNovatel, mm_plugin_novatel, G_TYPE_OBJECT,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginNovatel, mm_plugin_novatel, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -17,136 +28,137 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_NOVATEL, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_NOVATEL,
+ MM_PLUGIN_BASE_NAME, "Novatel",
+ NULL));
}
/*****************************************************************************/
-static const char *
-get_name (MMPlugin *plugin)
-{
- return "Novatel";
-}
+#define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
+ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856_A)
-static char **
-list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx)
+static guint32
+get_level_for_capabilities (guint32 capabilities)
{
- char **supported = NULL;
- char **devices;
- int num_devices;
- int i;
-
- devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL);
- if (devices) {
- GPtrArray *array;
-
- array = g_ptr_array_new ();
-
- for (i = 0; i < num_devices; i++) {
- char *udi = devices[i];
-
- if (mm_plugin_supports_udi (plugin, hal_ctx, udi))
- g_ptr_array_add (array, g_strdup (udi));
- }
-
- if (array->len > 0) {
- g_ptr_array_add (array, NULL);
- supported = (char **) g_ptr_array_free (array, FALSE);
- } else
- g_ptr_array_free (array, TRUE);
- }
-
- g_strfreev (devices);
-
- return supported;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ if (capabilities & CAP_CDMA)
+ return 10;
+ return 0;
}
static void
-is_novatel_modem (LibHalContext *hal_ctx,
- const char *udi,
- gboolean *is_novatel_gsm,
- gboolean *is_novatel_cdma)
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- char **capabilities;
- char **iter;
-
- *is_novatel_gsm = *is_novatel_cdma = FALSE;
-
- capabilities = libhal_device_get_property_strlist (hal_ctx, udi, "modem.command_sets", NULL);
- for (iter = capabilities; iter && *iter && !*is_novatel_gsm && !*is_novatel_cdma; iter++) {
- char *parent_udi;
-
- parent_udi = libhal_device_get_property_string (hal_ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- int vendor;
-
- vendor = libhal_device_get_property_int (hal_ctx, parent_udi, "usb.vendor_id", NULL);
- if (vendor == 0x1410) {
- if (!strcmp (*iter, "GSM-07.07")) {
- *is_novatel_gsm = TRUE;
- } else if (!strcmp (*iter, "IS-707-A")) {
- *is_novatel_cdma = TRUE;
- }
- }
-
- libhal_free_string (parent_udi);
- }
- }
-
- g_strfreev (capabilities);
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
-static gboolean
-supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- gboolean is_novatel_gsm = FALSE;
- gboolean is_novatel_cdma = FALSE;
-
- is_novatel_modem (hal_ctx, udi, &is_novatel_gsm, &is_novatel_cdma);
-
- return is_novatel_gsm || is_novatel_cdma;
-}
-
-static char *
-get_driver_name (LibHalContext *ctx, const char *udi)
-{
- char *parent_udi;
- char *driver = NULL;
-
- parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL);
- libhal_free_string (parent_udi);
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *subsys, *name, *driver;
+ guint16 vendor = 0;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || (strcmp (driver, "option1") && strcmp (driver, "option")))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x1410 && vendor != 0x413c)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
- return driver;
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
+ GError **error)
{
- char *data_device;
- char *driver;
- MMModem *modem;
- gboolean is_novatel_gsm = FALSE;
- gboolean is_novatel_cdma = FALSE;
-
- is_novatel_modem (hal_ctx, udi, &is_novatel_gsm, &is_novatel_cdma);
- g_return_val_if_fail (!is_novatel_gsm && !is_novatel_cdma, NULL);
-
- data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL);
- g_return_val_if_fail (data_device != NULL, NULL);
+ GUdevDevice *port = NULL, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
- driver = get_driver_name (hal_ctx, udi);
- g_return_val_if_fail (driver != NULL, NULL);
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
+ sysfs_path = g_udev_device_get_sysfs_path (physdev);
+ if (!sysfs_path) {
+ g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
+ return NULL;
+ }
- if (is_novatel_gsm)
- modem = MM_MODEM (mm_modem_novatel_gsm_new (data_device, driver));
- else
- modem = MM_MODEM (mm_modem_novatel_cdma_new (data_device, driver));
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_novatel_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else if (caps & CAP_CDMA) {
+ modem = mm_generic_cdma_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ }
- libhal_free_string (data_device);
- libhal_free_string (driver);
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else {
+ if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
+ return NULL;
+ }
+ }
return modem;
}
@@ -154,21 +166,16 @@ create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->list_supported_udis = list_supported_udis;
- plugin_class->supports_udi = supports_udi;
- plugin_class->create_modem = create_modem;
-}
-
-static void
mm_plugin_novatel_init (MMPluginNovatel *self)
{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
mm_plugin_novatel_class_init (MMPluginNovatelClass *klass)
{
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
}
diff --git a/plugins/mm-plugin-novatel.h b/plugins/mm-plugin-novatel.h
index fbbf9735..450bbddd 100644
--- a/plugins/mm-plugin-novatel.h
+++ b/plugins/mm-plugin-novatel.h
@@ -1,9 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_PLUGIN_NOVATEL_H
#define MM_PLUGIN_NOVATEL_H
-#include "mm-plugin.h"
+#include "mm-plugin-base.h"
#include "mm-generic-gsm.h"
#define MM_TYPE_PLUGIN_NOVATEL (mm_plugin_novatel_get_type ())
@@ -14,11 +28,11 @@
#define MM_PLUGIN_NOVATEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_NOVATEL, MMPluginNovatelClass))
typedef struct {
- GObject parent;
+ MMPluginBase parent;
} MMPluginNovatel;
typedef struct {
- GObjectClass parent;
+ MMPluginBaseClass parent;
} MMPluginNovatelClass;
GType mm_plugin_novatel_get_type (void);
diff --git a/plugins/mm-plugin-option.c b/plugins/mm-plugin-option.c
index 1a231f40..6f4aaa97 100644
--- a/plugins/mm-plugin-option.c
+++ b/plugins/mm-plugin-option.c
@@ -1,14 +1,25 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <string.h>
#include <gmodule.h>
#include "mm-plugin-option.h"
#include "mm-modem-option.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginOption, mm_plugin_option, G_TYPE_OBJECT,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginOption, mm_plugin_option, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -16,117 +27,126 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_OPTION, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_OPTION,
+ MM_PLUGIN_BASE_NAME, "Option",
+ NULL));
}
/*****************************************************************************/
-static const char *
-get_name (MMPlugin *plugin)
+static guint32
+get_level_for_capabilities (guint32 capabilities)
{
- return "Option";
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ return 0;
}
-static char **
-list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx)
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- char **supported = NULL;
- char **devices;
- int num_devices;
- int i;
-
- devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL);
- if (devices) {
- GPtrArray *array;
-
- array = g_ptr_array_new ();
-
- for (i = 0; i < num_devices; i++) {
- char *udi = devices[i];
-
- if (mm_plugin_supports_udi (plugin, hal_ctx, udi))
- g_ptr_array_add (array, g_strdup (udi));
- }
-
- if (array->len > 0) {
- g_ptr_array_add (array, NULL);
- supported = (char **) g_ptr_array_free (array, FALSE);
- } else
- g_ptr_array_free (array, TRUE);
- }
-
- g_strfreev (devices);
-
- return supported;
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
-static gboolean
-supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- char **capabilities;
- char **iter;
- gboolean supported = FALSE;
-
- capabilities = libhal_device_get_property_strlist (hal_ctx, udi, "modem.command_sets", NULL);
- for (iter = capabilities; iter && *iter && !supported; iter++) {
- if (!strcmp (*iter, "GSM-07.07")) {
- char *parent_udi;
-
- parent_udi = libhal_device_get_property_string (hal_ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- int vendor;
-
- vendor = libhal_device_get_property_int (hal_ctx, parent_udi, "usb.vendor_id", NULL);
- if (vendor == 0x0af0) {
- char *driver;
-
- driver = libhal_device_get_property_string (hal_ctx, parent_udi, "info.linux.driver", NULL);
- if (driver && !strcmp (driver, "option"))
- supported = TRUE;
- libhal_free_string (driver);
- }
-
- libhal_free_string (parent_udi);
- }
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *driver, *subsys, *name;
+ guint16 vendor = 0;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || (strcmp (driver, "option1") && strcmp (driver, "option")))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x0af0)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
}
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
- g_strfreev (capabilities);
- return supported;
-}
-
-static char *
-get_driver_name (LibHalContext *ctx, const char *udi)
-{
- char *parent_udi;
- char *driver = NULL;
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
- parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL);
- libhal_free_string (parent_udi);
- }
-
- return driver;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
+ GError **error)
{
- char *data_device;
- char *driver;
- MMModem *modem;
+ GUdevDevice *port = NULL, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
- data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL);
- g_return_val_if_fail (data_device != NULL, NULL);
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
+ sysfs_path = g_udev_device_get_sysfs_path (physdev);
+ if (!sysfs_path) {
+ g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
+ return NULL;
+ }
- driver = get_driver_name (hal_ctx, udi);
- g_return_val_if_fail (driver != NULL, NULL);
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
- modem = MM_MODEM (mm_modem_option_new (data_device, driver));
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_option_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ }
- libhal_free_string (data_device);
- libhal_free_string (driver);
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
+ return NULL;
+ }
+ }
return modem;
}
@@ -134,21 +154,16 @@ create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->list_supported_udis = list_supported_udis;
- plugin_class->supports_udi = supports_udi;
- plugin_class->create_modem = create_modem;
-}
-
-static void
mm_plugin_option_init (MMPluginOption *self)
{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
mm_plugin_option_class_init (MMPluginOptionClass *klass)
{
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
}
diff --git a/plugins/mm-plugin-option.h b/plugins/mm-plugin-option.h
index 7ac7e8a5..dfcff749 100644
--- a/plugins/mm-plugin-option.h
+++ b/plugins/mm-plugin-option.h
@@ -1,9 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_PLUGIN_OPTION_H
#define MM_PLUGIN_OPTION_H
-#include "mm-plugin.h"
+#include "mm-plugin-base.h"
#include "mm-generic-gsm.h"
#define MM_TYPE_PLUGIN_OPTION (mm_plugin_option_get_type ())
@@ -14,11 +28,11 @@
#define MM_PLUGIN_OPTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_OPTION, MMPluginOptionClass))
typedef struct {
- GObject parent;
+ MMPluginBase parent;
} MMPluginOption;
typedef struct {
- GObjectClass parent;
+ MMPluginBaseClass parent;
} MMPluginOptionClass;
GType mm_plugin_option_get_type (void);
diff --git a/plugins/mm-plugin-sierra.c b/plugins/mm-plugin-sierra.c
index 7185c4dd..9a02a059 100644
--- a/plugins/mm-plugin-sierra.c
+++ b/plugins/mm-plugin-sierra.c
@@ -1,14 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <string.h>
#include <gmodule.h>
#include "mm-plugin-sierra.h"
#include "mm-modem-sierra.h"
+#include "mm-generic-cdma.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginSierra, mm_plugin_sierra, G_TYPE_OBJECT,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginSierra, mm_plugin_sierra, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -16,119 +28,157 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_SIERRA, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_SIERRA,
+ MM_PLUGIN_BASE_NAME, "Sierra",
+ NULL));
}
/*****************************************************************************/
-static const char *
-get_name (MMPlugin *plugin)
+#define TAG_SIERRA_SECONDARY_PORT "sierra-secondary-port"
+
+#define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
+ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856_A)
+
+static guint32
+get_level_for_capabilities (guint32 capabilities)
{
- return "Sierra";
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ if (capabilities & CAP_CDMA)
+ return 10;
+ return 0;
}
-static char **
-list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx)
+static void
+handle_probe_response (MMPluginBase *self,
+ MMPluginBaseSupportsTask *task,
+ const char *cmd,
+ const char *response,
+ const GError *error)
{
- char **supported = NULL;
- char **devices;
- int num_devices;
- int i;
-
- devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL);
- if (devices) {
- GPtrArray *array;
-
- array = g_ptr_array_new ();
-
- for (i = 0; i < num_devices; i++) {
- char *udi = devices[i];
-
- if (mm_plugin_supports_udi (plugin, hal_ctx, udi))
- g_ptr_array_add (array, g_strdup (udi));
- }
-
- if (array->len > 0) {
- g_ptr_array_add (array, NULL);
- supported = (char **) g_ptr_array_free (array, FALSE);
- } else
- g_ptr_array_free (array, TRUE);
+ if (error || !response || strcmp (cmd, "I")) {
+ MM_PLUGIN_BASE_CLASS (mm_plugin_sierra_parent_class)->handle_probe_response (self, task, cmd, response, error);
+ return;
}
- g_strfreev (devices);
+ if (strstr (response, "APP1") || strstr (response, "APP2") || strstr (response, "APP3")) {
+ g_object_set_data (G_OBJECT (task), TAG_SIERRA_SECONDARY_PORT, GUINT_TO_POINTER (TRUE));
+ mm_plugin_base_supports_task_complete (task, 10);
+ return;
+ }
- return supported;
+ /* Not an app port, let the superclass handle the response */
+ MM_PLUGIN_BASE_CLASS (mm_plugin_sierra_parent_class)->handle_probe_response (self, task, cmd, response, error);
}
-static gboolean
-supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- char **capabilities;
- char **iter;
- gboolean supported = FALSE;
-
- capabilities = libhal_device_get_property_strlist (hal_ctx, udi, "modem.command_sets", NULL);
- for (iter = capabilities; iter && *iter && !supported; iter++) {
- if (!strcmp (*iter, "GSM-07.07")) {
- char *parent_udi;
-
- parent_udi = libhal_device_get_property_string (hal_ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- int vendor;
-
- vendor = libhal_device_get_property_int (hal_ctx, parent_udi, "usb.vendor_id", NULL);
- if (vendor == 0x1199)
- supported = TRUE;
-
- if (vendor == 0x03f0) {
- int product;
-
- product = libhal_device_get_property_int (hal_ctx, parent_udi, "usb.product_id", NULL);
- if (product == 0x1e1d)
- supported = TRUE;
- }
-
- libhal_free_string (parent_udi);
- }
- }
- }
- g_strfreev (capabilities);
-
- return supported;
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
-static char *
-get_driver_name (LibHalContext *ctx, const char *udi)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- char *parent_udi;
- char *driver = NULL;
-
- parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL);
- libhal_free_string (parent_udi);
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *driver;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || strcmp (driver, "sierra"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
- return driver;
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
+ GError **error)
{
- char *data_device;
- char *driver;
- MMModem *modem;
+ GUdevDevice *port = NULL, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
- data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL);
- g_return_val_if_fail (data_device != NULL, NULL);
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
+ sysfs_path = g_udev_device_get_sysfs_path (physdev);
+ if (!sysfs_path) {
+ g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
+ return NULL;
+ }
- driver = get_driver_name (hal_ctx, udi);
- g_return_val_if_fail (driver != NULL, NULL);
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_sierra_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else if (caps & CAP_CDMA) {
+ modem = mm_generic_cdma_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ }
- modem = MM_MODEM (mm_modem_sierra_new (data_device, driver));
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else {
+ gpointer gsm_data = NULL;
- libhal_free_string (data_device);
- libhal_free_string (driver);
+ /* Is this a GSM secondary port? */
+ if (g_object_get_data (G_OBJECT (task), TAG_SIERRA_SECONDARY_PORT))
+ gsm_data = GUINT_TO_POINTER (TRUE);
+
+ if ((caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) || gsm_data) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, gsm_data, error))
+ return NULL;
+ }
+ }
return modem;
}
@@ -136,21 +186,17 @@ create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->list_supported_udis = list_supported_udis;
- plugin_class->supports_udi = supports_udi;
- plugin_class->create_modem = create_modem;
-}
-
-static void
mm_plugin_sierra_init (MMPluginSierra *self)
{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
mm_plugin_sierra_class_init (MMPluginSierraClass *klass)
{
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
+ pb_class->handle_probe_response = handle_probe_response;
}
diff --git a/plugins/mm-plugin-sierra.h b/plugins/mm-plugin-sierra.h
index b2473acb..01fffc4c 100644
--- a/plugins/mm-plugin-sierra.h
+++ b/plugins/mm-plugin-sierra.h
@@ -1,9 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_PLUGIN_SIERRA_H
#define MM_PLUGIN_SIERRA_H
-#include "mm-plugin.h"
+#include "mm-plugin-base.h"
#include "mm-generic-gsm.h"
#define MM_TYPE_PLUGIN_SIERRA (mm_plugin_sierra_get_type ())
@@ -14,11 +28,11 @@
#define MM_PLUGIN_SIERRA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_SIERRA, MMPluginSierraClass))
typedef struct {
- GObject parent;
+ MMPluginBase parent;
} MMPluginSierra;
typedef struct {
- GObjectClass parent;
+ MMPluginBaseClass parent;
} MMPluginSierraClass;
GType mm_plugin_sierra_get_type (void);
diff --git a/plugins/mm-plugin-zte.c b/plugins/mm-plugin-zte.c
index 29e90ab9..e830823f 100644
--- a/plugins/mm-plugin-zte.c
+++ b/plugins/mm-plugin-zte.c
@@ -1,14 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <string.h>
#include <gmodule.h>
#include "mm-plugin-zte.h"
#include "mm-modem-zte.h"
+#include "mm-generic-cdma.h"
-static void plugin_init (MMPlugin *plugin_class);
-
-G_DEFINE_TYPE_EXTENDED (MMPluginZte, mm_plugin_zte, G_TYPE_OBJECT,
- 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+G_DEFINE_TYPE (MMPluginZte, mm_plugin_zte, MM_TYPE_PLUGIN_BASE)
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -16,111 +28,127 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
- return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_ZTE, NULL));
+ return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_ZTE,
+ MM_PLUGIN_BASE_NAME, "ZTE",
+ NULL));
}
/*****************************************************************************/
-static const char *
-get_name (MMPlugin *plugin)
+#define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
+ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856_A)
+
+static guint32
+get_level_for_capabilities (guint32 capabilities)
{
- return "ZTE";
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ if (capabilities & CAP_CDMA)
+ return 10;
+ return 0;
}
-static char **
-list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx)
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
{
- char **supported = NULL;
- char **devices;
- int num_devices;
- int i;
-
- devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL);
- if (devices) {
- GPtrArray *array;
-
- array = g_ptr_array_new ();
-
- for (i = 0; i < num_devices; i++) {
- char *udi = devices[i];
-
- if (mm_plugin_supports_udi (plugin, hal_ctx, udi))
- g_ptr_array_add (array, g_strdup (udi));
- }
-
- if (array->len > 0) {
- g_ptr_array_add (array, NULL);
- supported = (char **) g_ptr_array_free (array, FALSE);
- } else
- g_ptr_array_free (array, TRUE);
- }
-
- g_strfreev (devices);
-
- return supported;
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
-static gboolean
-supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
{
- char **capabilities;
- char **iter;
- gboolean supported = FALSE;
-
- capabilities = libhal_device_get_property_strlist (hal_ctx, udi, "modem.command_sets", NULL);
- for (iter = capabilities; iter && *iter && !supported; iter++) {
- if (!strcmp (*iter, "GSM-07.07")) {
- char *parent_udi;
-
- parent_udi = libhal_device_get_property_string (hal_ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- int vendor;
-
- vendor = libhal_device_get_property_int (hal_ctx, parent_udi, "usb.vendor_id", NULL);
- if (vendor == 0x19d2)
- supported = TRUE;
-
- libhal_free_string (parent_udi);
- }
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ guint16 vendor = 0;
+ const char *subsys, *name;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x19d2)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
}
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
- g_strfreev (capabilities);
- return supported;
-}
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
-static char *
-get_driver_name (LibHalContext *ctx, const char *udi)
-{
- char *parent_udi;
- char *driver = NULL;
-
- parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL);
- libhal_free_string (parent_udi);
- }
-
- return driver;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static MMModem *
-create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
+ GError **error)
{
- char *data_device;
- char *driver;
- MMModem *modem;
-
- data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL);
- g_return_val_if_fail (data_device != NULL, NULL);
-
- driver = get_driver_name (hal_ctx, udi);
- g_return_val_if_fail (driver != NULL, NULL);
+ GUdevDevice *port = NULL, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *sysfs_path;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
+ sysfs_path = g_udev_device_get_sysfs_path (physdev);
+ if (!sysfs_path) {
+ g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
+ return NULL;
+ }
- modem = MM_MODEM (mm_modem_zte_new (data_device, driver));
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_zte_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else if (caps & CAP_CDMA) {
+ modem = mm_generic_cdma_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ }
- libhal_free_string (data_device);
- libhal_free_string (driver);
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else {
+ if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
+ return NULL;
+ }
+ }
return modem;
}
@@ -128,21 +156,16 @@ create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
/*****************************************************************************/
static void
-plugin_init (MMPlugin *plugin_class)
-{
- /* interface implementation */
- plugin_class->get_name = get_name;
- plugin_class->list_supported_udis = list_supported_udis;
- plugin_class->supports_udi = supports_udi;
- plugin_class->create_modem = create_modem;
-}
-
-static void
mm_plugin_zte_init (MMPluginZte *self)
{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
}
static void
mm_plugin_zte_class_init (MMPluginZteClass *klass)
{
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
}
diff --git a/plugins/mm-plugin-zte.h b/plugins/mm-plugin-zte.h
index 9fe5b438..7a4d4c9a 100644
--- a/plugins/mm-plugin-zte.h
+++ b/plugins/mm-plugin-zte.h
@@ -1,9 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#ifndef MM_PLUGIN_ZTE_H
#define MM_PLUGIN_ZTE_H
-#include "mm-plugin.h"
+#include "mm-plugin-base.h"
#define MM_TYPE_PLUGIN_ZTE (mm_plugin_zte_get_type ())
#define MM_PLUGIN_ZTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_ZTE, MMPluginZte))
@@ -13,11 +27,11 @@
#define MM_PLUGIN_ZTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_ZTE, MMPluginZteClass))
typedef struct {
- GObject parent;
+ MMPluginBase parent;
} MMPluginZte;
typedef struct {
- GObjectClass parent;
+ MMPluginBaseClass parent;
} MMPluginZteClass;
GType mm_plugin_zte_get_type (void);
diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c
index 9dad455f..a333f2f2 100644
--- a/src/mm-generic-cdma.c
+++ b/src/mm-generic-cdma.c
@@ -85,6 +85,7 @@ static gboolean
grab_port (MMModem *modem,
const char *subsys,
const char *name,
+ gpointer user_data,
GError **error)
{
MMGenericCdma *self = MM_GENERIC_CDMA (modem);
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 73a27e5c..e27ab51d 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -252,6 +252,7 @@ static gboolean
grab_port (MMModem *modem,
const char *subsys,
const char *name,
+ gpointer user_data,
GError **error)
{
MMGenericGsm *self = MM_GENERIC_GSM (modem);
diff --git a/src/mm-manager.c b/src/mm-manager.c
index 3d3b1ac1..c6445cf6 100644
--- a/src/mm-manager.c
+++ b/src/mm-manager.c
@@ -36,6 +36,8 @@ typedef struct {
GUdevClient *udev;
GSList *plugins;
GHashTable *modems;
+
+ GHashTable *supports;
} MMManagerPrivate;
static MMPlugin *
@@ -99,6 +101,7 @@ load_plugins (MMManager *manager)
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GDir *dir;
const char *fname;
+ MMPlugin *generic_plugin = NULL;
if (!g_module_supported ()) {
g_warning ("GModules are not supported on your platform!");
@@ -122,10 +125,18 @@ load_plugins (MMManager *manager)
plugin = load_plugin (path);
g_free (path);
- if (plugin)
- priv->plugins = g_slist_append (priv->plugins, plugin);
+ if (plugin) {
+ if (!strcmp (mm_plugin_get_name (plugin), MM_PLUGIN_GENERIC_NAME))
+ generic_plugin = plugin;
+ else
+ priv->plugins = g_slist_append (priv->plugins, plugin);
+ }
}
+ /* Make sure the generic plugin is last */
+ if (generic_plugin)
+ priv->plugins = g_slist_append (priv->plugins, generic_plugin);
+
g_dir_close (dir);
}
@@ -179,7 +190,7 @@ modem_valid (MMModem *modem, GParamSpec *pspec, gpointer user_data)
device = mm_modem_get_device (modem);
g_assert (device);
- g_debug ("Exported modem %s", device);
+ g_debug ("Exported modem %s as %s", device, path);
g_free (device);
g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem);
@@ -236,107 +247,281 @@ impl_manager_enumerate_devices (MMManager *manager,
return TRUE;
}
+static MMModem *
+find_modem_for_port (MMManager *manager, const char *subsys, const char *name)
+{
+ MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, priv->modems);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ MMModem *modem = MM_MODEM (value);
+
+ if (mm_modem_owns_port (modem, subsys, name))
+ return modem;
+ }
+ return NULL;
+}
+
typedef struct {
- MMModem *modem;
- const char *subsys;
- const char *name;
-} FindPortInfo;
+ MMManager *manager;
+ char *subsys;
+ char *name;
+ GSList *plugins;
+ GSList *cur_plugin;
+ guint defer_id;
+
+ guint32 best_level;
+ MMPlugin *best_plugin;
+} SupportsInfo;
+
+static SupportsInfo *
+supports_info_new (MMManager *self, const char *subsys, const char *name)
+{
+ MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (self);
+ SupportsInfo *info;
+
+ info = g_malloc0 (sizeof (SupportsInfo));
+ info->manager = self;
+ info->subsys = g_strdup (subsys);
+ info->name = g_strdup (name);
+ info->plugins = g_slist_copy (priv->plugins);
+ info->cur_plugin = info->plugins;
+ return info;
+}
static void
-find_port (gpointer key, gpointer data, gpointer user_data)
+supports_info_free (SupportsInfo *info)
{
- FindPortInfo *info = user_data;
- MMModem *modem = MM_MODEM (data);
+ /* Cancel any in-process operation on the first plugin */
+ if (info->cur_plugin)
+ mm_plugin_cancel_supports_port (MM_PLUGIN (info->cur_plugin->data), info->subsys, info->name);
+
+ if (info->defer_id)
+ g_source_remove (info->defer_id);
+
+ g_free (info->subsys);
+ g_free (info->name);
+ g_slist_free (info->plugins);
+ memset (info, 0, sizeof (SupportsInfo));
+ g_free (info);
+}
- if (!info->modem && mm_modem_owns_port (modem, info->subsys, info->name))
- info->modem = modem;
+static char *
+get_key (const char *subsys, const char *name)
+{
+ return g_strdup_printf ("%s%s", subsys, name);
}
-static MMModem *
-find_modem_for_port (MMManager *manager, const char *subsys, const char *name)
+
+static void supports_callback (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ guint32 level,
+ gpointer user_data);
+
+static void try_supports_port (MMManager *manager,
+ MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ SupportsInfo *info);
+
+static gboolean
+supports_defer_timeout (gpointer user_data)
{
- MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
- FindPortInfo info = { NULL, subsys, name };
+ SupportsInfo *info = user_data;
+
+ g_debug ("(%s): re-checking support...", info->name);
+ try_supports_port (info->manager,
+ MM_PLUGIN (info->cur_plugin->data),
+ info->subsys,
+ info->name,
+ info);
+ return FALSE;
+}
+
+static void
+try_supports_port (MMManager *manager,
+ MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ SupportsInfo *info)
+{
+ MMPluginSupportsResult result;
+
+ result = mm_plugin_supports_port (plugin, subsys, name, supports_callback, info);
+
+ switch (result) {
+ case MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED:
+ /* If the plugin knows it doesn't support the modem, just call the
+ * callback and indicate 0 support.
+ */
+ supports_callback (plugin, subsys, name, 0, info);
+ break;
+ case MM_PLUGIN_SUPPORTS_PORT_DEFER:
+ g_debug ("(%s): (%s) deferring support check", mm_plugin_get_name (plugin), name);
+ if (info->defer_id)
+ g_source_remove (info->defer_id);
+
+ /* defer port detection for a bit as requested by the plugin */
+ info->defer_id = g_timeout_add (3000, supports_defer_timeout, info);
+ break;
+ case MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS:
+ default:
+ break;
+ }
+}
+
+static void
+supports_callback (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ guint32 level,
+ gpointer user_data)
+{
+ SupportsInfo *info = user_data;
+ MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (info->manager);
+ MMModem *modem;
+ GError *error = NULL;
+ char *key;
+ GSList *iter;
+ MMPlugin *next_plugin = NULL;
+
+ info->cur_plugin = info->cur_plugin->next;
+ if (info->cur_plugin)
+ next_plugin = MM_PLUGIN (info->cur_plugin->data);
+
+ /* Is this plugin's result better than any one we've tried before? */
+ if (level > info->best_level) {
+ info->best_level = level;
+ info->best_plugin = plugin;
+ }
- g_hash_table_foreach (priv->modems, find_port, &info);
- return info.modem;
+ /* Prevent the generic plugin from probing devices that are already supported
+ * by other plugins. For Huawei for example, secondary ports shouldn't
+ * be probed, but the generic plugin would happily do so if allowed to.
+ */
+ if ( next_plugin
+ && !strcmp (mm_plugin_get_name (next_plugin), MM_PLUGIN_GENERIC_NAME)
+ && info->best_plugin)
+ next_plugin = NULL;
+
+ /* Try the next plugin */
+ if (next_plugin) {
+ try_supports_port (info->manager, next_plugin, info->subsys, info->name, info);
+ return;
+ }
+
+ /* No more plugins to try */
+ if (info->best_plugin) {
+ /* Create the modem */
+ modem = mm_plugin_grab_port (info->best_plugin, info->subsys, info->name, &error);
+ if (modem) {
+ guint32 modem_type = MM_MODEM_TYPE_UNKNOWN;
+ const char *type_name = "UNKNOWN";
+
+ g_object_get (G_OBJECT (modem), MM_MODEM_TYPE, &modem_type, NULL);
+ if (modem_type == MM_MODEM_TYPE_GSM)
+ type_name = "GSM";
+ else if (modem_type == MM_MODEM_TYPE_CDMA)
+ type_name = "CDMA";
+
+ g_message ("(%s): %s modem %s claimed port %s",
+ mm_plugin_get_name (info->best_plugin),
+ type_name,
+ mm_modem_get_device (modem),
+ name);
+
+ add_modem (info->manager, modem);
+ } else {
+ g_warning ("%s: plugin '%s' claimed to support %s/%s but couldn't: (%d) %s",
+ __func__,
+ mm_plugin_get_name (info->best_plugin),
+ subsys,
+ name,
+ error ? error->code : -1,
+ (error && error->message) ? error->message : "(unknown)");
+ }
+ }
+
+ /* Tell each plugin to clean up any outstanding supports task */
+ for (iter = info->plugins; iter; iter = g_slist_next (iter))
+ mm_plugin_cancel_supports_port (MM_PLUGIN (iter->data), subsys, name);
+ g_slist_free (info->plugins);
+ info->cur_plugin = info->plugins = NULL;
+
+ key = get_key (info->subsys, info->name);
+ g_hash_table_remove (priv->supports, key);
+ g_free (key);
}
static void
device_added (MMManager *manager, GUdevDevice *device)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
- GSList *iter;
- MMModem *modem = NULL;
const char *subsys, *name;
- MMPlugin *best_plugin = NULL;
- guint32 best_level = 0;
- GError *error = NULL;
+ SupportsInfo *info;
+ char *key;
+ gboolean found;
g_return_if_fail (device != NULL);
+ if (!g_slist_length (priv->plugins))
+ return;
+
subsys = g_udev_device_get_subsystem (device);
name = g_udev_device_get_name (device);
if (find_modem_for_port (manager, subsys, name))
return;
- /* Build up the list of plugins that support this port */
- for (iter = priv->plugins; iter; iter = iter->next) {
- MMPlugin *plugin = MM_PLUGIN (iter->data);
- guint32 level;
-
- level = mm_plugin_supports_port (plugin, subsys, name);
- if (level > best_level) {
- best_plugin = plugin;
- best_level = level;
- }
- }
-
- /* Let the best plugin handle this port */
- if (!best_plugin)
- return;
-
- modem = mm_plugin_grab_port (best_plugin, subsys, name, &error);
- if (modem) {
- guint32 modem_type = MM_MODEM_TYPE_UNKNOWN;
- const char *type_name = "UNKNOWN";
-
- g_object_get (G_OBJECT (modem), MM_MODEM_TYPE, &modem_type, NULL);
- if (modem_type == MM_MODEM_TYPE_GSM)
- type_name = "GSM";
- else if (modem_type == MM_MODEM_TYPE_CDMA)
- type_name = "CDMA";
-
- g_message ("(%s): %s modem %s claimed port %s",
- mm_plugin_get_name (best_plugin),
- type_name,
- mm_modem_get_device (modem),
- name);
- } else {
- g_warning ("%s: plugin '%s' claimed to support %s/%s but couldn't: (%d) %s",
- __func__, mm_plugin_get_name (best_plugin), subsys, name,
- error ? error->code : -1,
- (error && error->message) ? error->message : "(unknown)");
+ key = get_key (subsys, name);
+ found = !!g_hash_table_lookup (priv->supports, key);
+ if (found) {
+ g_free (key);
return;
}
- add_modem (manager, modem);
+ info = supports_info_new (manager, subsys, name);
+ g_hash_table_insert (priv->supports, key, info);
+
+ try_supports_port (manager, MM_PLUGIN (info->cur_plugin->data), subsys, name, info);
}
static void
device_removed (MMManager *manager, GUdevDevice *device)
{
+ MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
MMModem *modem;
const char *subsys, *name;
+ char *key;
+ SupportsInfo *info;
g_return_if_fail (device != NULL);
+ if (!g_slist_length (priv->plugins))
+ return;
+
subsys = g_udev_device_get_subsystem (device);
name = g_udev_device_get_name (device);
modem = find_modem_for_port (manager, subsys, name);
- if (modem)
+ if (modem) {
mm_modem_release_port (modem, subsys, name);
+ return;
+ }
+
+ /* Maybe a plugin is checking whether or not the port is supported */
+ key = get_key (subsys, name);
+ info = g_hash_table_lookup (priv->supports, key);
+
+ if (info) {
+ if (info->plugins)
+ mm_plugin_cancel_supports_port (MM_PLUGIN (info->plugins->data), subsys, name);
+ g_hash_table_remove (priv->supports, key);
+ }
+
+ g_free (key);
}
static void
@@ -391,6 +576,8 @@ mm_manager_init (MMManager *manager)
priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
load_plugins (manager);
+ priv->supports = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) supports_info_free);
+
priv->udev = g_udev_client_new (subsys);
g_assert (priv->udev);
g_signal_connect (priv->udev, "uevent", G_CALLBACK (handle_uevent), manager);
@@ -401,6 +588,7 @@ finalize (GObject *object)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (object);
+ g_hash_table_destroy (priv->supports);
g_hash_table_destroy (priv->modems);
g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL);
@@ -454,3 +642,4 @@ mm_manager_class_init (MMManagerClass *manager_class)
dbus_g_error_domain_register (MM_MODEM_CONNECT_ERROR, "org.freedesktop.ModemManager.Modem", MM_TYPE_MODEM_CONNECT_ERROR);
dbus_g_error_domain_register (MM_MOBILE_ERROR, "org.freedesktop.ModemManager.Modem.Gsm", MM_TYPE_MOBILE_ERROR);
}
+
diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c
index 1e719e58..30de1123 100644
--- a/src/mm-modem-base.c
+++ b/src/mm-modem-base.c
@@ -56,7 +56,7 @@ mm_modem_base_get_port (MMModemBase *self,
key = get_hash_key (subsys, name);
port = g_hash_table_lookup (MM_MODEM_BASE_GET_PRIVATE (self)->ports, key);
g_free (key);
- return NULL;
+ return port;
}
static void
diff --git a/src/mm-modem.c b/src/mm-modem.c
index 63a8929e..3a566d08 100644
--- a/src/mm-modem.c
+++ b/src/mm-modem.c
@@ -300,6 +300,7 @@ gboolean
mm_modem_grab_port (MMModem *self,
const char *subsys,
const char *name,
+ gpointer user_data,
GError **error)
{
g_return_val_if_fail (self != NULL, FALSE);
@@ -308,7 +309,7 @@ mm_modem_grab_port (MMModem *self,
g_return_val_if_fail (name, FALSE);
g_assert (MM_MODEM_GET_INTERFACE (self)->grab_port);
- return MM_MODEM_GET_INTERFACE (self)->grab_port (self, subsys, name, error);
+ return MM_MODEM_GET_INTERFACE (self)->grab_port (self, subsys, name, user_data, error);
}
void
diff --git a/src/mm-modem.h b/src/mm-modem.h
index 5a2c3a8a..9222b703 100644
--- a/src/mm-modem.h
+++ b/src/mm-modem.h
@@ -78,6 +78,7 @@ struct _MMModem {
gboolean (*grab_port) (MMModem *self,
const char *subsys,
const char *name,
+ gpointer user_data,
GError **error);
void (*release_port) (MMModem *self,
@@ -116,6 +117,7 @@ gboolean mm_modem_owns_port (MMModem *self,
gboolean mm_modem_grab_port (MMModem *self,
const char *subsys,
const char *name,
+ gpointer user_data,
GError **error);
void mm_modem_release_port (MMModem *self,
diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c
index 6daa5895..25456ca5 100644
--- a/src/mm-plugin-base.c
+++ b/src/mm-plugin-base.c
@@ -23,66 +23,529 @@
#include <gudev/gudev.h>
#include "mm-plugin-base.h"
+#include "mm-serial-port.h"
+#include "mm-serial-parsers.h"
+#include "mm-errors.h"
+#include "mm-marshal.h"
-G_DEFINE_TYPE (MMPluginBase, mm_plugin_base, G_TYPE_OBJECT)
+static void plugin_init (MMPlugin *plugin_class);
+
+G_DEFINE_TYPE_EXTENDED (MMPluginBase, mm_plugin_base, G_TYPE_OBJECT,
+ 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
#define MM_PLUGIN_BASE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_BASE, MMPluginBasePrivate))
+/* A hash table shared between all instances of the plugin base that
+ * caches the probed capabilities so that only one plugin has to actually
+ * probe a port.
+ */
+static GHashTable *cached_caps = NULL;
+
+
typedef struct {
+ char *name;
+ GUdevClient *client;
+
GHashTable *modems;
+ GHashTable *tasks;
} MMPluginBasePrivate;
+enum {
+ PROP_0,
+ PROP_NAME,
+ LAST_PROP
+};
+
+enum {
+ PROBE_RESULT,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+
+typedef enum {
+ PROBE_STATE_GCAP_TRY1 = 0,
+ PROBE_STATE_GCAP_TRY2,
+ PROBE_STATE_GCAP_TRY3,
+ PROBE_STATE_ATI,
+ PROBE_STATE_CGMM,
+} ProbeState;
+
+/*****************************************************************************/
+
+G_DEFINE_TYPE (MMPluginBaseSupportsTask, mm_plugin_base_supports_task, G_TYPE_OBJECT)
+
+#define MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, MMPluginBaseSupportsTaskPrivate))
typedef struct {
- char *key;
- gpointer modem;
-} FindInfo;
+ MMPluginBase *plugin;
+ GUdevDevice *port;
+ GUdevDevice *physdev;
+ char *driver;
+
+ MMSerialPort *probe_port;
+ guint32 probed_caps;
+ ProbeState probe_state;
+ guint probe_id;
+ char *probe_resp;
+ GError *probe_error;
+
+ MMSupportsPortResultFunc callback;
+ gpointer callback_data;
+} MMPluginBaseSupportsTaskPrivate;
+
+static MMPluginBaseSupportsTask *
+supports_task_new (MMPluginBase *self,
+ GUdevDevice *port,
+ GUdevDevice *physdev,
+ const char *driver,
+ MMSupportsPortResultFunc callback,
+ gpointer callback_data)
+{
+ MMPluginBaseSupportsTask *task;
+ MMPluginBaseSupportsTaskPrivate *priv;
+
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (MM_IS_PLUGIN_BASE (self), NULL);
+ g_return_val_if_fail (port != NULL, NULL);
+ g_return_val_if_fail (physdev != NULL, NULL);
+ g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (callback != NULL, NULL);
+
+ task = (MMPluginBaseSupportsTask *) g_object_new (MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, NULL);
+
+ priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+ priv->plugin = self;
+ priv->port = g_object_ref (port);
+ priv->physdev = g_object_ref (physdev);
+ priv->driver = g_strdup (driver);
+ priv->callback = callback;
+ priv->callback_data = callback_data;
+
+ return task;
+}
+
+MMPlugin *
+mm_plugin_base_supports_task_get_plugin (MMPluginBaseSupportsTask *task)
+{
+ g_return_val_if_fail (task != NULL, NULL);
+ g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
+
+ return MM_PLUGIN (MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->plugin);
+}
+
+GUdevDevice *
+mm_plugin_base_supports_task_get_port (MMPluginBaseSupportsTask *task)
+{
+ g_return_val_if_fail (task != NULL, NULL);
+ g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
+
+ return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->port;
+}
+
+GUdevDevice *
+mm_plugin_base_supports_task_get_physdev (MMPluginBaseSupportsTask *task)
+{
+ g_return_val_if_fail (task != NULL, NULL);
+ g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
+
+ return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->physdev;
+}
+
+const char *
+mm_plugin_base_supports_task_get_driver (MMPluginBaseSupportsTask *task)
+{
+ g_return_val_if_fail (task != NULL, NULL);
+ g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
+
+ return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->driver;
+}
+
+guint32
+mm_plugin_base_supports_task_get_probed_capabilities (MMPluginBaseSupportsTask *task)
+{
+ g_return_val_if_fail (task != NULL, 0);
+ g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), 0);
+
+ return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->probed_caps;
+}
+
+void
+mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task,
+ guint32 level)
+{
+ MMPluginBaseSupportsTaskPrivate *priv;
+ const char *subsys, *name;
+
+ g_return_if_fail (task != NULL);
+ g_return_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task));
+
+ priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+ g_return_if_fail (priv->callback != NULL);
+
+ subsys = g_udev_device_get_subsystem (priv->port);
+ name = g_udev_device_get_name (priv->port);
+
+ priv->callback (MM_PLUGIN (priv->plugin), subsys, name, level, priv->callback_data);
+
+ /* Clear out the callback, it shouldn't be called more than once */
+ priv->callback = NULL;
+ priv->callback_data = NULL;
+}
+
+static void
+mm_plugin_base_supports_task_init (MMPluginBaseSupportsTask *self)
+{
+}
static void
-find_modem (gpointer key, gpointer data, gpointer user_data)
+dispose (GObject *object)
{
- FindInfo *info = user_data;
+ MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (object);
+
+ g_object_unref (priv->port);
+ g_object_unref (priv->physdev);
+ g_free (priv->driver);
+ g_free (priv->probe_resp);
+ g_clear_error (&(priv->probe_error));
- if (!info->key && data == info->modem)
- info->key = g_strdup ((const char *) key);
+ if (priv->probe_id)
+ g_source_remove (priv->probe_id);
+ if (priv->probe_port)
+ g_object_unref (priv->probe_port);
+
+ G_OBJECT_CLASS (mm_plugin_base_supports_task_parent_class)->dispose (object);
}
static void
-modem_destroyed (gpointer data, GObject *modem)
+mm_plugin_base_supports_task_class_init (MMPluginBaseSupportsTaskClass *klass)
{
- MMPluginBase *self = MM_PLUGIN_BASE (data);
- MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
- FindInfo info = { NULL, modem };
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMPluginBaseSupportsTaskPrivate));
+
+ /* Virtual methods */
+ object_class->dispose = dispose;
+}
+
+/*****************************************************************************/
+
+#define TAG_PROBE_ID "mm-plugin-base-probe-id"
+#define TAG_PROBE_PORT "mm-plugin-base-probe-port"
+#define TAG_PROBE_STATE "mm-plugin-base-probe-state"
+
+#define MM_PLUGIN_BASE_PORT_CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
+ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856_A)
+
+#define CAP_GSM_OR_CDMA (MM_PLUGIN_BASE_PORT_CAP_CDMA | MM_PLUGIN_BASE_PORT_CAP_GSM)
+
+struct modem_caps {
+ char *name;
+ guint32 bits;
+};
+
+static struct modem_caps modem_caps[] = {
+ {"+CGSM", MM_PLUGIN_BASE_PORT_CAP_GSM},
+ {"+CIS707-A", MM_PLUGIN_BASE_PORT_CAP_IS707_A},
+ {"+CIS707A", MM_PLUGIN_BASE_PORT_CAP_IS707_A}, /* Cmotech */
+ {"+CIS707", MM_PLUGIN_BASE_PORT_CAP_IS707_A},
+ {"CIS707", MM_PLUGIN_BASE_PORT_CAP_IS707_A}, /* Qualcomm Gobi */
+ {"+CIS707P", MM_PLUGIN_BASE_PORT_CAP_IS707_P},
+ {"CIS-856", MM_PLUGIN_BASE_PORT_CAP_IS856},
+ {"+IS-856", MM_PLUGIN_BASE_PORT_CAP_IS856}, /* Cmotech */
+ {"CIS-856-A", MM_PLUGIN_BASE_PORT_CAP_IS856_A},
+ {"CIS-856A", MM_PLUGIN_BASE_PORT_CAP_IS856_A}, /* Kyocera KPC680 */
+ {"+DS", MM_PLUGIN_BASE_PORT_CAP_DS},
+ {"+ES", MM_PLUGIN_BASE_PORT_CAP_ES},
+ {"+MS", MM_PLUGIN_BASE_PORT_CAP_MS},
+ {"+FCLASS", MM_PLUGIN_BASE_PORT_CAP_FCLASS},
+ {NULL}
+};
+
+static guint32
+parse_gcap (const char *buf)
+{
+ struct modem_caps *cap = modem_caps;
+ guint32 ret = 0;
+
+ while (cap->name) {
+ if (strstr (buf, cap->name))
+ ret |= cap->bits;
+ cap++;
+ }
+ return ret;
+}
+
+static guint32
+parse_cgmm (const char *buf)
+{
+ if (strstr (buf, "GSM900") || strstr (buf, "GSM1800") ||
+ strstr (buf, "GSM1900") || strstr (buf, "GSM850"))
+ return MM_PLUGIN_BASE_PORT_CAP_GSM;
+ return 0;
+}
+
+static gboolean
+emit_probe_result (gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
+ MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+ MMPlugin *self = mm_plugin_base_supports_task_get_plugin (task);
+
+ /* Close the serial port */
+ g_object_unref (task_priv->probe_port);
+ task_priv->probe_port = NULL;
+
+ task_priv->probe_id = 0;
+ g_signal_emit (self, signals[PROBE_RESULT], 0, task, task_priv->probed_caps);
+ return FALSE;
+}
+
+static void
+probe_complete (MMPluginBaseSupportsTask *task)
+{
+ MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+
+ g_hash_table_insert (cached_caps,
+ g_strdup (mm_port_get_device (MM_PORT (task_priv->probe_port))),
+ GUINT_TO_POINTER (task_priv->probed_caps));
+
+ task_priv->probe_id = g_idle_add (emit_probe_result, task);
+}
+
+static void
+parse_response (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data);
+
+static void
+real_handle_probe_response (MMPluginBase *self,
+ MMPluginBaseSupportsTask *task,
+ const char *cmd,
+ const char *response,
+ const GError *error)
+{
+ MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+ MMSerialPort *port = task_priv->probe_port;
+
+ task_priv->probe_state++;
+
+ if (error) {
+ if (error->code == MM_SERIAL_RESPONSE_TIMEOUT) {
+ /* Try GCAP again */
+ if (task_priv->probe_state <= PROBE_STATE_GCAP_TRY3) {
+ mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, task);
+ return;
+ }
+
+ /* Otherwise, if all the GCAP tries timed out, ignore the port
+ * as it's probably not an AT-capable port.
+ */
+ probe_complete (task);
+ } else if (task_priv->probe_state <= PROBE_STATE_GCAP_TRY3) {
+ mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, task);
+ } else if (task_priv->probe_state == PROBE_STATE_ATI) {
+ /* Give ATI a try */
+ mm_serial_port_queue_command (port, "I", 3, parse_response, task);
+ } else if (task_priv->probe_state == PROBE_STATE_CGMM) {
+ /* If CGMM failed, probably not a modem port */
+ probe_complete (task);
+ }
+ return;
+ }
+
+ if (response) {
+ /* Parse the response */
+ task_priv->probed_caps = parse_gcap (response);
+
+ /* Some models (BUSlink SCWi275u) stick stupid stuff in the GMM response */
+ if ( (task_priv->probe_state == PROBE_STATE_CGMM)
+ && !(task_priv->probed_caps & CAP_GSM_OR_CDMA))
+ task_priv->probed_caps = parse_cgmm (response);
+
+ if (task_priv->probed_caps & CAP_GSM_OR_CDMA) {
+ probe_complete (task);
+ return;
+ }
+ }
+
+ /* Try a different command */
+ switch (task_priv->probe_state) {
+ case PROBE_STATE_GCAP_TRY1:
+ case PROBE_STATE_GCAP_TRY2:
+ case PROBE_STATE_GCAP_TRY3:
+ mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, task);
+ break;
+ case PROBE_STATE_ATI:
+ /* After the last GCAP attempt, try ATI */
+ mm_serial_port_queue_command (port, "I", 3, parse_response, task);
+ break;
+ case PROBE_STATE_CGMM:
+ /* After the ATI attempt, try CGMM */
+ mm_serial_port_queue_command (port, "+CGMM", 3, parse_response, task);
+ break;
+ default:
+ /* Probably not GSM or CDMA */
+ probe_complete (task);
+ break;
+ }
+}
+
+static gboolean
+handle_probe_response (gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
+ MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+ MMPluginBase *self = MM_PLUGIN_BASE (mm_plugin_base_supports_task_get_plugin (task));
+ const char *cmd = NULL;
+
+ switch (task_priv->probe_state) {
+ case PROBE_STATE_GCAP_TRY1:
+ case PROBE_STATE_GCAP_TRY2:
+ case PROBE_STATE_GCAP_TRY3:
+ cmd = "+GCAP";
+ break;
+ case PROBE_STATE_ATI:
+ cmd = "I";
+ break;
+ case PROBE_STATE_CGMM:
+ default:
+ cmd = "+CGMM";
+ break;
+ }
+
+ MM_PLUGIN_BASE_GET_CLASS (self)->handle_probe_response (self,
+ task,
+ cmd,
+ task_priv->probe_resp,
+ task_priv->probe_error);
+ return FALSE;
+}
+
+static void
+parse_response (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
+ MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+
+ if (task_priv->probe_id)
+ g_source_remove (task_priv->probe_id);
+ g_free (task_priv->probe_resp);
+ task_priv->probe_resp = NULL;
+ g_clear_error (&(task_priv->probe_error));
+
+ if (response && response->len)
+ task_priv->probe_resp = g_strdup (response->str);
+ if (error)
+ task_priv->probe_error = g_error_copy (error);
+
+ /* Schedule the response handler in an idle, since we can't emit the
+ * PROBE_RESULT signal from the serial port response handler without
+ * potentially destroying the serial port in the middle of its response
+ * handler, which it understandably doesn't like.
+ */
+ task_priv->probe_id = g_idle_add (handle_probe_response, task);
+}
- g_hash_table_foreach (priv->modems, find_modem, &info);
- if (info.key)
- g_hash_table_remove (priv->modems, info.key);
- g_free (info.key);
+static void
+flash_done (MMSerialPort *port, gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
+ MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+
+ task_priv->probe_id = 0;
+ mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, user_data);
}
gboolean
-mm_plugin_base_add_modem (MMPluginBase *self,
- MMModem *modem)
+mm_plugin_base_probe_port (MMPluginBase *self,
+ MMPluginBaseSupportsTask *task,
+ GError **error)
{
- MMPluginBasePrivate *priv;
- const char *device;
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+ MMSerialPort *serial;
+ const char *name;
+ GUdevDevice *port;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (MM_IS_PLUGIN_BASE (self), FALSE);
- g_return_val_if_fail (modem != NULL, FALSE);
- g_return_val_if_fail (MM_IS_MODEM (modem), FALSE);
-
- priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
-
- device = mm_modem_get_device (modem);
- if (g_hash_table_lookup (priv->modems, device))
+ g_return_val_if_fail (task != NULL, FALSE);
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+ name = g_udev_device_get_name (port);
+ g_assert (name);
+
+ serial = mm_serial_port_new (name, MM_PORT_TYPE_PRIMARY);
+ g_object_set (serial,
+ MM_SERIAL_PORT_SEND_DELAY, 100000,
+ MM_PORT_CARRIER_DETECT, FALSE,
+ NULL);
+
+ mm_serial_port_set_response_parser (serial,
+ mm_serial_parser_v1_parse,
+ mm_serial_parser_v1_new (),
+ mm_serial_parser_v1_destroy);
+
+ if (!mm_serial_port_open (serial, error)) {
+ g_object_unref (serial);
return FALSE;
+ }
- g_object_weak_ref (G_OBJECT (modem), modem_destroyed, self);
- g_hash_table_insert (priv->modems, g_strdup (device), modem);
+ g_debug ("(%s): probe requested by plugin '%s'", name, priv->name);
+ task_priv->probe_port = serial;
+ task_priv->probe_id = mm_serial_port_flash (serial, 100, flash_done, task);
return TRUE;
}
+gboolean
+mm_plugin_base_get_cached_port_capabilities (MMPluginBase *self,
+ GUdevDevice *port,
+ guint32 *capabilities)
+{
+ return g_hash_table_lookup_extended (cached_caps,
+ g_udev_device_get_name (port),
+ NULL,
+ (gpointer) capabilities);
+}
+
+/*****************************************************************************/
+
+static void
+modem_destroyed (gpointer data, GObject *modem)
+{
+ MMPluginBase *self = MM_PLUGIN_BASE (data);
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ GHashTableIter iter;
+ gpointer key, value;
+
+ /* Remove it from the modems info */
+ g_hash_table_iter_init (&iter, priv->modems);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ if (value == modem) {
+ g_hash_table_iter_remove (&iter);
+ break;
+ }
+ }
+
+ /* Since we don't track port cached capabilities on a per-modem basis,
+ * we just have to live with blowing away the cached capabilities whenever
+ * a modem gets removed. Could do better here by storing a structure
+ * in the cached capabilities table that includes { caps, modem device }
+ * or something and then only removing cached capabilities for ports
+ * that the modem that was just removed owned, but whatever.
+ */
+ g_hash_table_remove_all (cached_caps);
+}
+
MMModem *
mm_plugin_base_find_modem (MMPluginBase *self,
const char *master_device)
@@ -132,9 +595,8 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
guint16 *vendor,
guint16 *product)
{
- GUdevClient *client;
+ MMPluginBasePrivate *priv;
GUdevDevice *device = NULL;
- const char *tmp[] = { subsys, NULL };
const char *vid, *pid;
gboolean success = FALSE;
@@ -147,11 +609,9 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
if (product)
g_return_val_if_fail (*product == 0, FALSE);
- client = g_udev_client_new (tmp);
- if (!client)
- return FALSE;
+ priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
- device = g_udev_client_query_by_subsystem_and_name (client, subsys, name);
+ device = g_udev_client_query_by_subsystem_and_name (priv->client, subsys, name);
if (!device)
goto out;
@@ -180,18 +640,255 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
out:
if (device)
g_object_unref (device);
- g_object_unref (client);
return success;
}
+static char *
+get_key (const char *subsys, const char *name)
+{
+ return g_strdup_printf ("%s%s", subsys, name);
+}
+
+static const char *
+get_name (MMPlugin *plugin)
+{
+ return MM_PLUGIN_BASE_GET_PRIVATE (plugin)->name;
+}
+
+static char *
+get_driver_name (GUdevDevice *device)
+{
+ GUdevDevice *parent = NULL;
+ const char *driver;
+ char *ret;
+
+ driver = g_udev_device_get_driver (device);
+ if (!driver) {
+ parent = g_udev_device_get_parent (device);
+ if (parent)
+ driver = g_udev_device_get_driver (parent);
+ }
+
+ if (driver)
+ ret = g_strdup (driver);
+ if (parent)
+ g_object_unref (parent);
+
+ return ret;
+}
+
+static GUdevDevice *
+real_find_physical_device (MMPluginBase *plugin, GUdevDevice *child)
+{
+ GUdevDevice *iter, *old = NULL;
+ const char *bus, *type;
+
+ g_return_val_if_fail (child != NULL, NULL);
+
+ bus = g_udev_device_get_property (child, "ID_BUS");
+ if (!bus)
+ return NULL;
+
+ if (!strcmp (bus, "usb")) {
+ /* Walk the parents to find the 'usb_device' for this device. */
+ iter = g_object_ref (child);
+ while (iter) {
+ type = g_udev_device_get_devtype (iter);
+ if (type && !strcmp (type, "usb_device"))
+ return iter;
+
+ old = iter;
+ iter = g_udev_device_get_parent (old);
+ g_object_unref (old);
+ }
+ g_object_unref (child);
+ } else if (!strcmp (bus, "pci")) {
+ return g_udev_device_get_parent (child);
+ }
+
+ // FIXME: pci and pcmcia/cardbus? (like Sierra 850/860)
+ return NULL;
+}
+
+static MMPluginSupportsResult
+supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ MMSupportsPortResultFunc callback,
+ gpointer callback_data)
+{
+ MMPluginBase *self = MM_PLUGIN_BASE (plugin);
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ GUdevDevice *port = NULL, *physdev = NULL;
+ char *driver = NULL, *key = NULL;
+ MMPluginBaseSupportsTask *task;
+ MMPluginSupportsResult result = MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ MMModem *existing;
+ const char *master_path;
+
+ key = get_key (subsys, name);
+ task = g_hash_table_lookup (priv->tasks, key);
+ if (task) {
+ g_free (key);
+ g_return_val_if_fail (task == NULL, MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED);
+ }
+
+ port = g_udev_client_query_by_subsystem_and_name (priv->client, subsys, name);
+ if (!port)
+ goto out;
+
+ physdev = MM_PLUGIN_BASE_GET_CLASS (self)->find_physical_device (self, port);
+ if (!physdev)
+ goto out;
+
+ driver = get_driver_name (port);
+ if (!driver)
+ goto out;
+
+ task = supports_task_new (self, port, physdev, driver, callback, callback_data);
+ g_assert (task);
+ g_hash_table_insert (priv->tasks, g_strdup (key), g_object_ref (task));
+
+ /* Help the plugin out a bit by finding an existing modem for this port */
+ master_path = g_udev_device_get_sysfs_path (physdev);
+ existing = g_hash_table_lookup (priv->modems, master_path);
+
+ result = MM_PLUGIN_BASE_GET_CLASS (self)->supports_port (self, existing, task);
+ if (result != MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS) {
+ /* If the plugin doesn't support the port at all, the supports task is
+ * not needed.
+ */
+ g_hash_table_remove (priv->tasks, key);
+ }
+ g_object_unref (task);
+
+out:
+ if (physdev)
+ g_object_unref (physdev);
+ if (port)
+ g_object_unref (port);
+ g_free (key);
+ g_free (driver);
+ return result;
+}
+
+static void
+cancel_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name)
+{
+ MMPluginBase *self = MM_PLUGIN_BASE (plugin);
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ MMPluginBaseSupportsTask *task;
+ char *key;
+
+ key = get_key (subsys, name);
+ task = g_hash_table_lookup (priv->tasks, key);
+ if (task) {
+ /* Let the plugin cancel any ongoing tasks */
+ if (MM_PLUGIN_BASE_GET_CLASS (self)->cancel_task)
+ MM_PLUGIN_BASE_GET_CLASS (self)->cancel_task (self, task);
+ g_hash_table_remove (priv->tasks, key);
+ }
+
+ g_free (key);
+}
+
+static MMModem *
+grab_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ GError **error)
+{
+ MMPluginBase *self = MM_PLUGIN_BASE (plugin);
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ MMPluginBaseSupportsTask *task;
+ char *key;
+ MMModem *existing = NULL, *modem = NULL;
+ const char *master_path;
+
+ key = get_key (subsys, name);
+ task = g_hash_table_lookup (priv->tasks, key);
+ if (!task) {
+ g_free (key);
+ g_return_val_if_fail (task != NULL, FALSE);
+ }
+
+ /* Help the plugin out a bit by finding an existing modem for this port */
+ master_path = g_udev_device_get_sysfs_path (mm_plugin_base_supports_task_get_physdev (task));
+ existing = g_hash_table_lookup (priv->modems, master_path);
+
+ /* Let the modem grab the port */
+ modem = MM_PLUGIN_BASE_GET_CLASS (self)->grab_port (self, existing, task, error);
+ if (modem && !existing) {
+ g_hash_table_insert (priv->modems, g_strdup (master_path), modem);
+ g_object_weak_ref (G_OBJECT (modem), modem_destroyed, self);
+ }
+
+ g_hash_table_remove (priv->tasks, key);
+ g_free (key);
+ return modem;
+}
+
/*****************************************************************************/
static void
+plugin_init (MMPlugin *plugin_class)
+{
+ /* interface implementation */
+ plugin_class->get_name = get_name;
+ plugin_class->supports_port = supports_port;
+ plugin_class->cancel_supports_port = cancel_supports_port;
+ plugin_class->grab_port = grab_port;
+}
+
+static void
mm_plugin_base_init (MMPluginBase *self)
{
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ const char *subsys[] = { "tty", "net", NULL };
+
+ if (!cached_caps)
+ cached_caps = g_hash_table_new (g_str_hash, g_str_equal);
+
+ priv->client = g_udev_client_new (subsys);
priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ priv->tasks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) g_object_unref);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ /* Construct only */
+ priv->name = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ g_value_set_string (value, priv->name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
static void
@@ -199,7 +896,12 @@ finalize (GObject *object)
{
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (object);
+ g_free (priv->name);
+
+ g_object_unref (priv->client);
+
g_hash_table_destroy (priv->modems);
+ g_hash_table_destroy (priv->tasks);
G_OBJECT_CLASS (mm_plugin_base_parent_class)->finalize (object);
}
@@ -211,6 +913,28 @@ mm_plugin_base_class_init (MMPluginBaseClass *klass)
g_type_class_add_private (object_class, sizeof (MMPluginBasePrivate));
+ klass->find_physical_device = real_find_physical_device;
+ klass->handle_probe_response = real_handle_probe_response;
+
/* Virtual methods */
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
object_class->finalize = finalize;
+
+ g_object_class_install_property
+ (object_class, PROP_NAME,
+ g_param_spec_string (MM_PLUGIN_BASE_NAME,
+ "Name",
+ "Name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ signals[PROBE_RESULT] =
+ g_signal_new ("probe-result",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MMPluginBaseClass, probe_result),
+ NULL, NULL,
+ mm_marshal_VOID__OBJECT_UINT,
+ G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
}
diff --git a/src/mm-plugin-base.h b/src/mm-plugin-base.h
index 92e46d90..e426956d 100644
--- a/src/mm-plugin-base.h
+++ b/src/mm-plugin-base.h
@@ -20,7 +20,54 @@
#include <glib/gtypes.h>
#include <glib-object.h>
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-plugin.h"
#include "mm-modem.h"
+#include "mm-port.h"
+
+#define MM_PLUGIN_BASE_PORT_CAP_GSM 0x0001 /* GSM */
+#define MM_PLUGIN_BASE_PORT_CAP_IS707_A 0x0002 /* CDMA Circuit Switched Data */
+#define MM_PLUGIN_BASE_PORT_CAP_IS707_P 0x0004 /* CDMA Packet Switched Data */
+#define MM_PLUGIN_BASE_PORT_CAP_DS 0x0008 /* Data compression selection (v.42bis) */
+#define MM_PLUGIN_BASE_PORT_CAP_ES 0x0010 /* Error control selection (v.42) */
+#define MM_PLUGIN_BASE_PORT_CAP_FCLASS 0x0020 /* Group III Fax */
+#define MM_PLUGIN_BASE_PORT_CAP_MS 0x0040 /* Modulation selection */
+#define MM_PLUGIN_BASE_PORT_CAP_W 0x0080 /* Wireless commands */
+#define MM_PLUGIN_BASE_PORT_CAP_IS856 0x0100 /* CDMA 3G EVDO rev 0 */
+#define MM_PLUGIN_BASE_PORT_CAP_IS856_A 0x0200 /* CDMA 3G EVDO rev A */
+
+#define MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK (mm_plugin_base_supports_task_get_type ())
+#define MM_PLUGIN_BASE_SUPPORTS_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, MMPluginBaseSupportsTask))
+#define MM_PLUGIN_BASE_SUPPORTS_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, MMPluginBaseSupportsTaskClass))
+#define MM_IS_PLUGIN_BASE_SUPPORTS_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK))
+#define MM_IS_PLUBIN_BASE_SUPPORTS_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK))
+#define MM_PLUGIN_BASE_SUPPORTS_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, MMPluginBaseSupportsTaskClass))
+
+typedef struct {
+ GObject parent;
+} MMPluginBaseSupportsTask;
+
+typedef struct {
+ GObjectClass parent;
+} MMPluginBaseSupportsTaskClass;
+
+GType mm_plugin_base_supports_task_get_type (void);
+
+MMPlugin *mm_plugin_base_supports_task_get_plugin (MMPluginBaseSupportsTask *task);
+
+GUdevDevice *mm_plugin_base_supports_task_get_port (MMPluginBaseSupportsTask *task);
+
+GUdevDevice *mm_plugin_base_supports_task_get_physdev (MMPluginBaseSupportsTask *task);
+
+const char *mm_plugin_base_supports_task_get_driver (MMPluginBaseSupportsTask *task);
+
+guint32 mm_plugin_base_supports_task_get_probed_capabilities (MMPluginBaseSupportsTask *task);
+
+void mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task,
+ guint32 level);
+
#define MM_TYPE_PLUGIN_BASE (mm_plugin_base_get_type ())
#define MM_PLUGIN_BASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_BASE, MMPluginBase))
@@ -29,6 +76,8 @@
#define MM_IS_PLUBIN_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_BASE))
#define MM_PLUGIN_BASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_BASE, MMPluginBaseClass))
+#define MM_PLUGIN_BASE_NAME "name"
+
typedef struct _MMPluginBase MMPluginBase;
typedef struct _MMPluginBaseClass MMPluginBaseClass;
@@ -38,13 +87,38 @@ struct _MMPluginBase {
struct _MMPluginBaseClass {
GObjectClass parent;
+
+ /* Mandatory subclass functions */
+ MMPluginSupportsResult (*supports_port) (MMPluginBase *plugin,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task);
+
+ MMModem *(*grab_port) (MMPluginBase *plugin,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
+ GError **error);
+
+ /* Optional subclass functions */
+ void (*cancel_task) (MMPluginBase *plugin,
+ MMPluginBaseSupportsTask *task);
+
+ GUdevDevice * (*find_physical_device) (MMPluginBase *plugin,
+ GUdevDevice *port);
+
+ void (*handle_probe_response) (MMPluginBase *plugin,
+ MMPluginBaseSupportsTask *task,
+ const char *command,
+ const char *response,
+ const GError *error);
+
+ /* Signals */
+ void (*probe_result) (MMPluginBase *self,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities);
};
GType mm_plugin_base_get_type (void);
-gboolean mm_plugin_base_add_modem (MMPluginBase *self,
- MMModem *modem);
-
MMModem *mm_plugin_base_find_modem (MMPluginBase *self,
const char *master_device);
@@ -54,5 +128,14 @@ gboolean mm_plugin_base_get_device_ids (MMPluginBase *self,
guint16 *vendor,
guint16 *product);
+gboolean mm_plugin_base_probe_port (MMPluginBase *self,
+ MMPluginBaseSupportsTask *task,
+ GError **error);
+
+/* Returns TRUE if the port was previously probed, FALSE if not */
+gboolean mm_plugin_base_get_cached_port_capabilities (MMPluginBase *self,
+ GUdevDevice *port,
+ guint32 *capabilities);
+
#endif /* MM_PLUGIN_BASE_H */
diff --git a/src/mm-plugin.c b/src/mm-plugin.c
index c3425538..12df9dab 100644
--- a/src/mm-plugin.c
+++ b/src/mm-plugin.c
@@ -10,16 +10,31 @@ mm_plugin_get_name (MMPlugin *plugin)
return MM_PLUGIN_GET_INTERFACE (plugin)->get_name (plugin);
}
-guint32
+MMPluginSupportsResult
mm_plugin_supports_port (MMPlugin *plugin,
const char *subsys,
- const char *name)
+ const char *name,
+ MMSupportsPortResultFunc callback,
+ gpointer user_data)
{
g_return_val_if_fail (MM_IS_PLUGIN (plugin), FALSE);
g_return_val_if_fail (subsys != NULL, FALSE);
g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (callback != NULL, FALSE);
- return MM_PLUGIN_GET_INTERFACE (plugin)->supports_port (plugin, subsys, name);
+ return MM_PLUGIN_GET_INTERFACE (plugin)->supports_port (plugin, subsys, name, callback, user_data);
+}
+
+void
+mm_plugin_cancel_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name)
+{
+ g_return_if_fail (MM_IS_PLUGIN (plugin));
+ g_return_if_fail (subsys != NULL);
+ g_return_if_fail (name != NULL);
+
+ MM_PLUGIN_GET_INTERFACE (plugin)->cancel_supports_port (plugin, subsys, name);
}
MMModem *
diff --git a/src/mm-plugin.h b/src/mm-plugin.h
index 696cf668..3fa3a2cb 100644
--- a/src/mm-plugin.h
+++ b/src/mm-plugin.h
@@ -6,6 +6,8 @@
#include <glib-object.h>
#include <mm-modem.h>
+#define MM_PLUGIN_GENERIC_NAME "Generic"
+
#define MM_PLUGIN_MAJOR_VERSION 3
#define MM_PLUGIN_MINOR_VERSION 0
@@ -18,6 +20,23 @@ typedef struct _MMPlugin MMPlugin;
typedef MMPlugin *(*MMPluginCreateFunc) (void);
+/*
+ * 'level' is a value between 0 and 100 inclusive, where 0 means the plugin has
+ * no support for the port, and 100 means the plugin has full support for the
+ * port.
+ */
+typedef void (*MMSupportsPortResultFunc) (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ guint32 level,
+ gpointer user_data);
+
+typedef enum {
+ MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED = 0x0,
+ MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS,
+ MM_PLUGIN_SUPPORTS_PORT_DEFER
+} MMPluginSupportsResult;
+
struct _MMPlugin {
GTypeInterface g_iface;
@@ -25,14 +44,30 @@ struct _MMPlugin {
const char *(*get_name) (MMPlugin *self);
/* Check whether a plugin supports a particular modem port, and what level
- * of support the plugin has for the device. The plugin should return a
- * value between 0 and 100 inclusive, where 0 means the plugin has no
- * support for the device, and 100 means the plugin has full support for the
- * device.
+ * of support the plugin has for the device. If the plugin can immediately
+ * determine whether a port is unsupported, it should return
+ * FALSE. Otherwise, if the plugin needs to perform additional operations
+ * (ie, probing) to determine the level of support or additional details
+ * about a port, it should queue that operation (but *not* block on the
+ * result) and return TRUE to indicate the operation is ongoing. When the
+ * operation is finished or the level of support is known, the plugin should
+ * call the provided callback and pass that callback the provided user_data.
*/
- guint32 (*supports_port) (MMPlugin *self,
- const char *subsys,
- const char *name);
+ MMPluginSupportsResult (*supports_port) (MMPlugin *self,
+ const char *subsys,
+ const char *name,
+ MMSupportsPortResultFunc callback,
+ gpointer user_data);
+
+ /* Called to cancel an ongoing supports_port() operation or to notify the
+ * plugin to clean up that operation. For example, if two plugins support
+ * a particular port, but the first plugin grabs the port, this method will
+ * be called on the second plugin to allow that plugin to clean up resources
+ * used while determining it's level of support for the port.
+ */
+ void (*cancel_supports_port) (MMPlugin *self,
+ const char *subsys,
+ const char *name);
/* Will only be called if the plugin returns a value greater than 0 for
* the supports_port() method for this port. The plugin should create and
@@ -52,9 +87,15 @@ GType mm_plugin_get_type (void);
const char *mm_plugin_get_name (MMPlugin *plugin);
-guint32 mm_plugin_supports_port (MMPlugin *plugin,
- const char *subsys,
- const char *name);
+MMPluginSupportsResult mm_plugin_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ MMSupportsPortResultFunc callback,
+ gpointer user_data);
+
+void mm_plugin_cancel_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name);
MMModem *mm_plugin_grab_port (MMPlugin *plugin,
const char *subsys,
diff --git a/src/mm-serial-parsers.c b/src/mm-serial-parsers.c
index 8e6b75b8..ae0c20da 100644
--- a/src/mm-serial-parsers.c
+++ b/src/mm-serial-parsers.c
@@ -87,6 +87,9 @@ mm_serial_parser_v0_parse (gpointer data,
g_return_val_if_fail (parser != NULL, FALSE);
g_return_val_if_fail (response != NULL, FALSE);
+ if (G_UNLIKELY (!response->len || !strlen (response->str)))
+ return FALSE;
+
found = g_regex_match_full (parser->generic_response, response->str, response->len, 0, 0, &match_info, NULL);
if (found) {
str = g_match_info_fetch (match_info, 1);
@@ -205,7 +208,10 @@ mm_serial_parser_v1_parse (gpointer data,
g_return_val_if_fail (parser != NULL, FALSE);
g_return_val_if_fail (response != NULL, FALSE);
- /* First, check for successfule responses */
+ if (G_UNLIKELY (!response->len || !strlen (response->str)))
+ return FALSE;
+
+ /* First, check for successful responses */
found = g_regex_match_full (parser->regex_ok, response->str, response->len, 0, 0, NULL, NULL);
if (found)
diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c
index 564a8ace..99258f91 100644
--- a/src/mm-serial-port.c
+++ b/src/mm-serial-port.c
@@ -696,6 +696,7 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
}
priv->channel = g_io_channel_unix_new (priv->fd);
+ g_io_channel_set_encoding (priv->channel, NULL, NULL);
priv->watch_id = g_io_add_watch (priv->channel,
G_IO_IN | G_IO_ERR | G_IO_HUP,
data_available, self);