asynchronous and deferred port detection

Allow plugins to perform asynchronous port detection, and to defer port detection
until later.  This moves the prober bits into MMPluginBase so that all plugins
can take adavantage of it only when needed; the probing is not done at udev time.
Furthermore, plugins like Novatel can flip the secondary ports over the AT mode
through	deferred detection, by deferring the secondary ports until the main port
has been detected and AT$NWDMAT	has been sent.

This commit also finishes the port of the rest of the plugins (except mbm) over
to the new port detection methods and plugin API.
This commit is contained in:
Dan Williams
2009-06-28 14:05:05 -04:00
parent 112f2da19d
commit 6077763d90
47 changed files with 2972 additions and 2597 deletions

View File

@@ -20,7 +20,7 @@ clean:
rm -f $(GENERATED_FILES) rm -f $(GENERATED_FILES)
endif endif
SUBDIRS = marshallers callouts src plugins introspection test SUBDIRS = marshallers src plugins introspection test
dbusservicedir = $(DBUS_SYS_DIR) dbusservicedir = $(DBUS_SYS_DIR)
dbusservice_DATA = org.freedesktop.ModemManager.conf dbusservice_DATA = org.freedesktop.ModemManager.conf

View File

@@ -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"

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -1,2 +1,3 @@
VOID:UINT,STRING,STRING VOID:UINT,STRING,STRING
VOID:STRING,STRING,UINT VOID:STRING,STRING,UINT
VOID:OBJECT,UINT

View File

@@ -4,12 +4,12 @@ pkglib_LTLIBRARIES = \
libmm-plugin-gobi.la \ libmm-plugin-gobi.la \
libmm-plugin-huawei.la \ libmm-plugin-huawei.la \
libmm-plugin-hso.la \ libmm-plugin-hso.la \
libmm-plugin-mbm.la \
libmm-plugin-option.la \ libmm-plugin-option.la \
libmm-plugin-sierra.la \ libmm-plugin-sierra.la \
libmm-plugin-novatel.la \ libmm-plugin-novatel.la \
libmm-plugin-nokia.la \ libmm-plugin-nokia.la \
libmm-plugin-zte.la libmm-plugin-zte.la \
libmm-plugin-mbm.la
# Generic # Generic
@@ -120,74 +120,92 @@ libmm_plugin_mbm_la_LDFLAGS = -module -avoid-version
# Option # Option
libmm_plugin_option_la_SOURCES = \ libmm_plugin_option_la_SOURCES = \
mm-modem-option.c \
mm-modem-option.h \
mm-plugin-option.c \ 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 = \ libmm_plugin_option_la_CPPFLAGS = \
$(MM_CFLAGS) \ $(MM_CFLAGS) \
$(GUDEV_CFLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/src
libmm_plugin_option_la_LDFLAGS = -module -avoid-version libmm_plugin_option_la_LDFLAGS = \
$(GUDEV_LDFLAGS) \
-module \
-avoid-version
# Sierra # Sierra
libmm_plugin_sierra_la_SOURCES = \ libmm_plugin_sierra_la_SOURCES = \
mm-modem-sierra.c \
mm-modem-sierra.h \
mm-plugin-sierra.c \ 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 = \ libmm_plugin_sierra_la_CPPFLAGS = \
$(MM_CFLAGS) \ $(MM_CFLAGS) \
$(GUDEV_CFLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/src
libmm_plugin_sierra_la_LDFLAGS = -module -avoid-version libmm_plugin_sierra_la_LDFLAGS = \
$(GUDEV_LDFLAGS) \
-module \
-avoid-version
# Novatel # Novatel
libmm_plugin_novatel_la_SOURCES = \ 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.c \
mm-plugin-novatel.h mm-plugin-novatel.h \
mm-modem-novatel-gsm.c \
mm-modem-novatel-gsm.h
libmm_plugin_novatel_la_CPPFLAGS = \ libmm_plugin_novatel_la_CPPFLAGS = \
$(MM_CFLAGS) \ $(MM_CFLAGS) \
$(GUDEV_CFLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/src
libmm_plugin_novatel_la_LDFLAGS = -module -avoid-version libmm_plugin_novatel_la_LDFLAGS = \
$(GUDEV_LDFLAGS) \
-module \
-avoid-version
# Nokia # Nokia
libmm_plugin_nokia_la_SOURCES = \ libmm_plugin_nokia_la_SOURCES = \
mm-modem-nokia.c \
mm-modem-nokia.h \
mm-plugin-nokia.c \ 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 = \ libmm_plugin_nokia_la_CPPFLAGS = \
$(MM_CFLAGS) \ $(MM_CFLAGS) \
$(GUDEV_CFLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/src
libmm_plugin_nokia_la_LDFLAGS = -module -avoid-version libmm_plugin_nokia_la_LDFLAGS = \
$(GUDEV_LDFLAGS) \
-module \
-avoid-version
# Zte # Zte
libmm_plugin_zte_la_SOURCES = \ libmm_plugin_zte_la_SOURCES = \
mm-modem-zte.c \
mm-modem-zte.h \
mm-plugin-zte.c \ 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 = \ libmm_plugin_zte_la_CPPFLAGS = \
$(MM_CFLAGS) \ $(MM_CFLAGS) \
$(GUDEV_CFLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/src
libmm_plugin_zte_la_LDFLAGS = -module -avoid-version libmm_plugin_zte_la_LDFLAGS = \
$(GUDEV_LDFLAGS) \
-module \
-avoid-version
BUILT_SOURCES = \ BUILT_SOURCES = \

View File

@@ -564,6 +564,7 @@ static gboolean
grab_port (MMModem *modem, grab_port (MMModem *modem,
const char *subsys, const char *subsys,
const char *name, const char *name,
gpointer user_data,
GError **error) GError **error)
{ {
MMGenericGsm *gsm = MM_GENERIC_GSM (modem); MMGenericGsm *gsm = MM_GENERIC_GSM (modem);

View File

@@ -496,10 +496,12 @@ handle_status_change (MMSerialPort *port,
/*****************************************************************************/ /*****************************************************************************/
/* user_data != NULL means the port is a secondary port */
static gboolean static gboolean
grab_port (MMModem *modem, grab_port (MMModem *modem,
const char *subsys, const char *subsys,
const char *name, const char *name,
gpointer user_data,
GError **error) GError **error)
{ {
MMGenericGsm *gsm = MM_GENERIC_GSM (modem); MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
@@ -531,7 +533,7 @@ grab_port (MMModem *modem,
if (usbif == 0) { if (usbif == 0) {
if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY)) if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
ptype = 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)) if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
ptype = MM_PORT_TYPE_SECONDARY; ptype = MM_PORT_TYPE_SECONDARY;
} }
@@ -545,8 +547,6 @@ grab_port (MMModem *modem,
if (ptype == MM_PORT_TYPE_SECONDARY) { if (ptype == MM_PORT_TYPE_SECONDARY) {
GRegex *regex; 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); 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); regex = g_regex_new ("\\r\\n\\^RSSI:(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);

View File

@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <stdlib.h>
#include <stdio.h> #include <stdio.h>
@@ -10,28 +24,59 @@
static gpointer mm_modem_nokia_parent_class = NULL; static gpointer mm_modem_nokia_parent_class = NULL;
MMModem * MMModem *
mm_modem_nokia_new (const char *data_device, mm_modem_nokia_new (const char *device,
const char *driver) 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 (driver != NULL, NULL);
g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_NOKIA, 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_DRIVER, driver,
MM_MODEM_TYPE, MM_MODEM_TYPE_GSM, MM_MODEM_PLUGIN, plugin,
NULL)); 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 static void
mm_modem_nokia_init (MMModemNokia *self) 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 static void
@@ -58,7 +103,13 @@ mm_modem_nokia_get_type (void)
(GInstanceInitFunc) mm_modem_nokia_init, (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); 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; return modem_nokia_type;

View File

@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_MODEM_NOKIA_H
#define MM_MODEM_NOKIA_H #define MM_MODEM_NOKIA_H
@@ -22,7 +36,8 @@ typedef struct {
GType mm_modem_nokia_get_type (void); GType mm_modem_nokia_get_type (void);
MMModem *mm_modem_nokia_new (const char *data_device, MMModem *mm_modem_nokia_new (const char *data,
const char *driver); const char *driver,
const char *plugin);
#endif /* MM_MODEM_NOKIA_H */ #endif /* MM_MODEM_NOKIA_H */

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <stdlib.h>
#include <stdio.h> #include <stdio.h>
@@ -11,16 +25,18 @@
static gpointer mm_modem_novatel_gsm_parent_class = NULL; static gpointer mm_modem_novatel_gsm_parent_class = NULL;
MMModem * MMModem *
mm_modem_novatel_gsm_new (const char *data_device, mm_modem_novatel_gsm_new (const char *device,
const char *driver) 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 (driver != NULL, NULL);
g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_NOVATEL_GSM, 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_DRIVER, driver,
MM_MODEM_TYPE, MM_MODEM_TYPE_GSM, MM_MODEM_PLUGIN, plugin,
NULL)); NULL));
} }
@@ -29,7 +45,7 @@ mm_modem_novatel_gsm_new (const char *data_device,
/*****************************************************************************/ /*****************************************************************************/
static void static void
init_modem_done (MMSerial *serial, init_modem_done (MMSerialPort *port,
GString *response, GString *response,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
@@ -46,17 +62,21 @@ static void
pin_check_done (MMModem *modem, GError *error, gpointer user_data) pin_check_done (MMModem *modem, GError *error, gpointer user_data)
{ {
MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMSerialPort *primary;
if (error) { if (error) {
info->error = g_error_copy (error); info->error = g_error_copy (error);
mm_callback_info_schedule (info); mm_callback_info_schedule (info);
} else } else {
/* Finish the initialization */ /* 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 static void
pre_init_done (MMSerial *serial, pre_init_done (MMSerialPort *port,
GString *response, GString *response,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
@@ -74,25 +94,25 @@ pre_init_done (MMSerial *serial,
} }
static void 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 static void
disable_done (MMSerial *serial, disable_done (MMSerialPort *port,
GString *response, GString *response,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
{ {
mm_serial_close (serial); mm_serial_port_close (port);
mm_callback_info_schedule ((MMCallbackInfo *) user_data); mm_callback_info_schedule ((MMCallbackInfo *) user_data);
} }
static void 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 static void
@@ -102,32 +122,75 @@ enable (MMModem *modem,
gpointer user_data) gpointer user_data)
{ {
MMCallbackInfo *info; MMCallbackInfo *info;
MMSerialPort *primary;
/* First, reset the previously used CID */ /* First, reset the previously used CID */
mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
info = mm_callback_info_new (modem, callback, user_data); 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 (!do_enable) {
if (mm_serial_is_connected (MM_SERIAL (modem))) if (mm_serial_port_is_connected (primary))
mm_serial_flash (MM_SERIAL (modem), 1000, disable_flash_done, info); mm_serial_port_flash (primary, 1000, disable_flash_done, info);
else else
disable_flash_done (MM_SERIAL (modem), info); disable_flash_done (primary, info);
} else { } else {
if (mm_serial_open (MM_SERIAL (modem), &info->error)) if (mm_serial_port_open (primary, &info->error))
mm_serial_flash (MM_SERIAL (modem), 100, enable_flash_done, info); mm_serial_port_flash (primary, 100, enable_flash_done, info);
if (info->error) if (info->error)
mm_callback_info_schedule (info); 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 static void
modem_init (MMModem *modem_class) modem_init (MMModem *modem_class)
{ {
modem_class->enable = enable; modem_class->enable = enable;
modem_class->grab_port = grab_port;
} }
static void static void

View File

@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_MODEM_NOVATEL_GSM_H
#define 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); GType mm_modem_novatel_gsm_get_type (void);
MMModem *mm_modem_novatel_gsm_new (const char *data_device, MMModem *mm_modem_novatel_gsm_new (const char *device,
const char *driver); const char *driver,
const char *plugin_name);
#endif /* MM_MODEM_NOVATEL_GSM_H */ #endif /* MM_MODEM_NOVATEL_GSM_H */

View File

@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <stdlib.h>
#include <stdio.h> #include <stdio.h>
@@ -11,19 +25,23 @@
static gpointer mm_modem_option_parent_class = NULL; static gpointer mm_modem_option_parent_class = NULL;
MMModem * MMModem *
mm_modem_option_new (const char *data_device, mm_modem_option_new (const char *device,
const char *driver) 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 (driver != NULL, NULL);
g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_OPTION, 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_DRIVER, driver,
MM_MODEM_TYPE, MM_MODEM_TYPE_GSM, MM_MODEM_PLUGIN, plugin,
NULL)); NULL));
} }
/*****************************************************************************/
static void static void
pin_check_done (MMModem *modem, GError *error, gpointer user_data) pin_check_done (MMModem *modem, GError *error, gpointer user_data)
{ {
@@ -80,7 +98,7 @@ enable (MMModem *modem,
} }
static void static void
get_network_mode_done (MMSerial *serial, get_network_mode_done (MMSerialPort *port,
GString *response, GString *response,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
@@ -131,13 +149,16 @@ get_network_mode (MMModemGsmNetwork *modem,
gpointer user_data) gpointer user_data)
{ {
MMCallbackInfo *info; MMCallbackInfo *info;
MMSerialPort *primary;
info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); 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 static void
set_network_mode_done (MMSerial *serial, set_network_mode_done (MMSerialPort *port,
GString *response, GString *response,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
@@ -157,6 +178,7 @@ set_network_mode (MMModemGsmNetwork *modem,
gpointer user_data) gpointer user_data)
{ {
MMCallbackInfo *info; MMCallbackInfo *info;
MMSerialPort *primary;
char *command; char *command;
int i; int i;
@@ -188,7 +210,9 @@ set_network_mode (MMModemGsmNetwork *modem,
} }
command = g_strdup_printf ("AT_OPSYS=%d,2", i); 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); g_free (command);
} }

View File

@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_MODEM_OPTION_H
#define MM_MODEM_OPTION_H #define MM_MODEM_OPTION_H
@@ -22,7 +36,8 @@ typedef struct {
GType mm_modem_option_get_type (void); GType mm_modem_option_get_type (void);
MMModem *mm_modem_option_new (const char *data_device, MMModem *mm_modem_option_new (const char *device,
const char *driver); const char *driver,
const char *plugin_name);
#endif /* MM_MODEM_OPTION_H */ #endif /* MM_MODEM_OPTION_H */

View File

@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <stdlib.h>
#include <stdio.h> #include <stdio.h>
@@ -11,16 +25,18 @@
static gpointer mm_modem_sierra_parent_class = NULL; static gpointer mm_modem_sierra_parent_class = NULL;
MMModem * MMModem *
mm_modem_sierra_new (const char *data_device, mm_modem_sierra_new (const char *device,
const char *driver) 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 (driver != NULL, NULL);
g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_SIERRA, 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_DRIVER, driver,
MM_MODEM_TYPE, MM_MODEM_TYPE_GSM, MM_MODEM_PLUGIN, plugin,
NULL)); NULL));
} }
@@ -51,7 +67,7 @@ sierra_enabled (gpointer data)
} }
static void static void
init_done (MMSerial *serial, init_done (MMSerialPort *port,
GString *response, GString *response,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
@@ -68,15 +84,15 @@ init_done (MMSerial *serial,
} }
static void 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 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); mm_callback_info_schedule ((MMCallbackInfo *) user_data);
} }
@@ -87,6 +103,7 @@ enable (MMModem *modem,
gpointer user_data) gpointer user_data)
{ {
MMCallbackInfo *info; MMCallbackInfo *info;
MMSerialPort *primary;
/* First, reset the previously used CID */ /* First, reset the previously used CID */
mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); 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); info = mm_callback_info_new (modem, callback, user_data);
mm_callback_info_set_data (info, "sierra-enable", GINT_TO_POINTER (do_enable), NULL); 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 (!do_enable) {
if (mm_serial_is_connected (MM_SERIAL (modem))) if (mm_serial_port_is_connected (primary))
mm_serial_flash (MM_SERIAL (modem), 1000, disable_flash_done, info); mm_serial_port_flash (primary, 1000, disable_flash_done, info);
else else
disable_flash_done (MM_SERIAL (modem), info); disable_flash_done (primary, info);
} else { } else {
if (mm_serial_open (MM_SERIAL (modem), &info->error)) if (mm_serial_port_open (primary, &info->error))
mm_serial_flash (MM_SERIAL (modem), 100, enable_flash_done, info); mm_serial_port_flash (primary, 100, enable_flash_done, info);
if (info->error) if (info->error)
mm_callback_info_schedule (info); 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 static void
modem_init (MMModem *modem_class) modem_init (MMModem *modem_class)
{ {
modem_class->enable = enable; modem_class->enable = enable;
modem_class->grab_port = grab_port;
} }
static void static void

View File

@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_MODEM_SIERRA_H
#define MM_MODEM_SIERRA_H #define MM_MODEM_SIERRA_H
@@ -22,7 +36,8 @@ typedef struct {
GType mm_modem_sierra_get_type (void); GType mm_modem_sierra_get_type (void);
MMModem *mm_modem_sierra_new (const char *data_device, MMModem *mm_modem_sierra_new (const char *device,
const char *driver); const char *driver,
const char *plugin_name);
#endif /* MM_MODEM_SIERRA_H */ #endif /* MM_MODEM_SIERRA_H */

View File

@@ -1,26 +1,43 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "mm-modem-zte.h" #include "mm-modem-zte.h"
#include "mm-serial.h" #include "mm-serial-port.h"
#include "mm-errors.h" #include "mm-errors.h"
#include "mm-callback-info.h" #include "mm-callback-info.h"
static gpointer mm_modem_zte_parent_class = NULL; static gpointer mm_modem_zte_parent_class = NULL;
MMModem * MMModem *
mm_modem_zte_new (const char *data_device, mm_modem_zte_new (const char *device,
const char *driver) 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 (driver != NULL, NULL);
g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_ZTE, 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_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
NULL)); NULL));
} }
@@ -29,7 +46,7 @@ mm_modem_zte_new (const char *data_device,
/*****************************************************************************/ /*****************************************************************************/
static void static void
init_modem_done (MMSerial *serial, init_modem_done (MMSerialPort *port,
GString *response, GString *response,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
@@ -46,17 +63,21 @@ static void
pin_check_done (MMModem *modem, GError *error, gpointer user_data) pin_check_done (MMModem *modem, GError *error, gpointer user_data)
{ {
MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMSerialPort *primary;
if (error) { if (error) {
info->error = g_error_copy (error); info->error = g_error_copy (error);
mm_callback_info_schedule (info); mm_callback_info_schedule (info);
} else } else {
/* Finish the initialization */ /* 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 static void
pre_init_done (MMSerial *serial, pre_init_done (MMSerialPort *port,
GString *response, GString *response,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
@@ -74,25 +95,25 @@ pre_init_done (MMSerial *serial,
} }
static void 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 static void
disable_done (MMSerial *serial, disable_done (MMSerialPort *port,
GString *response, GString *response,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
{ {
mm_serial_close (serial); mm_serial_port_close (port);
mm_callback_info_schedule ((MMCallbackInfo *) user_data); mm_callback_info_schedule ((MMCallbackInfo *) user_data);
} }
static void 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 static void
@@ -102,57 +123,85 @@ enable (MMModem *modem,
gpointer user_data) gpointer user_data)
{ {
MMCallbackInfo *info; MMCallbackInfo *info;
MMSerialPort *primary;
/* First, reset the previously used CID */ /* First, reset the previously used CID */
mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
info = mm_callback_info_new (modem, callback, user_data); 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 (!do_enable) {
if (mm_serial_is_connected (MM_SERIAL (modem))) if (mm_serial_port_is_connected (primary))
mm_serial_flash (MM_SERIAL (modem), 1000, disable_flash_done, info); mm_serial_port_flash (primary, 1000, disable_flash_done, info);
else else
disable_flash_done (MM_SERIAL (modem), info); disable_flash_done (primary, info);
} else { } else {
if (mm_serial_open (MM_SERIAL (modem), &info->error)) if (mm_serial_port_open (primary, &info->error))
mm_serial_flash (MM_SERIAL (modem), 100, enable_flash_done, info); mm_serial_port_flash (primary, 100, enable_flash_done, info);
if (info->error) if (info->error)
mm_callback_info_schedule (info); 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 static void
modem_init (MMModem *modem_class) modem_init (MMModem *modem_class)
{ {
modem_class->enable = enable; modem_class->enable = enable;
modem_class->grab_port = grab_port;
} }
static void static void
mm_modem_zte_init (MMModemZte *self) 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 static void

View File

@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_MODEM_ZTE_H
#define MM_MODEM_ZTE_H #define MM_MODEM_ZTE_H
@@ -22,7 +36,8 @@ typedef struct {
GType mm_modem_zte_get_type (void); GType mm_modem_zte_get_type (void);
MMModem *mm_modem_zte_new (const char *data_device, MMModem *mm_modem_zte_new (const char *device,
const char *driver); const char *driver,
const char *plugin);
#endif /* MM_MODEM_ZTE_H */ #endif /* MM_MODEM_ZTE_H */

View File

@@ -25,291 +25,163 @@
#include <time.h> #include <time.h>
#include <gmodule.h> #include <gmodule.h>
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
#include <gudev/gudev.h>
#include "mm-plugin-generic.h" #include "mm-plugin-generic.h"
#include "mm-generic-gsm.h" #include "mm-generic-gsm.h"
#include "mm-generic-cdma.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 (MMPluginGeneric, mm_plugin_generic, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginGeneric, mm_plugin_generic, MM_TYPE_PLUGIN_BASE,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_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 * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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 * #define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
get_driver_name (GUdevDevice *device) MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
{ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
GUdevDevice *parent = NULL; MM_PLUGIN_BASE_PORT_CAP_IS856_A)
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)
{
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;
}
#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)
{
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;
}
static guint32 static guint32
supports_port (MMPlugin *plugin, get_level_for_capabilities (guint32 capabilities)
const char *subsys,
const char *name)
{ {
GUdevDevice *device, *physdev = NULL; if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
gboolean gsm = FALSE, cdma = FALSE; return 5;
guint32 level = 0; if (capabilities & CAP_CDMA)
return 5;
return 0;
}
g_return_val_if_fail (plugin != NULL, 0); static void
g_return_val_if_fail (MM_IS_PLUGIN (plugin), 0); probe_result (MMPluginBase *base,
g_return_val_if_fail (subsys != NULL, 0); MMPluginBaseSupportsTask *task,
g_return_val_if_fail (name != NULL, 0); guint32 capabilities,
gpointer user_data)
{
mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
static MMPluginSupportsResult
supports_port (MMPluginBase *base,
MMModem *existing,
MMPluginBaseSupportsTask *task)
{
GUdevDevice *port;
guint32 cached = 0, level;
/* Can't do anything with non-serial ports */ /* Can't do anything with non-serial ports */
if (strcmp (subsys, "tty")) port = mm_plugin_base_supports_task_get_port (task);
return 0; if (strcmp (g_udev_device_get_subsystem (port), "tty"))
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
device = get_device_type (plugin, subsys, name, &gsm, &cdma); if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
if (!device) level = get_level_for_capabilities (cached);
return 0; if (level) {
mm_plugin_base_supports_task_complete (task, level);
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
}
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
if (!gsm && !cdma) /* Otherwise kick off a probe */
goto out; if (mm_plugin_base_probe_port (base, task, NULL))
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
physdev = find_physical_device (device); return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
if (!physdev)
goto out;
g_object_unref (physdev);
level = 5;
out:
return level;
} }
static MMModem * static MMModem *
grab_port (MMPlugin *plugin, grab_port (MMPluginBase *base,
const char *subsys, MMModem *existing,
const char *name, MMPluginBaseSupportsTask *task,
GError **error) GError **error)
{ {
MMPluginGeneric *self = MM_PLUGIN_GENERIC (plugin); GUdevDevice *port = NULL, *physdev = NULL;
GUdevDevice *device = NULL, *physdev = NULL;
const char *devfile, *sysfs_path;
char *driver = NULL;
MMModem *modem = NULL; MMModem *modem = NULL;
gboolean gsm = FALSE, cdma = FALSE; const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
g_return_val_if_fail (subsys != NULL, NULL); port = mm_plugin_base_supports_task_get_port (task);
g_return_val_if_fail (name != NULL, NULL); g_assert (port);
/* Can't do anything with non-serial ports */ devfile = g_udev_device_get_device_file (port);
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) { if (!devfile) {
g_set_error (error, 0, 0, "Could not get port's sysfs file."); g_set_error (error, 0, 0, "Could not get port's sysfs file.");
goto out; return NULL;
}
driver = get_driver_name (device);
if (!driver) {
g_set_error (error, 0, 0, "Could not get port's driver name.");
goto out;
} }
physdev = mm_plugin_base_supports_task_get_physdev (task);
g_assert (physdev);
sysfs_path = g_udev_device_get_sysfs_path (physdev); sysfs_path = g_udev_device_get_sysfs_path (physdev);
if (!sysfs_path) { if (!sysfs_path) {
g_set_error (error, 0, 0, "Could not get port's physical device 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); subsys = g_udev_device_get_subsystem (port);
if (!modem) { name = g_udev_device_get_name (port);
if (gsm) {
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, modem = mm_generic_gsm_new (sysfs_path,
driver, mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (plugin)); mm_plugin_get_name (MM_PLUGIN (base)));
} else if (cdma) { } else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path, modem = mm_generic_cdma_new (sysfs_path,
driver, mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (plugin)); mm_plugin_get_name (MM_PLUGIN (base)));
} }
if (modem) { 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); g_object_unref (modem);
modem = NULL; return NULL;
} }
} }
if (modem)
mm_plugin_base_add_modem (MM_PLUGIN_BASE (self), modem);
} else { } else {
if (gsm || cdma) { if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
if (!mm_modem_grab_port (modem, subsys, name, error)) modem = existing;
modem = NULL; 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; 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 static void
mm_plugin_generic_init (MMPluginGeneric *self) mm_plugin_generic_init (MMPluginGeneric *self)
{ {
MMPluginGenericPrivate *priv = MM_PLUGIN_GENERIC_GET_PRIVATE (self); g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
const char *subsys[2] = { "tty", NULL };
priv->client = g_udev_client_new (subsys);
} }
static void static void
dispose (GObject *object) dispose (GObject *object)
{ {
MMPluginGenericPrivate *priv = MM_PLUGIN_GENERIC_GET_PRIVATE (object);
g_object_unref (priv->client);
} }
static void static void
mm_plugin_generic_class_init (MMPluginGenericClass *klass) mm_plugin_generic_class_init (MMPluginGenericClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMPluginGenericPrivate));
object_class->dispose = dispose; object_class->dispose = dispose;
pb_class->supports_port = supports_port;
pb_class->grab_port = grab_port;
} }

View File

@@ -23,287 +23,147 @@
#include "mm-modem-gobi-gsm.h" #include "mm-modem-gobi-gsm.h"
#include "mm-generic-cdma.h" #include "mm-generic-cdma.h"
static void plugin_init (MMPlugin *plugin_class); G_DEFINE_TYPE (MMPluginGobi, mm_plugin_gobi, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginGobi, mm_plugin_gobi, MM_TYPE_PLUGIN_BASE,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_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 * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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 * #define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
get_driver_name (GUdevDevice *device) MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
{ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
GUdevDevice *parent = NULL; MM_PLUGIN_BASE_PORT_CAP_IS856_A)
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);
return ret;
}
static GUdevDevice *
find_physical_device (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"))
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;
}
#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)
{
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;
}
static guint32 static guint32
supports_port (MMPlugin *plugin, get_level_for_capabilities (guint32 capabilities)
const char *subsys,
const char *name)
{ {
GUdevDevice *device, *physdev = NULL; if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
guint32 level = 0; return 10;
gboolean gsm = FALSE, cdma = FALSE; if (capabilities & CAP_CDMA)
char *driver = NULL; return 10;
return 0;
}
g_return_val_if_fail (plugin != NULL, 0); static void
g_return_val_if_fail (MM_IS_PLUGIN (plugin), 0); probe_result (MMPluginBase *base,
g_return_val_if_fail (subsys != NULL, 0); MMPluginBaseSupportsTask *task,
g_return_val_if_fail (name != NULL, 0); guint32 capabilities,
gpointer user_data)
{
mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
static MMPluginSupportsResult
supports_port (MMPluginBase *base,
MMModem *existing,
MMPluginBaseSupportsTask *task)
{
GUdevDevice *port;
guint32 cached = 0, level;
const char *driver;
/* Can't do anything with non-serial ports */ /* Can't do anything with non-serial ports */
if (strcmp (subsys, "tty")) port = mm_plugin_base_supports_task_get_port (task);
return 0; if (strcmp (g_udev_device_get_subsystem (port), "tty"))
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
device = get_device_type (plugin, subsys, name, &gsm, &cdma); driver = mm_plugin_base_supports_task_get_driver (task);
if (!device)
return 0;
if (!gsm && !cdma)
goto out;
driver = get_driver_name (device);
if (!driver || strcmp (driver, "qcserial")) if (!driver || strcmp (driver, "qcserial"))
goto out; return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
physdev = find_physical_device (device); if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
if (!physdev) level = get_level_for_capabilities (cached);
goto out; if (level) {
g_object_unref (physdev); mm_plugin_base_supports_task_complete (task, level);
level = 10; return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
}
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
out: /* Otherwise kick off a probe */
g_object_unref (device); if (mm_plugin_base_probe_port (base, task, NULL))
return level; return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
} }
static MMModem * static MMModem *
grab_port (MMPlugin *plugin, grab_port (MMPluginBase *base,
const char *subsys, MMModem *existing,
const char *name, MMPluginBaseSupportsTask *task,
GError **error) GError **error)
{ {
MMPluginGobi *self = MM_PLUGIN_GOBI (plugin); GUdevDevice *port = NULL, *physdev = NULL;
GUdevDevice *device = NULL, *physdev = NULL;
const char *devfile, *sysfs_path;
char *driver = NULL;
MMModem *modem = NULL; MMModem *modem = NULL;
gboolean gsm = FALSE, cdma = FALSE; const char *name, *subsys, *sysfs_path;
guint32 caps;
g_return_val_if_fail (subsys != NULL, NULL); port = mm_plugin_base_supports_task_get_port (task);
g_return_val_if_fail (name != NULL, NULL); g_assert (port);
/* 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;
}
physdev = mm_plugin_base_supports_task_get_physdev (task);
g_assert (physdev);
sysfs_path = g_udev_device_get_sysfs_path (physdev); sysfs_path = g_udev_device_get_sysfs_path (physdev);
if (!sysfs_path) { if (!sysfs_path) {
g_set_error (error, 0, 0, "Could not get port's physical device 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); subsys = g_udev_device_get_subsystem (port);
if (!modem) { name = g_udev_device_get_name (port);
if (gsm) {
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, modem = mm_modem_gobi_gsm_new (sysfs_path,
driver, mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (plugin)); mm_plugin_get_name (MM_PLUGIN (base)));
} else if (cdma) { } else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path, modem = mm_generic_cdma_new (sysfs_path,
driver, mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (plugin)); mm_plugin_get_name (MM_PLUGIN (base)));
} }
if (modem) { 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); g_object_unref (modem);
modem = NULL; return NULL;
} }
} }
if (modem)
mm_plugin_base_add_modem (MM_PLUGIN_BASE (self), modem);
} else { } else {
if (gsm || cdma) { if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
if (!mm_modem_grab_port (modem, subsys, name, error)) modem = existing;
modem = NULL; 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; 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 static void
mm_plugin_gobi_init (MMPluginGobi *self) mm_plugin_gobi_init (MMPluginGobi *self)
{ {
MMPluginGobiPrivate *priv = MM_PLUGIN_GOBI_GET_PRIVATE (self); g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
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);
} }
static void static void
mm_plugin_gobi_class_init (MMPluginGobiClass *klass) 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)); pb_class->supports_port = supports_port;
pb_class->grab_port = grab_port;
object_class->dispose = dispose;
} }

View File

@@ -23,165 +23,89 @@
#include "mm-plugin-hso.h" #include "mm-plugin-hso.h"
#include "mm-modem-hso.h" #include "mm-modem-hso.h"
static void plugin_init (MMPlugin *plugin_class); G_DEFINE_TYPE (MMPluginHso, mm_plugin_hso, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginHso, mm_plugin_hso, MM_TYPE_PLUGIN_BASE,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_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 * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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)
{
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)
{
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;
}
static GUdevDevice *
get_device (GUdevClient *client,
const char *subsys,
const char *name,
GUdevDevice **physdev,
char **driver,
GError **error)
{
GUdevDevice *device = NULL;
if (strcmp (subsys, "tty") && strcmp (subsys, "net")) {
g_set_error (error, 0, 0, "Unsupported subsystem.");
return NULL;
}
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 = 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;
}
*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;
}
out:
return device;
}
static guint32 static guint32
supports_port (MMPlugin *plugin, get_level_for_capabilities (guint32 capabilities)
const char *subsys,
const char *name)
{ {
MMPluginHsoPrivate *priv = MM_PLUGIN_HSO_GET_PRIVATE (plugin); if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
GUdevDevice *device, *physdev = NULL; return 10;
guint32 level = 0; return 0;
char *driver = NULL; }
g_return_val_if_fail (plugin != NULL, 0); static void
g_return_val_if_fail (MM_IS_PLUGIN (plugin), 0); probe_result (MMPluginBase *base,
g_return_val_if_fail (subsys != NULL, 0); MMPluginBaseSupportsTask *task,
g_return_val_if_fail (name != NULL, 0); guint32 capabilities,
gpointer user_data)
{
mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
device = get_device (priv->client, subsys, name, &physdev, &driver, NULL); static MMPluginSupportsResult
if (device) supports_port (MMPluginBase *base,
level = 10; MMModem *existing,
MMPluginBaseSupportsTask *task)
{
GUdevDevice *port;
guint32 cached = 0, level;
const char *driver;
g_free (driver); port = mm_plugin_base_supports_task_get_port (task);
if (physdev)
g_object_unref (physdev); driver = mm_plugin_base_supports_task_get_driver (task);
if (device) if (!driver || strcmp (driver, "hso"))
g_object_unref (device); return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
return level;
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;
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
} }
static MMModem * static MMModem *
grab_port (MMPlugin *plugin, grab_port (MMPluginBase *base,
const char *subsys, MMModem *existing,
const char *name, MMPluginBaseSupportsTask *task,
GError **error) GError **error)
{ {
MMPluginHso *self = MM_PLUGIN_HSO (plugin); GUdevDevice *port = NULL, *physdev = NULL;
MMPluginHsoPrivate *priv = MM_PLUGIN_HSO_GET_PRIVATE (plugin);
GUdevDevice *device = NULL, *physdev = NULL;
const char *sysfs_path = NULL;
char *driver = NULL, *devfile = NULL;
MMModem *modem = NULL; MMModem *modem = NULL;
const char *name, *subsys, *sysfs_path;
char *devfile;
guint32 caps;
g_return_val_if_fail (subsys != NULL, NULL); port = mm_plugin_base_supports_task_get_port (task);
g_return_val_if_fail (name != NULL, NULL); g_assert (port);
device = get_device (priv->client, subsys, name, &physdev, &driver, error); subsys = g_udev_device_get_subsystem (port);
if (!device) { name = g_udev_device_get_name (port);
g_set_error (error, 0, 0, "Could not get port's udev device.");
return NULL;
}
devfile = g_strdup (g_udev_device_get_device_file (device)); devfile = g_strdup (g_udev_device_get_device_file (port));
if (!devfile) { if (!devfile) {
if (!strcmp (subsys, "net")) { if (!strcmp (subsys, "net")) {
/* Apparently 'hso' doesn't set up the right links for the netdevice, /* 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); sysfs_path = g_udev_device_get_sysfs_path (physdev);
if (!sysfs_path) { if (!sysfs_path) {
g_set_error (error, 0, 0, "Could not get port's physical device sysfs path."); g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
goto out; goto out;
} }
modem = mm_plugin_base_find_modem (MM_PLUGIN_BASE (self), sysfs_path); caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
if (!modem) { if (!existing) {
modem = mm_modem_hso_new (sysfs_path, if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
driver, modem = mm_modem_hso_new (sysfs_path,
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)) {
g_object_unref (modem);
modem = NULL;
}
} }
if (modem) if (modem) {
mm_plugin_base_add_modem (MM_PLUGIN_BASE (self), modem); if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
g_object_unref (modem);
return NULL;
}
}
} else { } else {
if (!mm_modem_grab_port (modem, subsys, name, error)) if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = NULL; modem = existing;
if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
return NULL;
}
} }
out: out:
g_free (devfile); g_free (devfile);
g_free (driver);
g_object_unref (device);
g_object_unref (physdev);
return modem; 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 static void
mm_plugin_hso_init (MMPluginHso *self) mm_plugin_hso_init (MMPluginHso *self)
{ {
MMPluginHsoPrivate *priv = MM_PLUGIN_HSO_GET_PRIVATE (self); g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
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);
} }
static void static void
mm_plugin_hso_class_init (MMPluginHsoClass *klass) mm_plugin_hso_class_init (MMPluginHsoClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMPluginHsoPrivate)); pb_class->supports_port = supports_port;
pb_class->grab_port = grab_port;
object_class->dispose = dispose;
} }

View File

@@ -22,269 +22,316 @@
#include "mm-plugin-huawei.h" #include "mm-plugin-huawei.h"
#include "mm-generic-gsm.h" #include "mm-generic-gsm.h"
#include "mm-generic-cdma.h"
#include "mm-modem-huawei.h" #include "mm-modem-huawei.h"
#include "mm-serial-parsers.h"
static void plugin_init (MMPlugin *plugin_class); G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_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 * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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 * #define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
get_driver_name (GUdevDevice *device) MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
{ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
GUdevDevice *parent = NULL; MM_PLUGIN_BASE_PORT_CAP_IS856_A)
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)
{
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;
}
#define PROP_GSM "ID_MM_MODEM_GSM"
static GUdevDevice *
get_device (GUdevClient *client,
const char *subsys,
const char *name,
GUdevDevice **physdev)
{
GUdevDevice *device;
const char *tmp;
/* Can't do anything with non-serial ports */
if (strcmp (subsys, "tty"))
return NULL;
device = g_udev_client_query_by_subsystem_and_name (client, subsys, name);
if (!device)
return NULL;
tmp = g_udev_device_get_property (device, "ID_BUS");
if (!tmp || strcmp (tmp, "usb"))
goto error;
if (!g_udev_device_get_property_as_boolean (device, PROP_GSM))
goto error;
*physdev = find_physical_device (device);
if (*physdev)
return device;
error:
g_object_unref (device);
return NULL;
}
static guint32 static guint32
supports_port (MMPlugin *plugin, get_level_for_capabilities (guint32 capabilities)
const char *subsys,
const char *name)
{ {
MMPluginHuaweiPrivate *priv = MM_PLUGIN_HUAWEI_GET_PRIVATE (plugin); if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
GUdevDevice *device, *physdev = NULL; return 10;
guint32 level = 0; if (capabilities & CAP_CDMA)
return 10;
return 0;
}
static void
probe_result (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
guint32 capabilities,
gpointer user_data)
{
mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
#define TAG_SUPPORTS_INFO "huawei-supports-info"
typedef struct {
MMSerialPort *serial;
guint id;
gboolean secondary;
} HuaweiSupportsInfo;
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);
}
static gboolean
probe_secondary_supported (gpointer user_data)
{
MMPluginBaseSupportsTask *task = user_data;
HuaweiSupportsInfo *info;
info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
info->id = 0;
g_object_unref (info->serial);
info->serial = NULL;
/* Yay, supported, we got an unsolicited message */
info->secondary = TRUE;
mm_plugin_base_supports_task_complete (task, 10);
return FALSE;
}
static void
probe_secondary_handle_msg (MMSerialPort *port,
GMatchInfo *match_info,
gpointer user_data)
{
MMPluginBaseSupportsTask *task = user_data;
HuaweiSupportsInfo *info;
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);
}
static gboolean
probe_secondary_timeout (gpointer user_data)
{
MMPluginBaseSupportsTask *task = user_data;
HuaweiSupportsInfo *info;
info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
info->id = 0;
g_object_unref (info->serial);
info->serial = NULL;
/* Not supported by this plugin */
mm_plugin_base_supports_task_complete (task, 0);
return FALSE;
}
static void
add_regex (MMSerialPort *port, const char *match, gpointer user_data)
{
GRegex *regex;
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 MMPluginSupportsResult
supports_port (MMPluginBase *base,
MMModem *existing,
MMPluginBaseSupportsTask *task)
{
GUdevDevice *port;
guint32 cached = 0, level;
const char *subsys, *name;
int usbif;
guint16 vendor = 0, product = 0; guint16 vendor = 0, product = 0;
guint32 existing_type = MM_MODEM_TYPE_UNKNOWN;
device = get_device (priv->client, subsys, name, &physdev); /* Can't do anything with non-serial ports */
if (!device) port = mm_plugin_base_supports_task_get_port (task);
goto out; if (strcmp (g_udev_device_get_subsystem (port), "tty"))
g_object_unref (physdev); return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
if (!mm_plugin_base_get_device_ids (MM_PLUGIN_BASE (plugin), subsys, name, &vendor, &product)) subsys = g_udev_device_get_subsystem (port);
goto out; 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) if (vendor != 0x12d1)
goto out; return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
if (product == 0x1001 || product == 0x1003 || product == 0x1004) usbif = g_udev_device_get_property_as_int (port, "ID_USB_INTERFACE_NUM");
level = 10; if (usbif < 0)
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
out: /* The secondary ports don't necessarily respond correctly to probing, so
if (device) * we need to use the first port that does respond to probing to create the
g_object_unref (device); * right type of mode (GSM or CDMA), and then re-check the other interfaces.
return level; */
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;
}
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
}
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
} }
static MMModem * static MMModem *
grab_port (MMPlugin *plugin, grab_port (MMPluginBase *base,
const char *subsys, MMModem *existing,
const char *name, MMPluginBaseSupportsTask *task,
GError **error) GError **error)
{ {
MMPluginHuawei *self = MM_PLUGIN_HUAWEI (plugin); GUdevDevice *port = NULL, *physdev = NULL;
MMPluginHuaweiPrivate *priv = MM_PLUGIN_HUAWEI_GET_PRIVATE (plugin);
GUdevDevice *device = NULL, *physdev = NULL;
const char *devfile, *sysfs_path;
char *driver = NULL;
MMModem *modem = NULL; MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
guint16 product = 0; guint16 product = 0;
g_return_val_if_fail (subsys != NULL, NULL); port = mm_plugin_base_supports_task_get_port (task);
g_return_val_if_fail (name != NULL, NULL); g_assert (port);
device = get_device (priv->client, subsys, name, &physdev); devfile = g_udev_device_get_device_file (port);
if (!device)
goto out;
devfile = g_udev_device_get_device_file (device);
if (!devfile) { if (!devfile) {
g_set_error (error, 0, 0, "Could not get port's sysfs file."); g_set_error (error, 0, 0, "Could not get port's sysfs file.");
goto out; return NULL;
}
driver = get_driver_name (device);
if (!driver) {
g_set_error (error, 0, 0, "Could not get port's driver name.");
goto out;
} }
physdev = mm_plugin_base_supports_task_get_physdev (task);
g_assert (physdev);
sysfs_path = g_udev_device_get_sysfs_path (physdev); sysfs_path = g_udev_device_get_sysfs_path (physdev);
if (!sysfs_path) { if (!sysfs_path) {
g_set_error (error, 0, 0, "Could not get port's physical device 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."); 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); caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
if (!modem) { if (!existing) {
if (product == 0x1001) { if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
/* This modem is handled by generic GSM driver */ if (product == 0x1001) {
modem = mm_generic_gsm_new (sysfs_path, /* This modem is handled by generic GSM driver */
driver, modem = mm_generic_gsm_new (sysfs_path,
mm_plugin_get_name (plugin)); mm_plugin_base_supports_task_get_driver (task),
} else { mm_plugin_get_name (MM_PLUGIN (base)));
modem = mm_modem_huawei_new (sysfs_path, } else {
driver, modem = mm_modem_huawei_new (sysfs_path,
mm_plugin_get_name (plugin)); 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 (modem) {
if (!mm_modem_grab_port (modem, subsys, name, error)) { if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
g_message ("%s: couldn't grab port", __func__);
g_object_unref (modem); g_object_unref (modem);
modem = NULL; return NULL;
goto out;
} }
mm_plugin_base_add_modem (MM_PLUGIN_BASE (self), modem);
} }
} else { } else {
if (!mm_modem_grab_port (modem, subsys, name, error)) HuaweiSupportsInfo *info;
modem = NULL; 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; 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 static void
mm_plugin_huawei_init (MMPluginHuawei *self) mm_plugin_huawei_init (MMPluginHuawei *self)
{ {
MMPluginHuaweiPrivate *priv = MM_PLUGIN_HUAWEI_GET_PRIVATE (self); g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
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);
} }
static void static void
mm_plugin_huawei_class_init (MMPluginHuaweiClass *klass) mm_plugin_huawei_class_init (MMPluginHuaweiClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMPluginHuaweiPrivate)); pb_class->supports_port = supports_port;
pb_class->grab_port = grab_port;
object_class->dispose = dispose;
} }

View File

@@ -22,255 +22,144 @@
#include "mm-plugin-moto-c.h" #include "mm-plugin-moto-c.h"
#include "mm-modem-moto-c-gsm.h" #include "mm-modem-moto-c-gsm.h"
static void plugin_init (MMPlugin *plugin_class); G_DEFINE_TYPE (MMPluginMotoC, mm_plugin_moto_c, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginMotoC, mm_plugin_moto_c, MM_TYPE_PLUGIN_BASE,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_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 * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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)
{
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;
}
#define PROP_GSM "ID_MM_MODEM_GSM"
static guint32
supports_port (MMPlugin *plugin,
const char *subsys,
const char *name)
{
MMPluginMotoCPrivate *priv = MM_PLUGIN_MOTO_C_GET_PRIVATE (plugin);
GUdevDevice *device, *physdev = NULL;
guint32 level = 0;
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);
/* 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;
tmp = g_udev_device_get_property (device, "ID_BUS");
if (!tmp || strcmp (tmp, "usb"))
goto out;
tmp = g_udev_device_get_property (device, "ID_VENDOR_ID");
if (!tmp || strcmp (tmp, "22b8"))
goto out;
tmp = g_udev_device_get_property (device, "ID_MODEL_ID");
if (!tmp || strcmp (tmp, "3802"))
goto out;
if (!g_udev_device_get_property_as_boolean (device, PROP_GSM))
goto out;
physdev = find_physical_device (device);
if (!physdev)
goto out;
g_object_unref (physdev);
level = 10;
out:
g_object_unref (device);
return level;
}
static MMModem *
grab_port (MMPlugin *plugin,
const char *subsys,
const char *name,
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;
MMModem *modem = NULL;
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);
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;
}
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_moto_c_gsm_new (sysfs_path,
driver,
mm_plugin_get_name (plugin));
if (modem) {
if (!mm_modem_grab_port (modem, subsys, name, error)) {
g_object_unref (modem);
modem = 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;
}
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 static void
plugin_init (MMPlugin *plugin_class) probe_result (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
guint32 capabilities,
gpointer user_data)
{ {
/* interface implementation */ guint32 level = 0;
plugin_class->get_name = get_name;
plugin_class->supports_port = supports_port; if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
plugin_class->grab_port = grab_port; level = 10;
mm_plugin_base_supports_task_complete (task, level);
} }
static MMPluginSupportsResult
supports_port (MMPluginBase *base,
MMModem *existing,
MMPluginBaseSupportsTask *task)
{
GUdevDevice *port;
const char *tmp;
guint32 cached = 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;
tmp = g_udev_device_get_property (port, "ID_BUS");
if (!tmp || strcmp (tmp, "usb"))
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
tmp = g_udev_device_get_property (port, "ID_VENDOR_ID");
if (!tmp || strcmp (tmp, "22b8"))
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
tmp = g_udev_device_get_property (port, "ID_MODEL_ID");
if (!tmp || strcmp (tmp, "3802"))
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
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;
}
/* 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 *
grab_port (MMPluginBase *base,
MMModem *existing,
MMPluginBaseSupportsTask *task,
GError **error)
{
GUdevDevice *port = NULL, *physdev = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
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;
}
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;
}
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,
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, NULL, error)) {
g_object_unref (modem);
return NULL;
}
}
} else {
modem = existing;
if (!mm_modem_grab_port (modem, subsys, name, NULL, error))
return NULL;
}
return modem;
}
/*****************************************************************************/
static void static void
mm_plugin_moto_c_init (MMPluginMotoC *self) mm_plugin_moto_c_init (MMPluginMotoC *self)
{ {
MMPluginMotoCPrivate *priv = MM_PLUGIN_MOTO_C_GET_PRIVATE (self); g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
const char *subsys[2] = { "tty", NULL };
priv->client = g_udev_client_new (subsys);
} }
static void static void
dispose (GObject *object) dispose (GObject *object)
{ {
MMPluginMotoCPrivate *priv = MM_PLUGIN_MOTO_C_GET_PRIVATE (object);
g_object_unref (priv->client);
} }
static void static void
mm_plugin_moto_c_class_init (MMPluginMotoCClass *klass) mm_plugin_moto_c_class_init (MMPluginMotoCClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMPluginMotoCPrivate));
object_class->dispose = dispose; object_class->dispose = dispose;
pb_class->supports_port = supports_port;
pb_class->grab_port = grab_port;
} }

View File

@@ -1,14 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <string.h>
#include <gmodule.h> #include <gmodule.h>
#include "mm-plugin-nokia.h" #include "mm-plugin-nokia.h"
#include "mm-modem-nokia.h" #include "mm-modem-nokia.h"
#include "mm-generic-cdma.h"
static void plugin_init (MMPlugin *plugin_class); G_DEFINE_TYPE (MMPluginNokia, mm_plugin_nokia, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginNokia, mm_plugin_nokia, G_TYPE_OBJECT,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -16,133 +28,150 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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 * #define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
get_name (MMPlugin *plugin) 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 ** static void
list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx) probe_result (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
guint32 capabilities,
gpointer user_data)
{ {
char **supported = NULL; mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
char **devices; }
int num_devices;
int i;
devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL); static MMPluginSupportsResult
if (devices) { supports_port (MMPluginBase *base,
GPtrArray *array; MMModem *existing,
MMPluginBaseSupportsTask *task)
{
GUdevDevice *port;
guint32 cached = 0, level;
const char *subsys, *name;
guint16 vendor = 0;
array = g_ptr_array_new (); /* 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;
for (i = 0; i < num_devices; i++) { subsys = g_udev_device_get_subsystem (port);
char *udi = devices[i]; name = g_udev_device_get_name (port);
if (mm_plugin_supports_udi (plugin, hal_ctx, udi)) if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
g_ptr_array_add (array, g_strdup (udi)); 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;
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); /* Otherwise kick off a probe */
if (mm_plugin_base_probe_port (base, task, NULL))
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
return supported; return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static gboolean
supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
{
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);
}
}
}
g_strfreev (capabilities);
return supported;
}
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;
} }
static MMModem * 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; GUdevDevice *port = NULL, *physdev = NULL;
char *driver; MMModem *modem = NULL;
MMModem *modem; const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL); port = mm_plugin_base_supports_task_get_port (task);
g_return_val_if_fail (data_device != NULL, NULL); g_assert (port);
driver = get_driver_name (hal_ctx, udi); devfile = g_udev_device_get_device_file (port);
g_return_val_if_fail (driver != NULL, NULL); if (!devfile) {
g_set_error (error, 0, 0, "Could not get port's sysfs file.");
return NULL;
}
modem = MM_MODEM (mm_modem_nokia_new (data_device, driver)); 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;
}
libhal_free_string (data_device); subsys = g_udev_device_get_subsystem (port);
libhal_free_string (driver); 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)));
}
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; return modem;
} }
/*****************************************************************************/ /*****************************************************************************/
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 static void
mm_plugin_nokia_init (MMPluginNokia *self) mm_plugin_nokia_init (MMPluginNokia *self)
{ {
g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
} }
static void static void
mm_plugin_nokia_class_init (MMPluginNokiaClass *klass) 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;
} }

View File

@@ -1,10 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_PLUGIN_NOKIA_H
#define MM_PLUGIN_NOKIA_H #define MM_PLUGIN_NOKIA_H
#include "mm-plugin.h" #include "mm-plugin-base.h"
#include "mm-generic-gsm.h"
#define MM_TYPE_PLUGIN_NOKIA (mm_plugin_nokia_get_type ()) #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)) #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)) #define MM_PLUGIN_NOKIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_NOKIA, MMPluginNokiaClass))
typedef struct { typedef struct {
GObject parent; MMPluginBase parent;
} MMPluginNokia; } MMPluginNokia;
typedef struct { typedef struct {
GObjectClass parent; MMPluginBaseClass parent;
} MMPluginNokiaClass; } MMPluginNokiaClass;
GType mm_plugin_nokia_get_type (void); GType mm_plugin_nokia_get_type (void);

View File

@@ -1,15 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <string.h>
#include <gmodule.h> #include <gmodule.h>
#include "mm-plugin-novatel.h" #include "mm-plugin-novatel.h"
#include "mm-modem-novatel-cdma.h"
#include "mm-modem-novatel-gsm.h" #include "mm-modem-novatel-gsm.h"
#include "mm-generic-cdma.h"
static void plugin_init (MMPlugin *plugin_class); G_DEFINE_TYPE (MMPluginNovatel, mm_plugin_novatel, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginNovatel, mm_plugin_novatel, G_TYPE_OBJECT,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -17,158 +28,154 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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 * #define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
get_name (MMPlugin *plugin) 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 "Novatel"; if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
} return 10;
if (capabilities & CAP_CDMA)
static char ** return 10;
list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx) return 0;
{
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;
} }
static void static void
is_novatel_modem (LibHalContext *hal_ctx, probe_result (MMPluginBase *base,
const char *udi, MMPluginBaseSupportsTask *task,
gboolean *is_novatel_gsm, guint32 capabilities,
gboolean *is_novatel_cdma) gpointer user_data)
{ {
char **capabilities; mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
char **iter; }
*is_novatel_gsm = *is_novatel_cdma = FALSE; static MMPluginSupportsResult
supports_port (MMPluginBase *base,
MMModem *existing,
MMPluginBaseSupportsTask *task)
{
GUdevDevice *port;
guint32 cached = 0, level;
const char *subsys, *name, *driver;
guint16 vendor = 0;
capabilities = libhal_device_get_property_strlist (hal_ctx, udi, "modem.command_sets", NULL); /* Can't do anything with non-serial ports */
for (iter = capabilities; iter && *iter && !*is_novatel_gsm && !*is_novatel_cdma; iter++) { port = mm_plugin_base_supports_task_get_port (task);
char *parent_udi; if (strcmp (g_udev_device_get_subsystem (port), "tty"))
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
parent_udi = libhal_device_get_property_string (hal_ctx, udi, "info.parent", NULL); subsys = g_udev_device_get_subsystem (port);
if (parent_udi) { name = g_udev_device_get_name (port);
int vendor;
vendor = libhal_device_get_property_int (hal_ctx, parent_udi, "usb.vendor_id", NULL); if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
if (vendor == 0x1410) { return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
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); 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;
} }
g_strfreev (capabilities); /* Otherwise kick off a probe */
} if (mm_plugin_base_probe_port (base, task, NULL))
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
static gboolean return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
{
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);
}
return driver;
} }
static MMModem * 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; GUdevDevice *port = NULL, *physdev = NULL;
char *driver; MMModem *modem = NULL;
MMModem *modem; const char *name, *subsys, *devfile, *sysfs_path;
gboolean is_novatel_gsm = FALSE; guint32 caps;
gboolean is_novatel_cdma = FALSE;
is_novatel_modem (hal_ctx, udi, &is_novatel_gsm, &is_novatel_cdma); port = mm_plugin_base_supports_task_get_port (task);
g_return_val_if_fail (!is_novatel_gsm && !is_novatel_cdma, NULL); g_assert (port);
data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL); devfile = g_udev_device_get_device_file (port);
g_return_val_if_fail (data_device != NULL, NULL); if (!devfile) {
g_set_error (error, 0, 0, "Could not get port's sysfs file.");
return NULL;
}
driver = get_driver_name (hal_ctx, udi); physdev = mm_plugin_base_supports_task_get_physdev (task);
g_return_val_if_fail (driver != NULL, NULL); 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) subsys = g_udev_device_get_subsystem (port);
modem = MM_MODEM (mm_modem_novatel_gsm_new (data_device, driver)); name = g_udev_device_get_name (port);
else
modem = MM_MODEM (mm_modem_novatel_cdma_new (data_device, driver));
libhal_free_string (data_device); caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
libhal_free_string (driver); 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)));
}
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; return modem;
} }
/*****************************************************************************/ /*****************************************************************************/
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 static void
mm_plugin_novatel_init (MMPluginNovatel *self) mm_plugin_novatel_init (MMPluginNovatel *self)
{ {
g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
} }
static void static void
mm_plugin_novatel_class_init (MMPluginNovatelClass *klass) 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;
} }

View File

@@ -1,9 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_PLUGIN_NOVATEL_H
#define MM_PLUGIN_NOVATEL_H #define MM_PLUGIN_NOVATEL_H
#include "mm-plugin.h" #include "mm-plugin-base.h"
#include "mm-generic-gsm.h" #include "mm-generic-gsm.h"
#define MM_TYPE_PLUGIN_NOVATEL (mm_plugin_novatel_get_type ()) #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)) #define MM_PLUGIN_NOVATEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_NOVATEL, MMPluginNovatelClass))
typedef struct { typedef struct {
GObject parent; MMPluginBase parent;
} MMPluginNovatel; } MMPluginNovatel;
typedef struct { typedef struct {
GObjectClass parent; MMPluginBaseClass parent;
} MMPluginNovatelClass; } MMPluginNovatelClass;
GType mm_plugin_novatel_get_type (void); GType mm_plugin_novatel_get_type (void);

View File

@@ -1,14 +1,25 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <string.h>
#include <gmodule.h> #include <gmodule.h>
#include "mm-plugin-option.h" #include "mm-plugin-option.h"
#include "mm-modem-option.h" #include "mm-modem-option.h"
static void plugin_init (MMPlugin *plugin_class); G_DEFINE_TYPE (MMPluginOption, mm_plugin_option, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginOption, mm_plugin_option, G_TYPE_OBJECT,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -16,139 +27,143 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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 * static guint32
get_name (MMPlugin *plugin) get_level_for_capabilities (guint32 capabilities)
{ {
return "Option"; if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
return 10;
return 0;
} }
static char ** static void
list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx) probe_result (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
guint32 capabilities,
gpointer user_data)
{ {
char **supported = NULL; mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
char **devices; }
int num_devices;
int i;
devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL); static MMPluginSupportsResult
if (devices) { supports_port (MMPluginBase *base,
GPtrArray *array; MMModem *existing,
MMPluginBaseSupportsTask *task)
{
GUdevDevice *port;
guint32 cached = 0, level;
const char *driver, *subsys, *name;
guint16 vendor = 0;
array = g_ptr_array_new (); /* 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;
for (i = 0; i < num_devices; i++) { subsys = g_udev_device_get_subsystem (port);
char *udi = devices[i]; name = g_udev_device_get_name (port);
if (mm_plugin_supports_udi (plugin, hal_ctx, udi)) driver = mm_plugin_base_supports_task_get_driver (task);
g_ptr_array_add (array, g_strdup (udi)); 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;
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); /* Otherwise kick off a probe */
if (mm_plugin_base_probe_port (base, task, NULL))
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
return supported; return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static gboolean
supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
{
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);
}
}
}
g_strfreev (capabilities);
return supported;
}
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;
} }
static MMModem * 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; GUdevDevice *port = NULL, *physdev = NULL;
char *driver; MMModem *modem = NULL;
MMModem *modem; const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL); port = mm_plugin_base_supports_task_get_port (task);
g_return_val_if_fail (data_device != NULL, NULL); g_assert (port);
driver = get_driver_name (hal_ctx, udi); devfile = g_udev_device_get_device_file (port);
g_return_val_if_fail (driver != NULL, NULL); if (!devfile) {
g_set_error (error, 0, 0, "Could not get port's sysfs file.");
return NULL;
}
modem = MM_MODEM (mm_modem_option_new (data_device, driver)); 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;
}
libhal_free_string (data_device); subsys = g_udev_device_get_subsystem (port);
libhal_free_string (driver); 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_option_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, 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; return modem;
} }
/*****************************************************************************/ /*****************************************************************************/
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 static void
mm_plugin_option_init (MMPluginOption *self) mm_plugin_option_init (MMPluginOption *self)
{ {
g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
} }
static void static void
mm_plugin_option_class_init (MMPluginOptionClass *klass) 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;
} }

View File

@@ -1,9 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_PLUGIN_OPTION_H
#define MM_PLUGIN_OPTION_H #define MM_PLUGIN_OPTION_H
#include "mm-plugin.h" #include "mm-plugin-base.h"
#include "mm-generic-gsm.h" #include "mm-generic-gsm.h"
#define MM_TYPE_PLUGIN_OPTION (mm_plugin_option_get_type ()) #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)) #define MM_PLUGIN_OPTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_OPTION, MMPluginOptionClass))
typedef struct { typedef struct {
GObject parent; MMPluginBase parent;
} MMPluginOption; } MMPluginOption;
typedef struct { typedef struct {
GObjectClass parent; MMPluginBaseClass parent;
} MMPluginOptionClass; } MMPluginOptionClass;
GType mm_plugin_option_get_type (void); GType mm_plugin_option_get_type (void);

View File

@@ -1,14 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <string.h>
#include <gmodule.h> #include <gmodule.h>
#include "mm-plugin-sierra.h" #include "mm-plugin-sierra.h"
#include "mm-modem-sierra.h" #include "mm-modem-sierra.h"
#include "mm-generic-cdma.h"
static void plugin_init (MMPlugin *plugin_class); G_DEFINE_TYPE (MMPluginSierra, mm_plugin_sierra, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginSierra, mm_plugin_sierra, G_TYPE_OBJECT,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -16,141 +28,175 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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 * #define TAG_SIERRA_SECONDARY_PORT "sierra-secondary-port"
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 "Sierra"; if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
return 10;
if (capabilities & CAP_CDMA)
return 10;
return 0;
} }
static char ** static void
list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx) handle_probe_response (MMPluginBase *self,
MMPluginBaseSupportsTask *task,
const char *cmd,
const char *response,
const GError *error)
{ {
char **supported = NULL; if (error || !response || strcmp (cmd, "I")) {
char **devices; MM_PLUGIN_BASE_CLASS (mm_plugin_sierra_parent_class)->handle_probe_response (self, task, cmd, response, error);
int num_devices; return;
int i; }
devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL); if (strstr (response, "APP1") || strstr (response, "APP2") || strstr (response, "APP3")) {
if (devices) { g_object_set_data (G_OBJECT (task), TAG_SIERRA_SECONDARY_PORT, GUINT_TO_POINTER (TRUE));
GPtrArray *array; mm_plugin_base_supports_task_complete (task, 10);
return;
}
array = g_ptr_array_new (); /* 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);
}
for (i = 0; i < num_devices; i++) { static void
char *udi = devices[i]; probe_result (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
guint32 capabilities,
gpointer user_data)
{
mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
if (mm_plugin_supports_udi (plugin, hal_ctx, udi)) static MMPluginSupportsResult
g_ptr_array_add (array, g_strdup (udi)); supports_port (MMPluginBase *base,
MMModem *existing,
MMPluginBaseSupportsTask *task)
{
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;
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); /* Otherwise kick off a probe */
if (mm_plugin_base_probe_port (base, task, NULL))
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
return supported; return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static gboolean
supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
{
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;
}
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;
} }
static MMModem * 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; GUdevDevice *port = NULL, *physdev = NULL;
char *driver; MMModem *modem = NULL;
MMModem *modem; const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL); port = mm_plugin_base_supports_task_get_port (task);
g_return_val_if_fail (data_device != NULL, NULL); g_assert (port);
driver = get_driver_name (hal_ctx, udi); devfile = g_udev_device_get_device_file (port);
g_return_val_if_fail (driver != NULL, NULL); if (!devfile) {
g_set_error (error, 0, 0, "Could not get port's sysfs file.");
return NULL;
}
modem = MM_MODEM (mm_modem_sierra_new (data_device, driver)); 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;
}
libhal_free_string (data_device); subsys = g_udev_device_get_subsystem (port);
libhal_free_string (driver); 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)));
}
if (modem) {
if (!mm_modem_grab_port (modem, subsys, name, NULL, error)) {
g_object_unref (modem);
return NULL;
}
}
} else {
gpointer gsm_data = NULL;
/* 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; return modem;
} }
/*****************************************************************************/ /*****************************************************************************/
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 static void
mm_plugin_sierra_init (MMPluginSierra *self) mm_plugin_sierra_init (MMPluginSierra *self)
{ {
g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
} }
static void static void
mm_plugin_sierra_class_init (MMPluginSierraClass *klass) 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;
} }

View File

@@ -1,9 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_PLUGIN_SIERRA_H
#define MM_PLUGIN_SIERRA_H #define MM_PLUGIN_SIERRA_H
#include "mm-plugin.h" #include "mm-plugin-base.h"
#include "mm-generic-gsm.h" #include "mm-generic-gsm.h"
#define MM_TYPE_PLUGIN_SIERRA (mm_plugin_sierra_get_type ()) #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)) #define MM_PLUGIN_SIERRA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_SIERRA, MMPluginSierraClass))
typedef struct { typedef struct {
GObject parent; MMPluginBase parent;
} MMPluginSierra; } MMPluginSierra;
typedef struct { typedef struct {
GObjectClass parent; MMPluginBaseClass parent;
} MMPluginSierraClass; } MMPluginSierraClass;
GType mm_plugin_sierra_get_type (void); GType mm_plugin_sierra_get_type (void);

View File

@@ -1,14 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 <string.h>
#include <gmodule.h> #include <gmodule.h>
#include "mm-plugin-zte.h" #include "mm-plugin-zte.h"
#include "mm-modem-zte.h" #include "mm-modem-zte.h"
#include "mm-generic-cdma.h"
static void plugin_init (MMPlugin *plugin_class); G_DEFINE_TYPE (MMPluginZte, mm_plugin_zte, MM_TYPE_PLUGIN_BASE)
G_DEFINE_TYPE_EXTENDED (MMPluginZte, mm_plugin_zte, G_TYPE_OBJECT,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
@@ -16,133 +28,144 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin * G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void) 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 * #define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
get_name (MMPlugin *plugin) 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 ** static void
list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx) probe_result (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
guint32 capabilities,
gpointer user_data)
{ {
char **supported = NULL; mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
char **devices; }
int num_devices;
int i;
devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL); static MMPluginSupportsResult
if (devices) { supports_port (MMPluginBase *base,
GPtrArray *array; MMModem *existing,
MMPluginBaseSupportsTask *task)
{
GUdevDevice *port;
guint32 cached = 0, level;
guint16 vendor = 0;
const char *subsys, *name;
array = g_ptr_array_new (); /* 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;
for (i = 0; i < num_devices; i++) { subsys = g_udev_device_get_subsystem (port);
char *udi = devices[i]; name = g_udev_device_get_name (port);
if (mm_plugin_supports_udi (plugin, hal_ctx, udi)) if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
g_ptr_array_add (array, g_strdup (udi)); 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;
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); /* Otherwise kick off a probe */
if (mm_plugin_base_probe_port (base, task, NULL))
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
return supported; return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static gboolean
supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
{
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);
}
}
}
g_strfreev (capabilities);
return supported;
}
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;
} }
static MMModem * 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; GUdevDevice *port = NULL, *physdev = NULL;
char *driver; MMModem *modem = NULL;
MMModem *modem; const char *name, *subsys, *sysfs_path;
guint32 caps;
data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL); port = mm_plugin_base_supports_task_get_port (task);
g_return_val_if_fail (data_device != NULL, NULL); g_assert (port);
driver = get_driver_name (hal_ctx, udi); physdev = mm_plugin_base_supports_task_get_physdev (task);
g_return_val_if_fail (driver != NULL, NULL); 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);
libhal_free_string (data_device); caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
libhal_free_string (driver); 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)));
}
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; return modem;
} }
/*****************************************************************************/ /*****************************************************************************/
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 static void
mm_plugin_zte_init (MMPluginZte *self) mm_plugin_zte_init (MMPluginZte *self)
{ {
g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
} }
static void static void
mm_plugin_zte_class_init (MMPluginZteClass *klass) 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;
} }

View File

@@ -1,9 +1,23 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- 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 #ifndef MM_PLUGIN_ZTE_H
#define 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_TYPE_PLUGIN_ZTE (mm_plugin_zte_get_type ())
#define MM_PLUGIN_ZTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_ZTE, MMPluginZte)) #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)) #define MM_PLUGIN_ZTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_ZTE, MMPluginZteClass))
typedef struct { typedef struct {
GObject parent; MMPluginBase parent;
} MMPluginZte; } MMPluginZte;
typedef struct { typedef struct {
GObjectClass parent; MMPluginBaseClass parent;
} MMPluginZteClass; } MMPluginZteClass;
GType mm_plugin_zte_get_type (void); GType mm_plugin_zte_get_type (void);

View File

@@ -85,6 +85,7 @@ static gboolean
grab_port (MMModem *modem, grab_port (MMModem *modem,
const char *subsys, const char *subsys,
const char *name, const char *name,
gpointer user_data,
GError **error) GError **error)
{ {
MMGenericCdma *self = MM_GENERIC_CDMA (modem); MMGenericCdma *self = MM_GENERIC_CDMA (modem);

View File

@@ -252,6 +252,7 @@ static gboolean
grab_port (MMModem *modem, grab_port (MMModem *modem,
const char *subsys, const char *subsys,
const char *name, const char *name,
gpointer user_data,
GError **error) GError **error)
{ {
MMGenericGsm *self = MM_GENERIC_GSM (modem); MMGenericGsm *self = MM_GENERIC_GSM (modem);

View File

@@ -36,6 +36,8 @@ typedef struct {
GUdevClient *udev; GUdevClient *udev;
GSList *plugins; GSList *plugins;
GHashTable *modems; GHashTable *modems;
GHashTable *supports;
} MMManagerPrivate; } MMManagerPrivate;
static MMPlugin * static MMPlugin *
@@ -99,6 +101,7 @@ load_plugins (MMManager *manager)
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GDir *dir; GDir *dir;
const char *fname; const char *fname;
MMPlugin *generic_plugin = NULL;
if (!g_module_supported ()) { if (!g_module_supported ()) {
g_warning ("GModules are not supported on your platform!"); g_warning ("GModules are not supported on your platform!");
@@ -122,10 +125,18 @@ load_plugins (MMManager *manager)
plugin = load_plugin (path); plugin = load_plugin (path);
g_free (path); g_free (path);
if (plugin) if (plugin) {
priv->plugins = g_slist_append (priv->plugins, 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); g_dir_close (dir);
} }
@@ -179,7 +190,7 @@ modem_valid (MMModem *modem, GParamSpec *pspec, gpointer user_data)
device = mm_modem_get_device (modem); device = mm_modem_get_device (modem);
g_assert (device); g_assert (device);
g_debug ("Exported modem %s", device); g_debug ("Exported modem %s as %s", device, path);
g_free (device); g_free (device);
g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem); g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem);
@@ -236,107 +247,281 @@ impl_manager_enumerate_devices (MMManager *manager,
return TRUE; return TRUE;
} }
typedef struct {
MMModem *modem;
const char *subsys;
const char *name;
} FindPortInfo;
static void
find_port (gpointer key, gpointer data, gpointer user_data)
{
FindPortInfo *info = user_data;
MMModem *modem = MM_MODEM (data);
if (!info->modem && mm_modem_owns_port (modem, info->subsys, info->name))
info->modem = modem;
}
static MMModem * static MMModem *
find_modem_for_port (MMManager *manager, const char *subsys, const char *name) find_modem_for_port (MMManager *manager, const char *subsys, const char *name)
{ {
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
FindPortInfo info = { NULL, subsys, name }; GHashTableIter iter;
gpointer key, value;
g_hash_table_foreach (priv->modems, find_port, &info); g_hash_table_iter_init (&iter, priv->modems);
return info.modem; 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 {
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
supports_info_free (SupportsInfo *info)
{
/* 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);
}
static char *
get_key (const char *subsys, const char *name)
{
return g_strdup_printf ("%s%s", subsys, 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)
{
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;
}
/* 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 static void
device_added (MMManager *manager, GUdevDevice *device) device_added (MMManager *manager, GUdevDevice *device)
{ {
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GSList *iter;
MMModem *modem = NULL;
const char *subsys, *name; const char *subsys, *name;
MMPlugin *best_plugin = NULL; SupportsInfo *info;
guint32 best_level = 0; char *key;
GError *error = NULL; gboolean found;
g_return_if_fail (device != NULL); g_return_if_fail (device != NULL);
if (!g_slist_length (priv->plugins))
return;
subsys = g_udev_device_get_subsystem (device); subsys = g_udev_device_get_subsystem (device);
name = g_udev_device_get_name (device); name = g_udev_device_get_name (device);
if (find_modem_for_port (manager, subsys, name)) if (find_modem_for_port (manager, subsys, name))
return; return;
/* Build up the list of plugins that support this port */ key = get_key (subsys, name);
for (iter = priv->plugins; iter; iter = iter->next) { found = !!g_hash_table_lookup (priv->supports, key);
MMPlugin *plugin = MM_PLUGIN (iter->data); if (found) {
guint32 level; g_free (key);
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)");
return; 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 static void
device_removed (MMManager *manager, GUdevDevice *device) device_removed (MMManager *manager, GUdevDevice *device)
{ {
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
MMModem *modem; MMModem *modem;
const char *subsys, *name; const char *subsys, *name;
char *key;
SupportsInfo *info;
g_return_if_fail (device != NULL); g_return_if_fail (device != NULL);
if (!g_slist_length (priv->plugins))
return;
subsys = g_udev_device_get_subsystem (device); subsys = g_udev_device_get_subsystem (device);
name = g_udev_device_get_name (device); name = g_udev_device_get_name (device);
modem = find_modem_for_port (manager, subsys, name); modem = find_modem_for_port (manager, subsys, name);
if (modem) if (modem) {
mm_modem_release_port (modem, subsys, name); 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 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); priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
load_plugins (manager); 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); priv->udev = g_udev_client_new (subsys);
g_assert (priv->udev); g_assert (priv->udev);
g_signal_connect (priv->udev, "uevent", G_CALLBACK (handle_uevent), manager); 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); MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (object);
g_hash_table_destroy (priv->supports);
g_hash_table_destroy (priv->modems); g_hash_table_destroy (priv->modems);
g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL); 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_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); dbus_g_error_domain_register (MM_MOBILE_ERROR, "org.freedesktop.ModemManager.Modem.Gsm", MM_TYPE_MOBILE_ERROR);
} }

View File

@@ -56,7 +56,7 @@ mm_modem_base_get_port (MMModemBase *self,
key = get_hash_key (subsys, name); key = get_hash_key (subsys, name);
port = g_hash_table_lookup (MM_MODEM_BASE_GET_PRIVATE (self)->ports, key); port = g_hash_table_lookup (MM_MODEM_BASE_GET_PRIVATE (self)->ports, key);
g_free (key); g_free (key);
return NULL; return port;
} }
static void static void

View File

@@ -300,6 +300,7 @@ gboolean
mm_modem_grab_port (MMModem *self, mm_modem_grab_port (MMModem *self,
const char *subsys, const char *subsys,
const char *name, const char *name,
gpointer user_data,
GError **error) GError **error)
{ {
g_return_val_if_fail (self != NULL, FALSE); 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_return_val_if_fail (name, FALSE);
g_assert (MM_MODEM_GET_INTERFACE (self)->grab_port); 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 void

View File

@@ -78,6 +78,7 @@ struct _MMModem {
gboolean (*grab_port) (MMModem *self, gboolean (*grab_port) (MMModem *self,
const char *subsys, const char *subsys,
const char *name, const char *name,
gpointer user_data,
GError **error); GError **error);
void (*release_port) (MMModem *self, void (*release_port) (MMModem *self,
@@ -116,6 +117,7 @@ gboolean mm_modem_owns_port (MMModem *self,
gboolean mm_modem_grab_port (MMModem *self, gboolean mm_modem_grab_port (MMModem *self,
const char *subsys, const char *subsys,
const char *name, const char *name,
gpointer user_data,
GError **error); GError **error);
void mm_modem_release_port (MMModem *self, void mm_modem_release_port (MMModem *self,

View File

@@ -23,64 +23,527 @@
#include <gudev/gudev.h> #include <gudev/gudev.h>
#include "mm-plugin-base.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)) #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 { typedef struct {
char *name;
GUdevClient *client;
GHashTable *modems; GHashTable *modems;
GHashTable *tasks;
} MMPluginBasePrivate; } 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 { typedef struct {
char *key; MMPluginBase *plugin;
gpointer modem; GUdevDevice *port;
} FindInfo; 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 static void
find_modem (gpointer key, gpointer data, gpointer user_data) mm_plugin_base_supports_task_init (MMPluginBaseSupportsTask *self)
{ {
FindInfo *info = user_data;
if (!info->key && data == info->modem)
info->key = g_strdup ((const char *) key);
} }
static void
dispose (GObject *object)
{
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 (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
mm_plugin_base_supports_task_class_init (MMPluginBaseSupportsTaskClass *klass)
{
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);
}
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_probe_port (MMPluginBase *self,
MMPluginBaseSupportsTask *task,
GError **error)
{
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 (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_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 static void
modem_destroyed (gpointer data, GObject *modem) modem_destroyed (gpointer data, GObject *modem)
{ {
MMPluginBase *self = MM_PLUGIN_BASE (data); MMPluginBase *self = MM_PLUGIN_BASE (data);
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self); MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
FindInfo info = { NULL, modem }; GHashTableIter iter;
gpointer key, value;
g_hash_table_foreach (priv->modems, find_modem, &info); /* Remove it from the modems info */
if (info.key) g_hash_table_iter_init (&iter, priv->modems);
g_hash_table_remove (priv->modems, info.key); while (g_hash_table_iter_next (&iter, &key, &value)) {
g_free (info.key); if (value == modem) {
} g_hash_table_iter_remove (&iter);
break;
}
}
gboolean /* Since we don't track port cached capabilities on a per-modem basis,
mm_plugin_base_add_modem (MMPluginBase *self, * we just have to live with blowing away the cached capabilities whenever
MMModem *modem) * a modem gets removed. Could do better here by storing a structure
{ * in the cached capabilities table that includes { caps, modem device }
MMPluginBasePrivate *priv; * or something and then only removing cached capabilities for ports
const char *device; * that the modem that was just removed owned, but whatever.
*/
g_return_val_if_fail (self != NULL, FALSE); g_hash_table_remove_all (cached_caps);
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))
return FALSE;
g_object_weak_ref (G_OBJECT (modem), modem_destroyed, self);
g_hash_table_insert (priv->modems, g_strdup (device), modem);
return TRUE;
} }
MMModem * MMModem *
@@ -132,9 +595,8 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
guint16 *vendor, guint16 *vendor,
guint16 *product) guint16 *product)
{ {
GUdevClient *client; MMPluginBasePrivate *priv;
GUdevDevice *device = NULL; GUdevDevice *device = NULL;
const char *tmp[] = { subsys, NULL };
const char *vid, *pid; const char *vid, *pid;
gboolean success = FALSE; gboolean success = FALSE;
@@ -147,11 +609,9 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
if (product) if (product)
g_return_val_if_fail (*product == 0, FALSE); g_return_val_if_fail (*product == 0, FALSE);
client = g_udev_client_new (tmp); priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
if (!client)
return FALSE;
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) if (!device)
goto out; goto out;
@@ -180,18 +640,255 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
out: out:
if (device) if (device)
g_object_unref (device); g_object_unref (device);
g_object_unref (client);
return success; 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 static void
mm_plugin_base_init (MMPluginBase *self) mm_plugin_base_init (MMPluginBase *self)
{ {
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (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->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 static void
@@ -199,7 +896,12 @@ finalize (GObject *object)
{ {
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (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->modems);
g_hash_table_destroy (priv->tasks);
G_OBJECT_CLASS (mm_plugin_base_parent_class)->finalize (object); 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)); 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 */ /* Virtual methods */
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->finalize = finalize; 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);
} }

View File

@@ -20,7 +20,54 @@
#include <glib/gtypes.h> #include <glib/gtypes.h>
#include <glib-object.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-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_TYPE_PLUGIN_BASE (mm_plugin_base_get_type ())
#define MM_PLUGIN_BASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_BASE, MMPluginBase)) #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_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_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 _MMPluginBase MMPluginBase;
typedef struct _MMPluginBaseClass MMPluginBaseClass; typedef struct _MMPluginBaseClass MMPluginBaseClass;
@@ -38,13 +87,38 @@ struct _MMPluginBase {
struct _MMPluginBaseClass { struct _MMPluginBaseClass {
GObjectClass parent; 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); 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, MMModem *mm_plugin_base_find_modem (MMPluginBase *self,
const char *master_device); const char *master_device);
@@ -54,5 +128,14 @@ gboolean mm_plugin_base_get_device_ids (MMPluginBase *self,
guint16 *vendor, guint16 *vendor,
guint16 *product); 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 */ #endif /* MM_PLUGIN_BASE_H */

View File

@@ -10,16 +10,31 @@ mm_plugin_get_name (MMPlugin *plugin)
return MM_PLUGIN_GET_INTERFACE (plugin)->get_name (plugin); return MM_PLUGIN_GET_INTERFACE (plugin)->get_name (plugin);
} }
guint32 MMPluginSupportsResult
mm_plugin_supports_port (MMPlugin *plugin, mm_plugin_supports_port (MMPlugin *plugin,
const char *subsys, 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 (MM_IS_PLUGIN (plugin), FALSE);
g_return_val_if_fail (subsys != NULL, FALSE); g_return_val_if_fail (subsys != NULL, FALSE);
g_return_val_if_fail (name != 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 * MMModem *

View File

@@ -6,6 +6,8 @@
#include <glib-object.h> #include <glib-object.h>
#include <mm-modem.h> #include <mm-modem.h>
#define MM_PLUGIN_GENERIC_NAME "Generic"
#define MM_PLUGIN_MAJOR_VERSION 3 #define MM_PLUGIN_MAJOR_VERSION 3
#define MM_PLUGIN_MINOR_VERSION 0 #define MM_PLUGIN_MINOR_VERSION 0
@@ -18,6 +20,23 @@ typedef struct _MMPlugin MMPlugin;
typedef MMPlugin *(*MMPluginCreateFunc) (void); 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 { struct _MMPlugin {
GTypeInterface g_iface; GTypeInterface g_iface;
@@ -25,14 +44,30 @@ struct _MMPlugin {
const char *(*get_name) (MMPlugin *self); const char *(*get_name) (MMPlugin *self);
/* Check whether a plugin supports a particular modem port, and what level /* 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 * of support the plugin has for the device. If the plugin can immediately
* value between 0 and 100 inclusive, where 0 means the plugin has no * determine whether a port is unsupported, it should return
* support for the device, and 100 means the plugin has full support for the * FALSE. Otherwise, if the plugin needs to perform additional operations
* device. * (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, MMPluginSupportsResult (*supports_port) (MMPlugin *self,
const char *subsys, const char *subsys,
const char *name); 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 /* 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 * 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); const char *mm_plugin_get_name (MMPlugin *plugin);
guint32 mm_plugin_supports_port (MMPlugin *plugin, MMPluginSupportsResult mm_plugin_supports_port (MMPlugin *plugin,
const char *subsys, const char *subsys,
const char *name); 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, MMModem *mm_plugin_grab_port (MMPlugin *plugin,
const char *subsys, const char *subsys,

View File

@@ -87,6 +87,9 @@ mm_serial_parser_v0_parse (gpointer data,
g_return_val_if_fail (parser != NULL, FALSE); g_return_val_if_fail (parser != NULL, FALSE);
g_return_val_if_fail (response != 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); found = g_regex_match_full (parser->generic_response, response->str, response->len, 0, 0, &match_info, NULL);
if (found) { if (found) {
str = g_match_info_fetch (match_info, 1); 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 (parser != NULL, FALSE);
g_return_val_if_fail (response != 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); found = g_regex_match_full (parser->regex_ok, response->str, response->len, 0, 0, NULL, NULL);
if (found) if (found)

View File

@@ -696,6 +696,7 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
} }
priv->channel = g_io_channel_unix_new (priv->fd); 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, priv->watch_id = g_io_add_watch (priv->channel,
G_IO_IN | G_IO_ERR | G_IO_HUP, G_IO_IN | G_IO_ERR | G_IO_HUP,
data_available, self); data_available, self);