udev: move device probing and detection to udev

Get rid of dependency on HAL, using libgudev instead.  Fix up the plugin API
to no longer use either HAL or udev defines, but let plugins use whatever
mechanism they want for getting more information out of the device given the
subsystem and device node name.

Modems are now defined as "master" devices which "own" a one or more ports.
A port could be a serial tty device or a network device or whatever.  The
plugin figures out whether it supports a given port or not and then assigns
it to a new or existing modem.  Modems now have a 'valid' property that
should be set to TRUE when the modem has enough ports to operate correctly.
For devices (ex. 'hso') that use a network device for data transfer, the
modem would need to grab at least one TTY and the network device associated
with that physical device to be 'valid'.

Also move the generic modem support code to a plugin like other modem plugins,
and change the I-support-this-device mechanism to return a number indicating
the level of support.  For example, the generic plugin would return a quite
low number if the device indicates via probing that it can do GSM or CDMA, but
a more specific plugin can indicate better support for the device, and thus
the more specific plugin would win control.
This commit is contained in:
Dan Williams
2009-06-18 14:25:30 -04:00
parent 0555cc1824
commit 924814c101
27 changed files with 3279 additions and 1597 deletions
+2
View File
@@ -25,3 +25,5 @@ ModemManager.pc
marshallers/mm-marshal.[ch]
src/modem-manager
docs/spec.html
callouts/mm-modem-probe
+1 -1
View File
@@ -20,7 +20,7 @@ clean:
rm -f $(GENERATED_FILES)
endif
SUBDIRS = marshallers src plugins introspection test
SUBDIRS = marshallers callouts src plugins introspection test
dbusservicedir = $(DBUS_SYS_DIR)
dbusservice_DATA = org.freedesktop.ModemManager.conf
@@ -0,0 +1,23 @@
# 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"
+13
View File
@@ -0,0 +1,13 @@
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)
+639
View File
@@ -0,0 +1,639 @@
/*
* 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;
}
+6 -1
View File
@@ -12,7 +12,11 @@ AM_PROG_CC_C_O
AC_PROG_INSTALL
AC_PROG_LIBTOOL
PKG_CHECK_MODULES(MM, dbus-glib-1 >= 0.75 glib-2.0 >= 2.14 gmodule-2.0 gobject-2.0 hal)
PKG_CHECK_MODULES(MM, dbus-glib-1 >= 0.75 glib-2.0 >= 2.14 gmodule-2.0 gobject-2.0)
PKG_CHECK_MODULES(GUDEV, gudev-1.0)
AC_SUBST(GUDEV_CFLAGS)
AC_SUBST(GUDEV_LIBS)
AC_ARG_WITH(dbus-sys-dir, AS_HELP_STRING([--with-dbus-sys-dir=DIR], [where D-BUS system.d directory is]))
@@ -67,6 +71,7 @@ esac
AC_CONFIG_FILES([
Makefile
marshallers/Makefile
callouts/Makefile
src/Makefile
plugins/Makefile
test/Makefile
+9 -1
View File
@@ -51,7 +51,15 @@
<property name="Device" type="s" access="read">
<tp:docstring>
The device to use for IP configuration and traffic.
The modem port to use for IP configuration and traffic.
</tp:docstring>
</property>
<property name="MasterDevice" type="s" access="read">
<tp:docstring>
The physical modem device reference (ie, USB, PCI, PCMCIA device), which
may be dependent upon the operating system. In Linux for example, this
points to a sysfs path of the usb_device object.
</tp:docstring>
</property>
+1
View File
@@ -1 +1,2 @@
VOID:UINT,STRING,STRING
VOID:STRING,STRING,UINT
+17
View File
@@ -1,4 +1,5 @@
pkglib_LTLIBRARIES = \
libmm-plugin-generic.la \
libmm-plugin-huawei.la \
libmm-plugin-hso.la \
libmm-plugin-mbm.la \
@@ -8,6 +9,22 @@ pkglib_LTLIBRARIES = \
libmm-plugin-nokia.la \
libmm-plugin-zte.la
# Generic
libmm_plugin_generic_la_SOURCES = \
mm-plugin-generic.c \
mm-plugin-generic.h
libmm_plugin_generic_la_CPPFLAGS = \
$(MM_CFLAGS) \
$(GUDEV_CFLAGS) \
-I$(top_srcdir)/src
libmm_plugin_generic_la_LDFLAGS = \
$(GUDEV_LDFLAGS) \
-module \
-avoid-version
# Huawei
libmm_plugin_huawei_la_SOURCES = \
+350
View File
@@ -0,0 +1,350 @@
/* -*- 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 Dan Williams <dcbw@redhat.com>
*/
#include <string.h>
#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 <gmodule.h>
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
#include <gudev/gudev.h>
#include "mm-plugin-generic.h"
#include "mm-generic-gsm.h"
#include "mm-generic-cdma.h"
#include "mm-serial-port.h"
static void plugin_init (MMPlugin *plugin_class);
G_DEFINE_TYPE_EXTENDED (MMPluginGeneric, mm_plugin_generic, G_TYPE_OBJECT,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
#define MM_PLUGIN_GENERIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_GENERIC, MMPluginGenericPrivate))
typedef struct {
GUdevClient *client;
GHashTable *modems;
} MMPluginGenericPrivate;
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_GENERIC, 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")) {
/* 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
supports_port (MMPlugin *plugin,
const char *subsys,
const char *name)
{
GUdevDevice *device, *physdev = NULL;
gboolean gsm = FALSE, cdma = FALSE;
guint32 level = 0;
g_return_val_if_fail (plugin != NULL, 0);
g_return_val_if_fail (MM_IS_PLUGIN (plugin), 0);
g_return_val_if_fail (subsys != NULL, 0);
g_return_val_if_fail (name != NULL, 0);
/* Can't do anything with non-serial ports */
if (strcmp (subsys, "tty"))
return 0;
device = get_device_type (plugin, subsys, name, &gsm, &cdma);
if (!device)
return 0;
if (!gsm && !cdma)
goto out;
physdev = find_physical_device (device);
if (!physdev)
goto out;
g_object_unref (physdev);
level = 5;
out:
return level;
}
typedef struct {
char *key;
gpointer modem;
} FindInfo;
static void
find_modem (gpointer key, gpointer data, gpointer user_data)
{
FindInfo *info = user_data;
if (!info->key && data == info->modem)
info->key = g_strdup ((const char *) key);
}
static void
modem_destroyed (gpointer data, GObject *modem)
{
MMPluginGeneric *self = MM_PLUGIN_GENERIC (data);
MMPluginGenericPrivate *priv = MM_PLUGIN_GENERIC_GET_PRIVATE (self);
FindInfo info = { NULL, modem };
g_hash_table_foreach (priv->modems, find_modem, &info);
if (info.key)
g_hash_table_remove (priv->modems, info.key);
g_free (info.key);
}
static MMModem *
grab_port (MMPlugin *plugin,
const char *subsys,
const char *name,
GError **error)
{
MMPluginGeneric *self = MM_PLUGIN_GENERIC (plugin);
MMPluginGenericPrivate *priv = MM_PLUGIN_GENERIC_GET_PRIVATE (plugin);
GUdevDevice *device = NULL, *physdev = NULL;
const char *devfile, *sysfs_path;
char *driver = NULL;
MMModem *modem = NULL;
gboolean gsm = FALSE, cdma = FALSE;
g_return_val_if_fail (subsys != NULL, NULL);
g_return_val_if_fail (name != NULL, NULL);
/* Can't do anything with non-serial ports */
if (strcmp (subsys, "tty"))
return NULL;
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 (!devfile) {
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 (!devfile) {
g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
goto out;
}
modem = g_hash_table_lookup (priv->modems, sysfs_path);
if (!modem) {
if (gsm) {
modem = mm_generic_gsm_new (sysfs_path,
driver,
mm_plugin_get_name (plugin));
} else if (cdma) {
modem = mm_generic_cdma_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) {
g_object_weak_ref (G_OBJECT (modem), modem_destroyed, self);
g_hash_table_insert (priv->modems, g_strdup (sysfs_path), modem);
}
} else {
if (gsm || cdma) {
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 "Generic";
}
/*****************************************************************************/
static void
plugin_init (MMPlugin *plugin_class)
{
/* interface implementation */
plugin_class->get_name = get_name;
plugin_class->supports_port = supports_port;
plugin_class->grab_port = grab_port;
}
static void
mm_plugin_generic_init (MMPluginGeneric *self)
{
MMPluginGenericPrivate *priv = MM_PLUGIN_GENERIC_GET_PRIVATE (self);
const char *subsys[2] = { "tty", NULL };
priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
priv->client = g_udev_client_new (subsys);
}
static void
dispose (GObject *object)
{
MMPluginGenericPrivate *priv = MM_PLUGIN_GENERIC_GET_PRIVATE (object);
g_hash_table_destroy (priv->modems);
g_object_unref (priv->client);
}
static void
mm_plugin_generic_class_init (MMPluginGenericClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMPluginGenericPrivate));
object_class->dispose = dispose;
}
+27
View File
@@ -0,0 +1,27 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_PLUGIN_GENERIC_H
#define MM_PLUGIN_GENERIC_H
#include "mm-plugin.h"
#define MM_TYPE_PLUGIN_GENERIC (mm_plugin_generic_get_type ())
#define MM_PLUGIN_GENERIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_GENERIC, MMPluginGeneric))
#define MM_PLUGIN_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_GENERIC, MMPluginGenericClass))
#define MM_IS_PLUGIN_GENERIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_GENERIC))
#define MM_IS_PLUGIN_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_GENERIC))
#define MM_PLUGIN_GENERIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_GENERIC, MMPluginGenericClass))
typedef struct {
GObject parent;
} MMPluginGeneric;
typedef struct {
GObjectClass parent;
} MMPluginGenericClass;
GType mm_plugin_generic_get_type (void);
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
#endif /* MM_PLUGIN_GENERIC_H */
+13 -9
View File
@@ -2,27 +2,35 @@ sbin_PROGRAMS = modem-manager
modem_manager_CPPFLAGS = \
$(MM_CFLAGS) \
$(GUDEV_CFLAGS) \
-I${top_builddir}/marshallers \
-DPLUGINDIR=\"$(pkglibdir)\"
modem_manager_LDADD = \
$(MM_LIBS) \
$(GUDEV_LIBS) \
$(top_builddir)/marshallers/libmarshallers.la
modem_manager_SOURCES = \
main.c \
mm-callback-info.c \
mm-callback-info.h \
mm-generic-cdma.c \
mm-generic-cdma.h \
mm-generic-gsm.c \
mm-generic-gsm.h \
mm-errors.c \
mm-errors.h \
mm-manager.c \
mm-manager.h \
mm-modem.c \
mm-modem.h \
mm-serial.c \
mm-serial.h \
mm-serial-port.c \
mm-serial-port.h \
mm-serial-parsers.c \
mm-serial-parsers.h \
mm-generic-cdma.c \
mm-generic-cdma.h \
mm-generic-gsm.c \
mm-generic-gsm.h \
mm-modem-cdma.c \
mm-modem-cdma.h \
mm-modem-gsm-card.c \
@@ -36,11 +44,7 @@ modem_manager_SOURCES = \
mm-options.c \
mm-options.h \
mm-plugin.c \
mm-plugin.h \
mm-serial.c \
mm-serial.h \
mm-serial-parsers.c \
mm-serial-parsers.h
mm-plugin.h
mm-manager-glue.h: $(top_srcdir)/introspection/mm-manager.xml
dbus-binding-tool --prefix=mm_manager --mode=glib-server --output=$@ $<
+4 -89
View File
@@ -5,7 +5,6 @@
#include <string.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <libhal.h>
#include "mm-manager.h"
#include "mm-options.h"
@@ -135,87 +134,11 @@ create_dbus_proxy (DBusGConnection *bus)
return proxy;
}
static void
hal_init (MMManager *manager)
{
LibHalContext *hal_ctx;
DBusError dbus_error;
hal_ctx = libhal_ctx_new ();
if (!hal_ctx) {
g_warning ("Could not get connection to the HAL service.");
}
libhal_ctx_set_dbus_connection (hal_ctx, dbus_g_connection_get_connection (mm_manager_get_bus (manager)));
dbus_error_init (&dbus_error);
if (!libhal_ctx_init (hal_ctx, &dbus_error)) {
g_warning ("libhal_ctx_init() failed: %s", dbus_error.message);
dbus_error_free (&dbus_error);
}
mm_manager_set_hal_ctx (manager, hal_ctx);
}
static void
hal_deinit (MMManager *manager)
{
LibHalContext *hal_ctx;
hal_ctx = mm_manager_get_hal_ctx (manager);
if (hal_ctx) {
libhal_ctx_shutdown (hal_ctx, NULL);
libhal_ctx_free (hal_ctx);
mm_manager_set_hal_ctx (manager, NULL);
}
}
static gboolean
hal_on_bus (DBusGProxy *proxy)
start_manager (gpointer user_data)
{
GError *err = NULL;
gboolean has_owner = FALSE;
if (!dbus_g_proxy_call (proxy,
"NameHasOwner", &err,
G_TYPE_STRING, HAL_DBUS_SERVICE,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &has_owner,
G_TYPE_INVALID)) {
g_warning ("Error on NameHasOwner DBUS call: %s", err->message);
g_error_free (err);
}
return has_owner;
}
static void
name_owner_changed (DBusGProxy *proxy,
const char *name,
const char *old_owner,
const char *new_owner,
gpointer user_data)
{
MMManager *manager;
gboolean old_owner_good;
gboolean new_owner_good;
/* Only care about signals from HAL */
if (strcmp (name, HAL_DBUS_SERVICE))
return;
manager = MM_MANAGER (user_data);
old_owner_good = (old_owner && (strlen (old_owner) > 0));
new_owner_good = (new_owner && (strlen (new_owner) > 0));
if (!old_owner_good && new_owner_good) {
g_message ("HAL appeared");
hal_init (manager);
} else if (old_owner_good && !new_owner_good) {
/* HAL went away. Bad HAL. */
g_message ("HAL disappeared");
hal_deinit (manager);
}
mm_manager_start (MM_MANAGER (user_data));
return FALSE;
}
int
@@ -249,21 +172,13 @@ main (int argc, char *argv[])
return -1;
manager = mm_manager_new (bus);
dbus_g_proxy_connect_signal (proxy,
"NameOwnerChanged",
G_CALLBACK (name_owner_changed),
manager, NULL);
if (hal_on_bus (proxy))
hal_init (manager);
g_idle_add (start_manager, manager);
loop = g_main_loop_new (NULL, FALSE);
g_signal_connect (proxy, "destroy", G_CALLBACK (destroy_cb), loop);
g_main_loop_run (loop);
hal_deinit (manager);
g_object_unref (manager);
g_object_unref (proxy);
dbus_g_connection_unref (bus);
+182 -35
View File
@@ -16,25 +16,124 @@ static gpointer mm_generic_cdma_parent_class = NULL;
typedef struct {
char *driver;
char *plugin;
char *device;
guint32 ip_method;
gboolean valid;
MMSerialPort *primary;
MMSerialPort *secondary;
} MMGenericCdmaPrivate;
MMModem *
mm_generic_cdma_new (const char *serial_device, const char *driver)
mm_generic_cdma_new (const char *device,
const char *driver,
const char *plugin)
{
g_return_val_if_fail (serial_device != NULL, NULL);
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_GENERIC_CDMA,
MM_SERIAL_DEVICE, serial_device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_TYPE, MM_MODEM_TYPE_CDMA,
MM_MODEM_PLUGIN, plugin,
NULL));
}
/*****************************************************************************/
static void
enable_error_reporting_done (MMSerial *serial,
check_valid (MMGenericCdma *self)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
gboolean new_valid = FALSE;
if (priv->primary)
new_valid = TRUE;
if (priv->valid != new_valid) {
priv->valid = new_valid;
g_object_notify (G_OBJECT (self), MM_MODEM_VALID);
}
}
static gboolean
owns_port (MMModem *modem, const char *subsys, const char *name)
{
MMGenericCdma *self = MM_GENERIC_CDMA (modem);
if (strcmp (subsys, "tty"))
return FALSE;
return !!mm_serial_get_port (MM_SERIAL (self), name);
}
static gboolean
grab_port (MMModem *modem,
const char *subsys,
const char *name,
GError **error)
{
MMGenericCdma *self = MM_GENERIC_CDMA (modem);
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
MMSerialPortType ptype = MM_SERIAL_PORT_TYPE_IGNORED;
MMSerialPort *port;
if (strcmp (subsys, "tty"))
return FALSE;
if (!priv->primary)
ptype = MM_SERIAL_PORT_TYPE_PRIMARY;
else if (!priv->secondary)
ptype = MM_SERIAL_PORT_TYPE_SECONDARY;
port = mm_serial_add_port (MM_SERIAL (self), name, ptype);
g_object_set (G_OBJECT (port), MM_SERIAL_PORT_CARRIER_DETECT, FALSE, NULL);
mm_serial_port_set_response_parser (port,
mm_serial_parser_v1_parse,
mm_serial_parser_v1_new (),
mm_serial_parser_v1_destroy);
if (ptype == MM_SERIAL_PORT_TYPE_PRIMARY) {
priv->primary = port;
g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
check_valid (self);
} else if (ptype == MM_SERIAL_PORT_TYPE_SECONDARY)
priv->secondary = port;
return TRUE;
}
static void
release_port (MMModem *modem, const char *subsys, const char *name)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMSerialPort *port;
if (strcmp (subsys, "tty"))
return;
port = mm_serial_get_port (MM_SERIAL (modem), name);
if (!port)
return;
if (port == priv->primary) {
mm_serial_remove_port (MM_SERIAL (modem), port);
priv->primary = NULL;
}
if (port == priv->secondary) {
mm_serial_remove_port (MM_SERIAL (modem), port);
priv->secondary = NULL;
}
check_valid (MM_GENERIC_CDMA (modem));
}
static void
enable_error_reporting_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -49,7 +148,7 @@ enable_error_reporting_done (MMSerial *serial,
}
static void
init_done (MMSerial *serial,
init_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -65,14 +164,14 @@ init_done (MMSerial *serial,
FIXME: It's mandatory by spec, so it really shouldn't be optional. Figure
out which CDMA modems have problems with it and implement plugin for them.
*/
mm_serial_queue_command (serial, "+CMEE=1", 3, enable_error_reporting_done, user_data);
mm_serial_port_queue_command (port, "+CMEE=1", 3, enable_error_reporting_done, user_data);
}
}
static void
flash_done (MMSerial *serial, gpointer user_data)
flash_done (MMSerialPort *port, gpointer user_data)
{
mm_serial_queue_command (serial, "Z E0 V1 X4 &C1", 3, init_done, user_data);
mm_serial_port_queue_command (port, "Z E0 V1 X4 &C1", 3, init_done, user_data);
}
static void
@@ -81,25 +180,26 @@ enable (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_new (modem, callback, user_data);
if (!do_enable) {
mm_serial_close (MM_SERIAL (modem));
mm_serial_port_close (priv->primary);
mm_callback_info_schedule (info);
return;
}
if (mm_serial_open (MM_SERIAL (modem), &info->error))
mm_serial_flash (MM_SERIAL (modem), 100, flash_done, info);
if (mm_serial_port_open (priv->primary, &info->error))
mm_serial_port_flash (priv->primary, 100, flash_done, info);
if (info->error)
mm_callback_info_schedule (info);
}
static void
dial_done (MMSerial *serial,
dial_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -118,17 +218,18 @@ connect (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (modem, callback, user_data);
command = g_strconcat ("DT", number, NULL);
mm_serial_queue_command (MM_SERIAL (modem), command, 60, dial_done, info);
mm_serial_port_queue_command (priv->primary, command, 60, dial_done, info);
g_free (command);
}
static void
disconnect_flash_done (MMSerial *serial, gpointer user_data)
disconnect_flash_done (MMSerialPort *port, gpointer user_data)
{
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
}
@@ -138,14 +239,17 @@ disconnect (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMCallbackInfo *info;
g_return_if_fail (priv->primary != NULL);
info = mm_callback_info_new (modem, callback, user_data);
mm_serial_flash (MM_SERIAL (modem), 1000, disconnect_flash_done, info);
mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info);
}
static void
get_signal_quality_done (MMSerial *serial,
get_signal_quality_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -182,10 +286,15 @@ get_signal_quality (MMModemCdma *modem,
MMModemUIntFn callback,
gpointer user_data)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
mm_serial_queue_command (MM_SERIAL (modem), "+CSQ", 3, get_signal_quality_done, info);
/* Prefer secondary port for signal strength */
mm_serial_port_queue_command (priv->secondary ? priv->secondary : priv->primary,
"+CSQ",
3,
get_signal_quality_done, info);
}
/*****************************************************************************/
@@ -261,6 +370,7 @@ simple_connect (MMModemSimple *simple,
gpointer user_data)
{
MMCallbackInfo *info;
GError *error = NULL;
info = mm_callback_info_new (MM_MODEM (simple), callback, user_data);
mm_callback_info_set_data (info, "simple-connect-properties",
@@ -268,12 +378,12 @@ simple_connect (MMModemSimple *simple,
(GDestroyNotify) g_hash_table_unref);
/* At least number must be present */
if (!simple_get_string_property (info, "number", &info->error)) {
if (!info->error)
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Missing number property");
if (!simple_get_string_property (info, "number", &error)) {
if (!error)
error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Missing number property");
}
simple_state_machine (MM_MODEM (simple), NULL, info);
simple_state_machine (MM_MODEM (simple), error, info);
}
static void
@@ -340,6 +450,9 @@ simple_get_status (MMModemSimple *simple,
static void
modem_init (MMModem *modem_class)
{
modem_class->owns_port = owns_port;
modem_class->grab_port = grab_port;
modem_class->release_port = release_port;
modem_class->enable = enable;
modem_class->connect = connect;
modem_class->disconnect = disconnect;
@@ -361,24 +474,32 @@ modem_simple_init (MMModemSimple *class)
static void
mm_generic_cdma_init (MMGenericCdma *self)
{
mm_serial_set_response_parser (MM_SERIAL (self),
mm_serial_parser_v1_parse,
mm_serial_parser_v1_new (),
mm_serial_parser_v1_destroy);
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (object);
switch (prop_id) {
case MM_MODEM_PROP_DRIVER:
/* Construct only */
MM_GENERIC_CDMA_GET_PRIVATE (object)->driver = g_value_dup_string (value);
priv->driver = g_value_dup_string (value);
break;
case MM_MODEM_PROP_PLUGIN:
/* Construct only */
priv->plugin = g_value_dup_string (value);
break;
case MM_MODEM_PROP_MASTER_DEVICE:
/* Constrcut only */
priv->device = g_value_dup_string (value);
break;
case MM_MODEM_PROP_DEVICE:
case MM_MODEM_PROP_TYPE:
case MM_MODEM_PROP_IP_METHOD:
priv->ip_method = g_value_get_uint (value);
break;
case MM_MODEM_PROP_TYPE:
case MM_MODEM_PROP_VALID:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -390,18 +511,32 @@ static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (object);
switch (prop_id) {
case MM_MODEM_PROP_DEVICE:
g_value_set_string (value, mm_serial_get_device (MM_SERIAL (object)));
case MM_MODEM_PROP_DATA_DEVICE:
if (priv->primary)
g_value_set_string (value, mm_serial_port_get_device (priv->primary));
else
g_value_set_string (value, NULL);
break;
case MM_MODEM_PROP_MASTER_DEVICE:
g_value_set_string (value, priv->device);
break;
case MM_MODEM_PROP_DRIVER:
g_value_set_string (value, MM_GENERIC_CDMA_GET_PRIVATE (object)->driver);
g_value_set_string (value, priv->driver);
break;
case MM_MODEM_PROP_PLUGIN:
g_value_set_string (value, priv->plugin);
break;
case MM_MODEM_PROP_TYPE:
g_value_set_uint (value, MM_MODEM_TYPE_CDMA);
break;
case MM_MODEM_PROP_IP_METHOD:
g_value_set_uint (value, MM_MODEM_IP_METHOD_PPP);
g_value_set_uint (value, priv->ip_method);
break;
case MM_MODEM_PROP_VALID:
g_value_set_boolean (value, priv->valid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -434,13 +569,21 @@ mm_generic_cdma_class_init (MMGenericCdmaClass *klass)
/* Properties */
g_object_class_override_property (object_class,
MM_MODEM_PROP_DEVICE,
MM_MODEM_DEVICE);
MM_MODEM_PROP_DATA_DEVICE,
MM_MODEM_DATA_DEVICE);
g_object_class_override_property (object_class,
MM_MODEM_PROP_MASTER_DEVICE,
MM_MODEM_MASTER_DEVICE);
g_object_class_override_property (object_class,
MM_MODEM_PROP_DRIVER,
MM_MODEM_DRIVER);
g_object_class_override_property (object_class,
MM_MODEM_PROP_PLUGIN,
MM_MODEM_PLUGIN);
g_object_class_override_property (object_class,
MM_MODEM_PROP_TYPE,
MM_MODEM_TYPE);
@@ -448,6 +591,10 @@ mm_generic_cdma_class_init (MMGenericCdmaClass *klass)
g_object_class_override_property (object_class,
MM_MODEM_PROP_IP_METHOD,
MM_MODEM_IP_METHOD);
g_object_class_override_property (object_class,
MM_MODEM_PROP_VALID,
MM_MODEM_VALID);
}
GType
+9 -8
View File
@@ -6,12 +6,12 @@
#include "mm-modem.h"
#include "mm-serial.h"
#define MM_TYPE_GENERIC_CDMA (mm_generic_cdma_get_type ())
#define MM_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdma))
#define MM_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
#define MM_IS_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_CDMA))
#define MM_IS_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_CDMA))
#define MM_GENERIC_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
#define MM_TYPE_GENERIC_CDMA (mm_generic_cdma_get_type ())
#define MM_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdma))
#define MM_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
#define MM_IS_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_CDMA))
#define MM_IS_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_CDMA))
#define MM_GENERIC_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
typedef struct {
MMSerial parent;
@@ -23,7 +23,8 @@ typedef struct {
GType mm_generic_cdma_get_type (void);
MMModem *mm_generic_cdma_new (const char *serial_device,
const char *driver);
MMModem *mm_generic_cdma_new (const char *device,
const char *driver,
const char *plugin);
#endif /* MM_GENERIC_CDMA_H */
+325 -132
View File
@@ -18,10 +18,14 @@ static gpointer mm_generic_gsm_parent_class = NULL;
typedef struct {
char *driver;
char *plugin;
char *device;
gboolean valid;
char *data_device;
char *oper_code;
char *oper_name;
guint32 modem_type;
guint32 ip_method;
gboolean unsolicited_registration;
@@ -30,24 +34,39 @@ typedef struct {
guint32 signal_quality;
guint32 cid;
MMSerialPort *primary;
MMSerialPort *secondary;
} MMGenericGsmPrivate;
static void get_registration_status (MMSerial *serial, MMCallbackInfo *info);
static void read_operator_done (MMSerial *serial,
GString *response,
GError *error,
gpointer user_data);
static void get_registration_status (MMSerialPort *port, MMCallbackInfo *info);
static void read_operator_code_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data);
static void read_operator_name_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data);
static void reg_state_changed (MMSerialPort *port,
GMatchInfo *match_info,
gpointer user_data);
MMModem *
mm_generic_gsm_new (const char *serial_device, const char *driver)
mm_generic_gsm_new (const char *device,
const char *driver,
const char *plugin)
{
g_return_val_if_fail (serial_device != NULL, NULL);
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_GENERIC_GSM,
MM_SERIAL_DEVICE, serial_device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_TYPE, MM_MODEM_TYPE_GSM,
MM_MODEM_PLUGIN, plugin,
NULL));
}
@@ -101,8 +120,8 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *modem,
if (status == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
status == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
mm_serial_queue_command (MM_SERIAL (modem), "+COPS=3,2;+COPS?", 3, read_operator_done, GINT_TO_POINTER (0));
mm_serial_queue_command (MM_SERIAL (modem), "+COPS=3,0;+COPS?", 3, read_operator_done, GINT_TO_POINTER (1));
mm_serial_port_queue_command (priv->primary, "+COPS=3,2;+COPS?", 3, read_operator_code_done, modem);
mm_serial_port_queue_command (priv->primary, "+COPS=3,0;+COPS?", 3, read_operator_name_done, modem);
mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (modem), got_signal_quality, NULL);
} else {
g_free (priv->oper_code);
@@ -116,7 +135,7 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *modem,
}
static void
pin_check_done (MMSerial *serial,
pin_check_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -150,18 +169,113 @@ mm_generic_gsm_check_pin (MMGenericGsm *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv;
MMCallbackInfo *info;
g_return_if_fail (MM_IS_GENERIC_GSM (modem));
priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
mm_serial_queue_command (MM_SERIAL (modem), "+CPIN?", 3, pin_check_done, info);
mm_serial_port_queue_command (priv->primary, "+CPIN?", 3, pin_check_done, info);
}
/*****************************************************************************/
static void
enable_done (MMSerial *serial,
check_valid (MMGenericGsm *self)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
gboolean new_valid = FALSE;
if (priv->primary)
new_valid = TRUE;
if (priv->valid != new_valid) {
priv->valid = new_valid;
g_object_notify (G_OBJECT (self), MM_MODEM_VALID);
}
}
static gboolean
owns_port (MMModem *modem, const char *subsys, const char *name)
{
MMGenericGsm *self = MM_GENERIC_GSM (modem);
if (strcmp (subsys, "tty"))
return FALSE;
return !!mm_serial_get_port (MM_SERIAL (self), name);
}
static gboolean
grab_port (MMModem *modem,
const char *subsys,
const char *name,
GError **error)
{
MMGenericGsm *self = MM_GENERIC_GSM (modem);
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
MMSerialPortType ptype = MM_SERIAL_PORT_TYPE_IGNORED;
MMSerialPort *port;
GRegex *regex;
if (strcmp (subsys, "tty"))
return FALSE;
if (!priv->primary)
ptype = MM_SERIAL_PORT_TYPE_PRIMARY;
else if (!priv->secondary)
ptype = MM_SERIAL_PORT_TYPE_SECONDARY;
port = mm_serial_add_port (MM_SERIAL (self), name, ptype);
mm_serial_port_set_response_parser (port,
mm_serial_parser_v1_parse,
mm_serial_parser_v1_new (),
mm_serial_parser_v1_destroy);
regex = g_regex_new ("\\r\\n\\+CREG: (\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
mm_serial_port_add_unsolicited_msg_handler (port, regex, reg_state_changed, self, NULL);
g_regex_unref (regex);
if (ptype == MM_SERIAL_PORT_TYPE_PRIMARY) {
priv->primary = port;
g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
check_valid (self);
} else if (ptype == MM_SERIAL_PORT_TYPE_SECONDARY)
priv->secondary = port;
return TRUE;
}
static void
release_port (MMModem *modem, const char *subsys, const char *name)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMSerialPort *port;
if (strcmp (subsys, "tty"))
return;
port = mm_serial_get_port (MM_SERIAL (modem), name);
if (!port)
return;
if (port == priv->primary) {
mm_serial_remove_port (MM_SERIAL (modem), port);
priv->primary = NULL;
check_valid (MM_GENERIC_GSM (modem));
}
if (port == priv->secondary) {
mm_serial_remove_port (MM_SERIAL (modem), port);
priv->secondary = NULL;
check_valid (MM_GENERIC_GSM (modem));
}
}
static void
enable_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -175,7 +289,7 @@ enable_done (MMSerial *serial,
}
static void
init_done (MMSerial *serial,
init_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -186,35 +300,35 @@ init_done (MMSerial *serial,
info->error = g_error_copy (error);
mm_callback_info_schedule (info);
} else {
if (MM_GENERIC_GSM_GET_PRIVATE (serial)->unsolicited_registration)
mm_serial_queue_command (serial, "+CREG=1", 5, NULL, NULL);
if (MM_GENERIC_GSM_GET_PRIVATE (info->modem)->unsolicited_registration)
mm_serial_port_queue_command (port, "+CREG=1", 5, NULL, NULL);
else
mm_serial_queue_command (serial, "+CREG=0", 5, NULL, NULL);
mm_serial_port_queue_command (port, "+CREG=0", 5, NULL, NULL);
mm_serial_queue_command (serial, "+CFUN=1", 5, enable_done, user_data);
mm_serial_port_queue_command (port, "+CFUN=1", 5, enable_done, user_data);
}
}
static void
enable_flash_done (MMSerial *serial, gpointer user_data)
enable_flash_done (MMSerialPort *port, gpointer user_data)
{
mm_serial_queue_command (serial, "Z E0 V1 X4 &C1 +CMEE=1", 3, init_done, user_data);
mm_serial_port_queue_command (port, "Z E0 V1 X4 &C1 +CMEE=1", 3, init_done, user_data);
}
static void
disable_done (MMSerial *serial,
disable_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
mm_serial_close (serial);
mm_serial_port_close (port);
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
}
static void
disable_flash_done (MMSerial *serial, gpointer user_data)
disable_flash_done (MMSerialPort *port, gpointer user_data)
{
mm_serial_queue_command (serial, "+CFUN=0", 5, disable_done, user_data);
mm_serial_port_queue_command (port, "+CFUN=0", 5, disable_done, user_data);
}
static void
@@ -223,6 +337,7 @@ enable (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
/* First, reset the previously used CID */
@@ -233,13 +348,13 @@ enable (MMModem *modem,
if (!do_enable) {
mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem));
if (mm_serial_is_connected (MM_SERIAL (modem)))
mm_serial_flash (MM_SERIAL (modem), 1000, disable_flash_done, info);
if (mm_serial_port_is_connected (priv->primary))
mm_serial_port_flash (priv->primary, 1000, disable_flash_done, info);
else
disable_flash_done (MM_SERIAL (modem), info);
disable_flash_done (priv->primary, info);
} else {
if (mm_serial_open (MM_SERIAL (modem), &info->error))
mm_serial_flash (MM_SERIAL (modem), 100, enable_flash_done, info);
if (mm_serial_port_open (priv->primary, &info->error))
mm_serial_port_flash (priv->primary, 100, enable_flash_done, info);
if (info->error)
mm_callback_info_schedule (info);
@@ -247,7 +362,7 @@ enable (MMModem *modem,
}
static void
get_string_done (MMSerial *serial,
get_string_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -267,10 +382,11 @@ get_imei (MMModemGsmCard *modem,
MMModemStringFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
mm_serial_queue_command_cached (MM_SERIAL (modem), "+CGSN", 3, get_string_done, info);
mm_serial_port_queue_command_cached (priv->primary, "+CGSN", 3, get_string_done, info);
}
static void
@@ -278,10 +394,11 @@ get_imsi (MMModemGsmCard *modem,
MMModemStringFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
mm_serial_queue_command_cached (MM_SERIAL (modem), "+CIMI", 3, get_string_done, info);
mm_serial_port_queue_command_cached (priv->primary, "+CIMI", 3, get_string_done, info);
}
static void
@@ -297,7 +414,7 @@ gsm_card_info_invoke (MMCallbackInfo *info)
}
static void
get_version_done (MMSerial *serial,
get_version_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -313,7 +430,7 @@ get_version_done (MMSerial *serial,
}
static void
get_model_done (MMSerial *serial,
get_model_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -327,7 +444,7 @@ get_model_done (MMSerial *serial,
}
static void
get_manufacturer_done (MMSerial *serial,
get_manufacturer_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -345,21 +462,21 @@ get_card_info (MMModemGsmCard *modem,
MMModemGsmCardInfoFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
MMSerial *serial = MM_SERIAL (modem);
info = mm_callback_info_new_full (MM_MODEM (modem),
gsm_card_info_invoke,
G_CALLBACK (callback),
user_data);
mm_serial_queue_command_cached (serial, "+CGMI", 3, get_manufacturer_done, info);
mm_serial_queue_command_cached (serial, "+CGMM", 3, get_model_done, info);
mm_serial_queue_command_cached (serial, "+CGMR", 3, get_version_done, info);
mm_serial_port_queue_command_cached (priv->primary, "+CGMI", 3, get_manufacturer_done, info);
mm_serial_port_queue_command_cached (priv->primary, "+CGMM", 3, get_model_done, info);
mm_serial_port_queue_command_cached (priv->primary, "+CGMR", 3, get_version_done, info);
}
static void
send_puk_done (MMSerial *serial,
send_puk_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -378,17 +495,18 @@ send_puk (MMModemGsmCard *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CPIN=\"%s\",\"%s\"", puk, pin);
mm_serial_queue_command (MM_SERIAL (modem), command, 3, send_puk_done, info);
mm_serial_port_queue_command (priv->primary, command, 3, send_puk_done, info);
g_free (command);
}
static void
send_pin_done (MMSerial *serial,
send_pin_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -406,17 +524,18 @@ send_pin (MMModemGsmCard *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CPIN=\"%s\"", pin);
mm_serial_queue_command (MM_SERIAL (modem), command, 3, send_pin_done, info);
mm_serial_port_queue_command (priv->primary, command, 3, send_pin_done, info);
g_free (command);
}
static void
enable_pin_done (MMSerial *serial,
enable_pin_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -435,17 +554,18 @@ enable_pin (MMModemGsmCard *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CLCK=\"SC\",%d,\"%s\"", enabled ? 1 : 0, pin);
mm_serial_queue_command (MM_SERIAL (modem), command, 3, enable_pin_done, info);
mm_serial_port_queue_command (priv->primary, command, 3, enable_pin_done, info);
g_free (command);
}
static void
change_pin_done (MMSerial *serial,
change_pin_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -464,12 +584,13 @@ change_pin (MMModemGsmCard *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CPWD=\"SC\",\"%s\",\"%s\"", old_pin, new_pin);
mm_serial_queue_command (MM_SERIAL (modem), command, 3, change_pin_done, info);
mm_serial_port_queue_command (priv->primary, command, 3, change_pin_done, info);
g_free (command);
}
@@ -500,30 +621,48 @@ parse_operator (const char *reply)
}
static void
read_operator_done (MMSerial *serial,
GString *response,
GError *error,
gpointer user_data)
read_operator_code_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
if (!error) {
char *oper;
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data);
char *oper;
oper = parse_operator (response->str);
if (oper) {
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (serial);
if (error)
return;
if (GPOINTER_TO_INT (user_data) == 0) {
g_free (priv->oper_code);
priv->oper_code = oper;
} else {
g_free (priv->oper_name);
priv->oper_name = oper;
oper = parse_operator (response->str);
if (!oper)
return;
mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (serial), priv->reg_status,
priv->oper_code, priv->oper_name);
}
}
}
g_free (priv->oper_code);
priv->oper_code = oper;
}
static void
read_operator_name_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data);
char *oper;
if (error)
return;
oper = parse_operator (response->str);
if (!oper)
return;
g_free (priv->oper_name);
priv->oper_name = oper;
mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (user_data),
priv->reg_status,
priv->oper_code,
priv->oper_name);
}
/* Registration */
@@ -618,24 +757,27 @@ reg_status_updated (MMGenericGsm *self, int new_value)
}
static void
reg_state_changed (MMSerial *serial,
reg_state_changed (MMSerialPort *port,
GMatchInfo *match_info,
gpointer user_data)
{
MMGenericGsm *self = MM_GENERIC_GSM (user_data);
char *str;
str = g_match_info_fetch (match_info, 1);
reg_status_updated (MM_GENERIC_GSM (serial), atoi (str));
reg_status_updated (self, atoi (str));
g_free (str);
}
static gboolean
reg_status_again (gpointer data)
{
MMGenericGsmPrivate *priv;
MMCallbackInfo *info = (MMCallbackInfo *) data;
if (MM_GENERIC_GSM_GET_PRIVATE (info->modem)->pending_registration)
get_registration_status (MM_SERIAL (info->modem), info);
priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
if (priv->pending_registration)
get_registration_status (priv->primary, info);
return FALSE;
}
@@ -647,13 +789,13 @@ reg_status_again_remove (gpointer data)
}
static void
get_reg_status_done (MMSerial *serial,
get_reg_status_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (serial);
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
if (error) {
info->error = g_error_copy (error);
@@ -666,7 +808,7 @@ get_reg_status_done (MMSerial *serial,
int unsolicited, stat;
if (sscanf (response->str + 7, "%d,%d", &unsolicited, &stat)) {
reg_status_updated (MM_GENERIC_GSM (serial), stat);
reg_status_updated (MM_GENERIC_GSM (info->modem), stat);
if (!unsolicited && priv->pending_registration) {
guint id;
@@ -687,19 +829,19 @@ get_reg_status_done (MMSerial *serial,
}
static void
get_registration_status (MMSerial *serial, MMCallbackInfo *info)
get_registration_status (MMSerialPort *port, MMCallbackInfo *info)
{
mm_serial_queue_command (serial, "+CREG?", 3, get_reg_status_done, info);
mm_serial_port_queue_command (port, "+CREG?", 3, get_reg_status_done, info);
}
static void
register_done (MMSerial *serial,
register_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
/* Ignore errors here, get the actual registration status */
get_registration_status (serial, (MMCallbackInfo *) user_data);
get_registration_status (port, (MMCallbackInfo *) user_data);
}
static void
@@ -708,12 +850,13 @@ do_register (MMModemGsmNetwork *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
MM_GENERIC_GSM_GET_PRIVATE (modem)->pending_registration =
priv->pending_registration =
g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, 60,
pending_registration_timed_out,
info,
@@ -724,7 +867,7 @@ do_register (MMModemGsmNetwork *modem,
else
command = g_strdup ("+COPS=0,,");
mm_serial_queue_command (MM_SERIAL (modem), command, 5, register_done, info);
mm_serial_port_queue_command (priv->primary, command, 5, register_done, info);
g_free (command);
}
@@ -758,7 +901,7 @@ get_registration_info (MMModemGsmNetwork *self,
}
static void
connect_report_done (MMSerial *serial,
connect_report_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -774,17 +917,19 @@ connect_report_done (MMSerial *serial,
}
static void
connect_done (MMSerial *serial,
connect_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMGenericGsmPrivate *priv;
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
if (error) {
info->error = g_error_copy (error);
/* Try to get more information why it failed */
mm_serial_queue_command (serial, "+CEER", 3, connect_report_done, info);
priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
mm_serial_port_queue_command (priv->primary, "+CEER", 3, connect_report_done, info);
} else
/* Done */
mm_callback_info_schedule (info);
@@ -796,6 +941,7 @@ connect (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
guint32 cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (modem));
@@ -816,12 +962,12 @@ connect (MMModem *modem,
} else
command = g_strconcat ("DT", number, NULL);
mm_serial_queue_command (MM_SERIAL (modem), command, 60, connect_done, info);
mm_serial_port_queue_command (priv->primary, command, 60, connect_done, info);
g_free (command);
}
static void
disconnect_flash_done (MMSerial *serial, gpointer user_data)
disconnect_flash_done (MMSerialPort *port, gpointer user_data)
{
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
}
@@ -831,13 +977,14 @@ disconnect (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
/* First, reset the previously used CID */
mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
info = mm_callback_info_new (modem, callback, user_data);
mm_serial_flash (MM_SERIAL (modem), 1000, disconnect_flash_done, info);
mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info);
}
static void
@@ -861,7 +1008,7 @@ destroy_scan_data (gpointer data)
}
static void
scan_done (MMSerial *serial,
scan_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -880,8 +1027,13 @@ scan_done (MMSerial *serial,
reply += 7;
/* Pattern without crazy escaping using | for matching: (|\d|,"|.+|","|.+|","|.+|",|\d|) */
r = g_regex_new ("\\((\\d),\"(.+)\",\"(.+)\",\"(.+)\",(\\d)\\)", G_REGEX_UNGREEDY, 0, &err);
/* Pattern without crazy escaping using | for matching: (|\d|,"|.+|","|.+|","|.+|"\)?,|\d|) */
/* Quirk: Sony-Ericsson TM-506 sometimes includes a stray ')' like so:
*
* +COPS: (2,"","T-Mobile","31026",0),(1,"AT&T","AT&T","310410"),0)
*/
r = g_regex_new ("\\((\\d),\"(.*)\",\"(.*)\",\"(.*)\"\\)?,(\\d)\\)", G_REGEX_UNGREEDY, 0, &err);
if (err) {
g_error ("Invalid regular expression: %s", err->message);
g_error_free (err);
@@ -922,6 +1074,7 @@ scan (MMModemGsmNetwork *modem,
MMModemGsmNetworkScanFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_new_full (MM_MODEM (modem),
@@ -929,13 +1082,13 @@ scan (MMModemGsmNetwork *modem,
G_CALLBACK (callback),
user_data);
mm_serial_queue_command (MM_SERIAL (modem), "+COPS=?", 60, scan_done, info);
mm_serial_port_queue_command (priv->primary, "+COPS=?", 60, scan_done, info);
}
/* SetApn */
static void
set_apn_done (MMSerial *serial,
set_apn_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -945,14 +1098,14 @@ set_apn_done (MMSerial *serial,
if (error)
info->error = g_error_copy (error);
else
mm_generic_gsm_set_cid (MM_GENERIC_GSM (serial),
mm_generic_gsm_set_cid (MM_GENERIC_GSM (info->modem),
GPOINTER_TO_UINT (mm_callback_info_get_data (info, "cid")));
mm_callback_info_schedule (info);
}
static void
cid_range_read (MMSerial *serial,
cid_range_read (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -1012,13 +1165,13 @@ cid_range_read (MMSerial *serial,
mm_callback_info_set_data (info, "cid", GUINT_TO_POINTER (cid), NULL);
command = g_strdup_printf ("+CGDCONT=%d, \"IP\", \"%s\"", cid, apn);
mm_serial_queue_command (serial, command, 3, set_apn_done, info);
mm_serial_port_queue_command (port, command, 3, set_apn_done, info);
g_free (command);
}
}
static void
existing_apns_read (MMSerial *serial,
existing_apns_read (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -1051,7 +1204,7 @@ existing_apns_read (MMSerial *serial,
apn = g_match_info_fetch (match_info, 3);
if (!strcmp (apn, new_apn)) {
mm_generic_gsm_set_cid (MM_GENERIC_GSM (serial), (guint32) num_cid);
mm_generic_gsm_set_cid (MM_GENERIC_GSM (info->modem), (guint32) num_cid);
found = TRUE;
}
@@ -1083,7 +1236,7 @@ existing_apns_read (MMSerial *serial,
mm_callback_info_schedule (info);
else
/* APN not configured on the card. Get the allowed CID range */
mm_serial_queue_command_cached (serial, "+CGDCONT=?", 3, cid_range_read, info);
mm_serial_port_queue_command_cached (port, "+CGDCONT=?", 3, cid_range_read, info);
}
static void
@@ -1092,23 +1245,25 @@ set_apn (MMModemGsmNetwork *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
mm_callback_info_set_data (info, "apn", g_strdup (apn), g_free);
/* Start by searching if the APN is already in card */
mm_serial_queue_command (MM_SERIAL (modem), "+CGDCONT?", 3, existing_apns_read, info);
mm_serial_port_queue_command (priv->primary, "+CGDCONT?", 3, existing_apns_read, info);
}
/* GetSignalQuality */
static void
get_signal_quality_done (MMSerial *serial,
get_signal_quality_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMGenericGsmPrivate *priv;
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
char *reply = response->str;
@@ -1127,7 +1282,8 @@ get_signal_quality_done (MMSerial *serial,
/* Normalize the quality */
quality = quality * 100 / 31;
MM_GENERIC_GSM_GET_PRIVATE (serial)->signal_quality = quality;
priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
priv->signal_quality = quality;
mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL);
} else
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
@@ -1142,23 +1298,26 @@ get_signal_quality (MMModemGsmNetwork *modem,
MMModemUIntFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
gboolean connected;
if (mm_serial_is_connected (MM_SERIAL (modem))) {
g_message ("Returning saved signal quality %d", MM_GENERIC_GSM_GET_PRIVATE (modem)->signal_quality);
callback (MM_MODEM (modem), MM_GENERIC_GSM_GET_PRIVATE (modem)->signal_quality, NULL, user_data);
connected = mm_serial_port_is_connected (priv->primary);
if (connected && !priv->secondary) {
g_message ("Returning saved signal quality %d", priv->signal_quality);
callback (MM_MODEM (modem), priv->signal_quality, NULL, user_data);
return;
}
info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
mm_serial_queue_command (MM_SERIAL (modem), "+CSQ", 3, get_signal_quality_done, info);
mm_serial_port_queue_command (connected ? priv->secondary : priv->primary, "+CSQ", 3, get_signal_quality_done, info);
}
/*****************************************************************************/
/* MMModemGsmSms interface */
static void
sms_send_done (MMSerial *serial,
sms_send_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -1181,16 +1340,33 @@ sms_send (MMModemGsmSms *modem,
MMModemFn callback,
gpointer user_data)
{
MMGenericGsmPrivate *priv;
MMCallbackInfo *info;
char *command;
gboolean connected;
MMSerialPort *port = NULL;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
connected = mm_serial_port_is_connected (priv->primary);
if (connected)
port = priv->secondary;
else
port = priv->primary;
if (!port) {
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"Cannot send SMS while connected");
mm_callback_info_schedule (info);
return;
}
/* FIXME: use the PDU mode instead */
mm_serial_queue_command (MM_SERIAL (modem), "AT+CMGF=1", 3, NULL, NULL);
mm_serial_port_queue_command (port, "AT+CMGF=1", 3, NULL, NULL);
command = g_strdup_printf ("+CMGS=\"%s\"\r%s\x1a", number, text);
mm_serial_queue_command (MM_SERIAL (modem), command, 10, sms_send_done, info);
mm_serial_port_queue_command (port, command, 10, sms_send_done, info);
g_free (command);
}
@@ -1441,6 +1617,9 @@ simple_get_status (MMModemSimple *simple,
static void
modem_init (MMModem *modem_class)
{
modem_class->owns_port = owns_port;
modem_class->grab_port = grab_port;
modem_class->release_port = release_port;
modem_class->enable = enable;
modem_class->connect = connect;
modem_class->disconnect = disconnect;
@@ -1484,16 +1663,6 @@ modem_simple_init (MMModemSimple *class)
static void
mm_generic_gsm_init (MMGenericGsm *self)
{
GRegex *regex;
mm_serial_set_response_parser (MM_SERIAL (self),
mm_serial_parser_v1_parse,
mm_serial_parser_v1_new (),
mm_serial_parser_v1_destroy);
regex = g_regex_new ("\\r\\n\\+CREG: (\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
mm_serial_add_unsolicited_msg_handler (MM_SERIAL (self), regex, reg_state_changed, NULL, NULL);
g_regex_unref (regex);
}
static void
@@ -1507,16 +1676,20 @@ set_property (GObject *object, guint prop_id,
/* Construct only */
priv->driver = g_value_dup_string (value);
break;
case MM_MODEM_PROP_DEVICE:
g_free (priv->data_device);
priv->data_device = g_value_dup_string (value);
case MM_MODEM_PROP_PLUGIN:
/* Construct only */
priv->plugin = g_value_dup_string (value);
break;
case MM_MODEM_PROP_TYPE:
priv->modem_type = g_value_get_uint (value);
case MM_MODEM_PROP_MASTER_DEVICE:
/* Constrcut only */
priv->device = g_value_dup_string (value);
break;
case MM_MODEM_PROP_IP_METHOD:
priv->ip_method = g_value_get_uint (value);
break;
case MM_MODEM_PROP_TYPE:
case MM_MODEM_PROP_VALID:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1530,21 +1703,30 @@ get_property (GObject *object, guint prop_id,
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (object);
switch (prop_id) {
case MM_MODEM_PROP_DEVICE:
if (priv->data_device)
g_value_set_string (value, priv->data_device);
case MM_MODEM_PROP_DATA_DEVICE:
if (priv->primary)
g_value_set_string (value, mm_serial_port_get_device (priv->primary));
else
g_value_set_string (value, mm_serial_get_device (MM_SERIAL (object)));
g_value_set_string (value, NULL);
break;
case MM_MODEM_PROP_MASTER_DEVICE:
g_value_set_string (value, priv->device);
break;
case MM_MODEM_PROP_DRIVER:
g_value_set_string (value, MM_GENERIC_GSM_GET_PRIVATE (object)->driver);
g_value_set_string (value, priv->driver);
break;
case MM_MODEM_PROP_PLUGIN:
g_value_set_string (value, priv->plugin);
break;
case MM_MODEM_PROP_TYPE:
g_value_set_uint (value, priv->modem_type);
g_value_set_uint (value, MM_MODEM_TYPE_GSM);
break;
case MM_MODEM_PROP_IP_METHOD:
g_value_set_uint (value, priv->ip_method);
break;
case MM_MODEM_PROP_VALID:
g_value_set_boolean (value, priv->valid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1581,13 +1763,21 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
/* Properties */
g_object_class_override_property (object_class,
MM_MODEM_PROP_DEVICE,
MM_MODEM_DEVICE);
MM_MODEM_PROP_DATA_DEVICE,
MM_MODEM_DATA_DEVICE);
g_object_class_override_property (object_class,
MM_MODEM_PROP_MASTER_DEVICE,
MM_MODEM_MASTER_DEVICE);
g_object_class_override_property (object_class,
MM_MODEM_PROP_DRIVER,
MM_MODEM_DRIVER);
g_object_class_override_property (object_class,
MM_MODEM_PROP_PLUGIN,
MM_MODEM_PLUGIN);
g_object_class_override_property (object_class,
MM_MODEM_PROP_TYPE,
MM_MODEM_TYPE);
@@ -1596,6 +1786,9 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
MM_MODEM_PROP_IP_METHOD,
MM_MODEM_IP_METHOD);
g_object_class_override_property (object_class,
MM_MODEM_PROP_VALID,
MM_MODEM_VALID);
}
GType
+9 -8
View File
@@ -6,12 +6,12 @@
#include "mm-modem-gsm-network.h"
#include "mm-serial.h"
#define MM_TYPE_GENERIC_GSM (mm_generic_gsm_get_type ())
#define MM_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsm))
#define MM_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
#define MM_IS_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_GSM))
#define MM_IS_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_GSM))
#define MM_GENERIC_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
#define MM_TYPE_GENERIC_GSM (mm_generic_gsm_get_type ())
#define MM_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsm))
#define MM_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
#define MM_IS_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_GSM))
#define MM_IS_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_GSM))
#define MM_GENERIC_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
typedef struct {
MMSerial parent;
@@ -23,8 +23,9 @@ typedef struct {
GType mm_generic_gsm_get_type (void);
MMModem *mm_generic_gsm_new (const char *serial_device,
const char *driver);
MMModem *mm_generic_gsm_new (const char *device,
const char *driver,
const char *plugin);
void mm_generic_gsm_set_unsolicited_registration (MMGenericGsm *modem,
gboolean enabled);
+164 -210
View File
@@ -2,12 +2,12 @@
#include <string.h>
#include <gmodule.h>
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
#include <gudev/gudev.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "mm-manager.h"
#include "mm-errors.h"
#include "mm-generic-gsm.h"
#include "mm-generic-cdma.h"
#include "mm-plugin.h"
static gboolean impl_manager_enumerate_devices (MMManager *manager,
@@ -29,9 +29,11 @@ static guint signals[LAST_SIGNAL] = { 0 };
#define MM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MANAGER, MMManagerPrivate))
#define DBUS_PATH_TAG "dbus-path"
typedef struct {
DBusGConnection *connection;
LibHalContext *hal_ctx;
GUdevClient *udev;
GSList *plugins;
GHashTable *modems;
} MMManagerPrivate;
@@ -147,169 +149,78 @@ mm_manager_new (DBusGConnection *bus)
return manager;
}
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 *
create_generic_modem (MMManager *manager, const char *udi)
static void
remove_modem (MMManager *manager, MMModem *modem)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
MMModem *modem;
char **capabilities;
char **iter;
char *serial_device;
char *driver;
gboolean type_gsm = FALSE;
gboolean type_cdma = FALSE;
char *device;
capabilities = libhal_device_get_property_strlist (priv->hal_ctx, udi, "modem.command_sets", NULL);
for (iter = capabilities; iter && *iter; iter++) {
if (!strcmp (*iter, "GSM-07.07")) {
type_gsm = TRUE;
break;
}
if (!strcmp (*iter, "IS-707-A")) {
type_cdma = TRUE;
break;
}
}
g_strfreev (capabilities);
device = mm_modem_get_device (modem);
g_assert (device);
g_debug ("Removed modem %s", device);
if (!type_gsm && !type_cdma)
return NULL;
serial_device = libhal_device_get_property_string (priv->hal_ctx, udi, "serial.device", NULL);
g_return_val_if_fail (serial_device != NULL, NULL);
driver = get_driver_name (priv->hal_ctx, udi);
g_return_val_if_fail (driver != NULL, NULL);
if (type_gsm)
modem = mm_generic_gsm_new (serial_device, driver);
else
modem = mm_generic_cdma_new (serial_device, driver);
g_free (serial_device);
g_free (driver);
if (modem)
g_debug ("Created new generic modem (%s)", udi);
else
g_warning ("Failed to create generic modem (%s)", udi);
return modem;
g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
g_hash_table_remove (priv->modems, device);
g_free (device);
}
static void
add_modem (MMManager *manager, const char *udi, MMModem *modem)
modem_valid (MMModem *modem, GParamSpec *pspec, gpointer user_data)
{
MMManager *manager = MM_MANAGER (user_data);
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
static guint32 id = 0;
char *path, *device;
g_hash_table_insert (priv->modems, g_strdup (udi), modem);
dbus_g_connection_register_g_object (priv->connection, udi, G_OBJECT (modem));
if (mm_modem_get_valid (modem)) {
path = g_strdup_printf (MM_DBUS_PATH"/Modems/%d", id++);
dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem));
g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free);
g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem);
}
device = mm_modem_get_device (modem);
g_assert (device);
g_debug ("Exported modem %s", device);
g_free (device);
static MMModem *
modem_exists (MMManager *manager, const char *udi)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
return (MMModem *) g_hash_table_lookup (priv->modems, udi);
g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem);
} else
remove_modem (manager, modem);
}
static void
create_initial_modems_from_plugins (MMManager *manager)
add_modem (MMManager *manager, MMModem *modem)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GSList *iter;
char *device;
gboolean valid = FALSE;
for (iter = priv->plugins; iter; iter = iter->next) {
MMPlugin *plugin = MM_PLUGIN (iter->data);
char **udis;
int i;
udis = mm_plugin_list_supported_udis (plugin, priv->hal_ctx);
if (udis) {
for (i = 0; udis[i]; i++) {
char *udi = udis[i];
MMModem *modem;
if (modem_exists (manager, udi)) {
g_warning ("Modem for UDI %s already exists, ignoring", udi);
continue;
}
modem = mm_plugin_create_modem (plugin, priv->hal_ctx, udi);
if (modem)
add_modem (manager, udi, modem);
}
g_strfreev (udis);
}
device = mm_modem_get_device (modem);
g_assert (device);
if (!g_hash_table_lookup (priv->modems, device)) {
g_hash_table_insert (priv->modems, g_strdup (device), modem);
g_debug ("Added modem %s", device);
g_signal_connect (modem, "notify::valid", G_CALLBACK (modem_valid), manager);
g_object_get (modem, MM_MODEM_VALID, &valid, NULL);
if (valid)
modem_valid (modem, NULL, manager);
}
}
static void
create_initial_modems_generic (MMManager *manager)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
char **devices;
int num_devices;
int i;
DBusError err;
dbus_error_init (&err);
devices = libhal_find_device_by_capability (priv->hal_ctx, "modem", &num_devices, &err);
if (dbus_error_is_set (&err)) {
g_warning ("Could not list HAL devices: %s", err.message);
dbus_error_free (&err);
}
if (devices) {
for (i = 0; i < num_devices; i++) {
char *udi = devices[i];
MMModem *modem;
if (modem_exists (manager, udi))
/* Already exists, most likely handled by a plugin */
continue;
modem = create_generic_modem (manager, udi);
if (modem)
add_modem (manager, g_strdup (udi), modem);
}
}
g_strfreev (devices);
}
static void
create_initial_modems (MMManager *manager)
{
create_initial_modems_from_plugins (manager);
create_initial_modems_generic (manager);
g_free (device);
}
static void
enumerate_devices_cb (gpointer key, gpointer val, gpointer user_data)
{
MMModem *modem = MM_MODEM (val);
GPtrArray **devices = (GPtrArray **) user_data;
const char *path;
gboolean valid = FALSE;
g_ptr_array_add (*devices, g_strdup ((char *) key));
g_object_get (G_OBJECT (modem), MM_MODEM_VALID, &valid, NULL);
if (valid) {
path = g_object_get_data (G_OBJECT (modem), DBUS_PATH_TAG);
g_return_if_fail (path != NULL);
g_ptr_array_add (*devices, g_strdup (path));
}
}
static gboolean
@@ -325,118 +236,164 @@ impl_manager_enumerate_devices (MMManager *manager,
return TRUE;
}
typedef struct {
MMModem *modem;
const char *subsys;
const char *name;
} FindPortInfo;
static void
device_added (LibHalContext *ctx, const char *udi)
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 *
find_modem_for_port (MMManager *manager, const char *subsys, const char *name)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
FindPortInfo info = { NULL, subsys, name };
g_hash_table_foreach (priv->modems, find_port, &info);
return info.modem;
}
static void
device_added (MMManager *manager, GUdevDevice *device)
{
MMManager *manager = MM_MANAGER (libhal_ctx_get_user_data (ctx));
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GSList *iter;
MMModem *modem = NULL;
const char *subsys, *name;
MMPlugin *best_plugin = NULL;
guint32 best_level = 0;
GError *error = NULL;
if (modem_exists (manager, udi))
/* Shouldn't happen */
g_return_if_fail (device != NULL);
subsys = g_udev_device_get_subsystem (device);
name = g_udev_device_get_name (device);
if (find_modem_for_port (manager, subsys, name))
return;
for (iter = priv->plugins; iter && modem == NULL; iter = iter->next) {
/* Build up the list of plugins that support this port */
for (iter = priv->plugins; iter; iter = iter->next) {
MMPlugin *plugin = MM_PLUGIN (iter->data);
guint32 level;
if (mm_plugin_supports_udi (plugin, ctx, udi)) {
modem = mm_plugin_create_modem (plugin, ctx, udi);
if (modem)
break;
level = mm_plugin_supports_port (plugin, subsys, name);
if (level > best_level) {
best_plugin = plugin;
best_level = level;
}
}
if (!modem)
/* None of the plugins supported the udi, try generic devices */
modem = create_generic_modem (manager, udi);
/* Let the best plugin handle this port */
if (!best_plugin)
return;
if (modem)
add_modem (manager, udi, modem);
}
static void
device_removed (LibHalContext *ctx, const char *udi)
{
MMManager *manager = MM_MANAGER (libhal_ctx_get_user_data (ctx));
MMModem *modem;
modem = modem_exists (manager, udi);
modem = mm_plugin_grab_port (best_plugin, subsys, name, &error);
if (modem) {
g_debug ("Removed modem %s", udi);
g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
g_hash_table_remove (MM_MANAGER_GET_PRIVATE (manager)->modems, udi);
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;
}
add_modem (manager, modem);
}
static void
device_new_capability (LibHalContext *ctx, const char *udi, const char *capability)
device_removed (MMManager *manager, GUdevDevice *device)
{
device_added (ctx, udi);
MMModem *modem;
const char *subsys, *name;
g_return_if_fail (device != NULL);
subsys = g_udev_device_get_subsystem (device);
name = g_udev_device_get_name (device);
modem = find_modem_for_port (manager, subsys, name);
if (modem)
mm_modem_release_port (modem, subsys, name);
}
DBusGConnection *
mm_manager_get_bus (MMManager *manager)
static void
handle_uevent (GUdevClient *client,
const char *action,
GUdevDevice *device,
gpointer user_data)
{
g_return_val_if_fail (MM_IS_MANAGER (manager), NULL);
MMManager *self = MM_MANAGER (user_data);
const char *subsys;
return MM_MANAGER_GET_PRIVATE (manager)->connection;
}
g_return_if_fail (action != NULL);
static gboolean
remove_one (gpointer key,
gpointer value,
gpointer user_data)
{
const char *udi = (char *) key;
MMModem *modem = MM_MODEM (value);
MMManager *manager = MM_MANAGER (user_data);
/* A bit paranoid */
subsys = g_udev_device_get_subsystem (device);
g_return_if_fail (subsys != NULL);
g_debug ("Removed modem %s", udi);
g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
g_return_if_fail (!strcmp (subsys, "tty") || !strcmp (subsys, "net"));
return TRUE;
if (!strcmp (action, "add"))
device_added (self, device);
else if (!strcmp (action, "remove"))
device_removed (self, device);
}
void
mm_manager_set_hal_ctx (MMManager *manager,
LibHalContext *hal_ctx)
mm_manager_start (MMManager *manager)
{
MMManagerPrivate *priv;
GList *devices, *iter;
g_return_if_fail (manager != NULL);
g_return_if_fail (MM_IS_MANAGER (manager));
priv = MM_MANAGER_GET_PRIVATE (manager);
priv->hal_ctx = hal_ctx;
if (hal_ctx) {
libhal_ctx_set_user_data (hal_ctx, manager);
libhal_ctx_set_device_added (hal_ctx, device_added);
libhal_ctx_set_device_removed (hal_ctx, device_removed);
libhal_ctx_set_device_new_capability (hal_ctx, device_new_capability);
devices = g_udev_client_query_by_subsystem (priv->udev, "tty");
for (iter = devices; iter; iter = g_list_next (iter))
device_added (manager, G_UDEV_DEVICE (iter->data));
create_initial_modems (manager);
} else {
g_hash_table_foreach_remove (priv->modems, remove_one, manager);
}
}
LibHalContext *
mm_manager_get_hal_ctx (MMManager *manager)
{
g_return_val_if_fail (MM_IS_MANAGER (manager), NULL);
return MM_MANAGER_GET_PRIVATE (manager)->hal_ctx;
devices = g_udev_client_query_by_subsystem (priv->udev, "net");
for (iter = devices; iter; iter = g_list_next (iter))
device_added (manager, G_UDEV_DEVICE (iter->data));
}
static void
mm_manager_init (MMManager *manager)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
const char *subsys[3] = { "tty", "net", NULL };
priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
load_plugins (manager);
priv->udev = g_udev_client_new (subsys);
g_assert (priv->udev);
g_signal_connect (priv->udev, "uevent", G_CALLBACK (handle_uevent), manager);
}
static void
@@ -449,11 +406,8 @@ finalize (GObject *object)
g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL);
g_slist_free (priv->plugins);
if (priv->hal_ctx) {
mm_manager_set_hal_ctx (MM_MANAGER (object), NULL);
libhal_ctx_shutdown (priv->hal_ctx, NULL);
libhal_ctx_free (priv->hal_ctx);
}
if (priv->udev)
g_object_unref (priv->udev);
if (priv->connection)
dbus_g_connection_unref (priv->connection);
+1 -5
View File
@@ -6,7 +6,6 @@
#include <glib/gtypes.h>
#include <glib-object.h>
#include <dbus/dbus-glib.h>
#include <libhal.h>
#include "mm-modem.h"
#define MM_TYPE_MANAGER (mm_manager_get_type ())
@@ -34,10 +33,7 @@ typedef struct {
GType mm_manager_get_type (void);
MMManager *mm_manager_new (DBusGConnection *bus);
DBusGConnection *mm_manager_get_bus (MMManager *manager);
void mm_manager_set_hal_ctx (MMManager *manager,
LibHalContext *hal_ctx);
LibHalContext *mm_manager_get_hal_ctx (MMManager *manager);
void mm_manager_start (MMManager *manager);
#endif /* MM_MANAGER_H */
+95 -2
View File
@@ -197,6 +197,75 @@ impl_modem_disconnect (MMModem *modem,
}
/*****************************************************************************/
gboolean
mm_modem_owns_port (MMModem *self,
const char *subsys,
const char *name)
{
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
g_return_val_if_fail (subsys, FALSE);
g_return_val_if_fail (name, FALSE);
g_assert (MM_MODEM_GET_INTERFACE (self)->owns_port);
return MM_MODEM_GET_INTERFACE (self)->owns_port (self, subsys, name);
}
gboolean
mm_modem_grab_port (MMModem *self,
const char *subsys,
const char *name,
GError **error)
{
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
g_return_val_if_fail (subsys, FALSE);
g_return_val_if_fail (name, FALSE);
g_assert (MM_MODEM_GET_INTERFACE (self)->grab_port);
return MM_MODEM_GET_INTERFACE (self)->grab_port (self, subsys, name, error);
}
void
mm_modem_release_port (MMModem *self,
const char *subsys,
const char *name)
{
g_return_if_fail (self != NULL);
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (subsys);
g_return_if_fail (name);
g_assert (MM_MODEM_GET_INTERFACE (self)->release_port);
MM_MODEM_GET_INTERFACE (self)->release_port (self, subsys, name);
}
gboolean
mm_modem_get_valid (MMModem *self)
{
gboolean valid = FALSE;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
g_object_get (G_OBJECT (self), MM_MODEM_VALID, &valid, NULL);
return valid;
}
char *
mm_modem_get_device (MMModem *self)
{
char *device;
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (MM_IS_MODEM (self), NULL);
g_object_get (G_OBJECT (self), MM_MODEM_MASTER_DEVICE, &device, NULL);
return device;
}
/*****************************************************************************/
static void
@@ -210,9 +279,17 @@ mm_modem_init (gpointer g_iface)
/* Properties */
g_object_interface_install_property
(g_iface,
g_param_spec_string (MM_MODEM_DEVICE,
"Device",
g_param_spec_string (MM_MODEM_DATA_DEVICE,
"Device",
"Data device",
NULL,
G_PARAM_READWRITE));
g_object_interface_install_property
(g_iface,
g_param_spec_string (MM_MODEM_MASTER_DEVICE,
"MasterDevice",
"Master modem parent device of all the modem's ports",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
@@ -224,6 +301,14 @@ mm_modem_init (gpointer g_iface)
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property
(g_iface,
g_param_spec_string (MM_MODEM_PLUGIN,
"Plugin",
"Plugin name",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property
(g_iface,
g_param_spec_uint (MM_MODEM_TYPE,
@@ -242,6 +327,14 @@ mm_modem_init (gpointer g_iface)
MM_MODEM_IP_METHOD_PPP,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property
(g_iface,
g_param_spec_boolean (MM_MODEM_VALID,
"Valid",
"Modem is valid",
FALSE,
G_PARAM_READABLE));
initialized = TRUE;
}
+45 -7
View File
@@ -10,13 +10,17 @@
#define MM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM))
#define MM_MODEM_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM, MMModem))
#define MM_MODEM_DEVICE "device"
#define MM_MODEM_DRIVER "driver"
#define MM_MODEM_TYPE "type"
#define MM_MODEM_IP_METHOD "ip-method"
#define MM_MODEM_DATA_DEVICE "device"
#define MM_MODEM_MASTER_DEVICE "master-device"
#define MM_MODEM_DRIVER "driver"
#define MM_MODEM_TYPE "type"
#define MM_MODEM_IP_METHOD "ip-method"
#define MM_MODEM_VALID "valid" /* not exported */
#define MM_MODEM_PLUGIN "plugin" /* not exported */
#define MM_MODEM_TYPE_GSM 1
#define MM_MODEM_TYPE_CDMA 2
#define MM_MODEM_TYPE_UNKNOWN 0
#define MM_MODEM_TYPE_GSM 1
#define MM_MODEM_TYPE_CDMA 2
#define MM_MODEM_IP_METHOD_PPP 0
#define MM_MODEM_IP_METHOD_STATIC 1
@@ -25,10 +29,13 @@
typedef enum {
MM_MODEM_PROP_FIRST = 0x1000,
MM_MODEM_PROP_DEVICE = MM_MODEM_PROP_FIRST,
MM_MODEM_PROP_DATA_DEVICE = MM_MODEM_PROP_FIRST,
MM_MODEM_PROP_MASTER_DEVICE,
MM_MODEM_PROP_DRIVER,
MM_MODEM_PROP_TYPE,
MM_MODEM_PROP_IP_METHOD,
MM_MODEM_PROP_VALID, /* Not exported */
MM_MODEM_PROP_PLUGIN, /* Not exported */
} MMModemProp;
typedef struct _MMModem MMModem;
@@ -57,6 +64,19 @@ struct _MMModem {
GTypeInterface g_iface;
/* Methods */
gboolean (*owns_port) (MMModem *self,
const char *subsys,
const char *name);
gboolean (*grab_port) (MMModem *self,
const char *subsys,
const char *name,
GError **error);
void (*release_port) (MMModem *self,
const char *subsys,
const char *name);
void (*enable) (MMModem *self,
gboolean enable,
MMModemFn callback,
@@ -78,6 +98,19 @@ struct _MMModem {
GType mm_modem_get_type (void);
gboolean mm_modem_owns_port (MMModem *self,
const char *subsys,
const char *name);
gboolean mm_modem_grab_port (MMModem *self,
const char *subsys,
const char *name,
GError **error);
void mm_modem_release_port (MMModem *self,
const char *subsys,
const char *name);
void mm_modem_enable (MMModem *self,
gboolean enable,
MMModemFn callback,
@@ -96,4 +129,9 @@ void mm_modem_disconnect (MMModem *self,
MMModemFn callback,
gpointer user_data);
gboolean mm_modem_get_valid (MMModem *self);
char *mm_modem_get_device (MMModem *self);
#endif /* MM_MODEM_H */
+15 -33
View File
@@ -10,49 +10,31 @@ mm_plugin_get_name (MMPlugin *plugin)
return MM_PLUGIN_GET_INTERFACE (plugin)->get_name (plugin);
}
char **
mm_plugin_list_supported_udis (MMPlugin *plugin,
LibHalContext *hal_ctx)
{
g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
g_return_val_if_fail (hal_ctx != NULL, NULL);
return MM_PLUGIN_GET_INTERFACE (plugin)->list_supported_udis (plugin, hal_ctx);
}
gboolean
mm_plugin_supports_udi (MMPlugin *plugin,
LibHalContext *hal_ctx,
const char *udi)
guint32
mm_plugin_supports_port (MMPlugin *plugin,
const char *subsys,
const char *name)
{
g_return_val_if_fail (MM_IS_PLUGIN (plugin), FALSE);
g_return_val_if_fail (hal_ctx != NULL, FALSE);
g_return_val_if_fail (udi != NULL, FALSE);
g_return_val_if_fail (subsys != NULL, FALSE);
g_return_val_if_fail (name != NULL, FALSE);
return MM_PLUGIN_GET_INTERFACE (plugin)->supports_udi (plugin, hal_ctx, udi);
return MM_PLUGIN_GET_INTERFACE (plugin)->supports_port (plugin, subsys, name);
}
MMModem *
mm_plugin_create_modem (MMPlugin *plugin,
LibHalContext *hal_ctx,
const char *udi)
mm_plugin_grab_port (MMPlugin *plugin,
const char *subsys,
const char *name,
GError **error)
{
MMModem *modem;
g_return_val_if_fail (MM_IS_PLUGIN (plugin), FALSE);
g_return_val_if_fail (subsys != NULL, FALSE);
g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
g_return_val_if_fail (hal_ctx != NULL, NULL);
g_return_val_if_fail (udi != NULL, NULL);
modem = MM_PLUGIN_GET_INTERFACE (plugin)->create_modem (plugin, hal_ctx, udi);
if (modem)
g_debug ("Created new %s modem (%s)", mm_plugin_get_name (plugin), udi);
else
g_warning ("Failed to create %s modem (%s)", mm_plugin_get_name (plugin), udi);
return modem;
return MM_PLUGIN_GET_INTERFACE (plugin)->grab_port (plugin, subsys, name, error);
}
/*****************************************************************************/
static void
+32 -22
View File
@@ -4,10 +4,9 @@
#define MM_PLUGIN_H
#include <glib-object.h>
#include <libhal.h>
#include <mm-modem.h>
#define MM_PLUGIN_MAJOR_VERSION 1
#define MM_PLUGIN_MAJOR_VERSION 2
#define MM_PLUGIN_MINOR_VERSION 0
#define MM_TYPE_PLUGIN (mm_plugin_get_type ())
@@ -23,33 +22,44 @@ struct _MMPlugin {
GTypeInterface g_iface;
/* Methods */
const char *(*get_name) (MMPlugin *self);
const char *(*get_name) (MMPlugin *self);
char **(*list_supported_udis) (MMPlugin *self,
LibHalContext *hal_ctx);
/* Check whether a plugin supports a particular modem port, and what level
* of support the plugin has for the device. The plugin should return a
* value between 0 and 100 inclusive, where 0 means the plugin has no
* support for the device, and 100 means the plugin has full support for the
* device.
*/
guint32 (*supports_port) (MMPlugin *self,
const char *subsys,
const char *name);
gboolean (*supports_udi) (MMPlugin *self,
LibHalContext *hal_ctx,
const char *udi);
MMModem *(*create_modem) (MMPlugin *self,
LibHalContext *hal_ctx,
const char *udi);
/* 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
* return a new modem for the port's device if there is no existing modem
* to handle the port's hardware device, or should add the port to an
* existing modem and return that modem object. If an error is encountered
* while claiming the port, the error information should be returned in the
* error argument, and the plugin should return NULL.
*/
MMModem * (*grab_port) (MMPlugin *self,
const char *subsys,
const char *name,
GError **error);
};
GType mm_plugin_get_type (void);
const char *mm_plugin_get_name (MMPlugin *plugin);
const char *mm_plugin_get_name (MMPlugin *plugin);
char **mm_plugin_list_supported_udis (MMPlugin *plugin,
LibHalContext *hal_ctx);
guint32 mm_plugin_supports_port (MMPlugin *plugin,
const char *subsys,
const char *name);
gboolean mm_plugin_supports_udi (MMPlugin *plugin,
LibHalContext *hal_ctx,
const char *udi);
MMModem *mm_plugin_create_modem (MMPlugin *plugin,
LibHalContext *hal_ctx,
const char *udi);
MMModem *mm_plugin_grab_port (MMPlugin *plugin,
const char *subsys,
const char *name,
GError **error);
#endif /* MM_PLUGIN_H */
+1107
View File
File diff suppressed because it is too large Load Diff
+114
View File
@@ -0,0 +1,114 @@
/* -*- 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_SERIAL_PORT_H
#define MM_SERIAL_PORT_H
#include <glib.h>
#include <glib/gtypes.h>
#include <glib-object.h>
typedef enum {
MM_SERIAL_PORT_TYPE_UNKNOWN = 0x0,
MM_SERIAL_PORT_TYPE_PRIMARY,
MM_SERIAL_PORT_TYPE_SECONDARY,
MM_SERIAL_PORT_TYPE_IGNORED
} MMSerialPortType;
#define MM_TYPE_SERIAL_PORT (mm_serial_port_get_type ())
#define MM_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SERIAL_PORT, MMSerialPort))
#define MM_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SERIAL_PORT, MMSerialPortClass))
#define MM_IS_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SERIAL_PORT))
#define MM_IS_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SERIAL_PORT))
#define MM_SERIAL_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SERIAL_PORT, MMSerialPortClass))
#define MM_SERIAL_PORT_DEVICE "serial-device"
#define MM_SERIAL_PORT_BAUD "baud"
#define MM_SERIAL_PORT_BITS "bits"
#define MM_SERIAL_PORT_PARITY "parity"
#define MM_SERIAL_PORT_STOPBITS "stopbits"
#define MM_SERIAL_PORT_SEND_DELAY "send-delay"
#define MM_SERIAL_PORT_CARRIER_DETECT "carrier-detect"
typedef struct _MMSerialPort MMSerialPort;
typedef struct _MMSerialPortClass MMSerialPortClass;
typedef gboolean (*MMSerialResponseParserFn) (gpointer user_data,
GString *response,
GError **error);
typedef void (*MMSerialUnsolicitedMsgFn) (MMSerialPort *port,
GMatchInfo *match_info,
gpointer user_data);
typedef void (*MMSerialResponseFn) (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data);
typedef void (*MMSerialFlashFn) (MMSerialPort *port,
gpointer user_data);
struct _MMSerialPort {
GObject parent;
};
struct _MMSerialPortClass {
GObjectClass parent;
};
GType mm_serial_port_get_type (void);
MMSerialPort *mm_serial_port_new (const char *name);
void mm_serial_port_add_unsolicited_msg_handler (MMSerialPort *self,
GRegex *regex,
MMSerialUnsolicitedMsgFn callback,
gpointer user_data,
GDestroyNotify notify);
void mm_serial_port_set_response_parser (MMSerialPort *self,
MMSerialResponseParserFn fn,
gpointer user_data,
GDestroyNotify notify);
gboolean mm_serial_port_open (MMSerialPort *self,
GError **error);
void mm_serial_port_close (MMSerialPort *self);
void mm_serial_port_queue_command (MMSerialPort *self,
const char *command,
guint32 timeout_seconds,
MMSerialResponseFn callback,
gpointer user_data);
void mm_serial_port_queue_command_cached (MMSerialPort *self,
const char *command,
guint32 timeout_seconds,
MMSerialResponseFn callback,
gpointer user_data);
guint mm_serial_port_flash (MMSerialPort *self,
guint32 flash_time,
MMSerialFlashFn callback,
gpointer user_data);
gboolean mm_serial_port_is_connected (MMSerialPort *self);
const char *mm_serial_port_get_device (MMSerialPort *self);
#endif /* MM_SERIAL_PORT_H */
+52 -978
View File
File diff suppressed because it is too large Load Diff
+24 -56
View File
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2008 - 2009 Novell, Inc.
* Copyright (C) 2009 Red Hat, Inc.
*/
#ifndef MM_SERIAL_H
#define MM_SERIAL_H
@@ -7,6 +21,8 @@
#include <glib/gtypes.h>
#include <glib-object.h>
#include "mm-serial-port.h"
#define MM_TYPE_SERIAL (mm_serial_get_type ())
#define MM_SERIAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SERIAL, MMSerial))
#define MM_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SERIAL, MMSerialClass))
@@ -14,33 +30,9 @@
#define MM_IS_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SERIAL))
#define MM_SERIAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SERIAL, MMSerialClass))
#define MM_SERIAL_DEVICE "serial-device"
#define MM_SERIAL_BAUD "baud"
#define MM_SERIAL_BITS "bits"
#define MM_SERIAL_PARITY "parity"
#define MM_SERIAL_STOPBITS "stopbits"
#define MM_SERIAL_SEND_DELAY "send-delay"
#define MM_SERIAL_CARRIER_DETECT "carrier-detect"
typedef struct _MMSerial MMSerial;
typedef struct _MMSerialClass MMSerialClass;
typedef gboolean (*MMSerialResponseParserFn) (gpointer user_data,
GString *response,
GError **error);
typedef void (*MMSerialUnsolicitedMsgFn) (MMSerial *serial,
GMatchInfo *match_info,
gpointer user_data);
typedef void (*MMSerialResponseFn) (MMSerial *serial,
GString *response,
GError *error,
gpointer user_data);
typedef void (*MMSerialFlashFn) (MMSerial *serial,
gpointer user_data);
struct _MMSerial {
GObject parent;
};
@@ -51,39 +43,15 @@ struct _MMSerialClass {
GType mm_serial_get_type (void);
void mm_serial_add_unsolicited_msg_handler (MMSerial *self,
GRegex *regex,
MMSerialUnsolicitedMsgFn callback,
gpointer user_data,
GDestroyNotify notify);
MMSerialPort *mm_serial_get_port (MMSerial *self,
const char *name);
void mm_serial_set_response_parser (MMSerial *self,
MMSerialResponseParserFn fn,
gpointer user_data,
GDestroyNotify notify);
MMSerialPort *mm_serial_add_port (MMSerial *self,
const char *name,
MMSerialPortType ptype);
gboolean mm_serial_open (MMSerial *self,
GError **error);
void mm_serial_close (MMSerial *self);
void mm_serial_queue_command (MMSerial *self,
const char *command,
guint32 timeout_seconds,
MMSerialResponseFn callback,
gpointer user_data);
void mm_serial_queue_command_cached (MMSerial *self,
const char *command,
guint32 timeout_seconds,
MMSerialResponseFn callback,
gpointer user_data);
guint mm_serial_flash (MMSerial *self,
guint32 flash_time,
MMSerialFlashFn callback,
gpointer user_data);
gboolean mm_serial_is_connected (MMSerial *self);
const char *mm_serial_get_device (MMSerial *self);
gboolean mm_serial_remove_port (MMSerial *self,
MMSerialPort *port);
#endif /* MM_SERIAL_H */