diff options
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); |