port-serial: allow ports based on Unix sockets
This commit is contained in:
@@ -503,7 +503,9 @@ MMPortSerialAt *
|
|||||||
mm_port_serial_at_new (const char *name,
|
mm_port_serial_at_new (const char *name,
|
||||||
MMPortSubsys subsys)
|
MMPortSubsys subsys)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (subsys == MM_PORT_SUBSYS_TTY || subsys == MM_PORT_SUBSYS_USB, NULL);
|
g_return_val_if_fail (subsys == MM_PORT_SUBSYS_TTY ||
|
||||||
|
subsys == MM_PORT_SUBSYS_USB ||
|
||||||
|
subsys == MM_PORT_SUBSYS_UNIX, NULL);
|
||||||
|
|
||||||
return MM_PORT_SERIAL_AT (g_object_new (MM_TYPE_PORT_SERIAL_AT,
|
return MM_PORT_SERIAL_AT (g_object_new (MM_TYPE_PORT_SERIAL_AT,
|
||||||
MM_PORT_DEVICE, name,
|
MM_PORT_DEVICE, name,
|
||||||
|
@@ -28,6 +28,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
|
|
||||||
|
#include <gio/gunixsocketaddress.h>
|
||||||
|
|
||||||
#include <ModemManager.h>
|
#include <ModemManager.h>
|
||||||
#include <mm-errors-types.h>
|
#include <mm-errors-types.h>
|
||||||
|
|
||||||
@@ -77,10 +79,17 @@ struct _MMPortSerialPrivate {
|
|||||||
gboolean forced_close;
|
gboolean forced_close;
|
||||||
int fd;
|
int fd;
|
||||||
GHashTable *reply_cache;
|
GHashTable *reply_cache;
|
||||||
GIOChannel *iochannel;
|
|
||||||
GQueue *queue;
|
GQueue *queue;
|
||||||
GByteArray *response;
|
GByteArray *response;
|
||||||
|
|
||||||
|
/* For real ports, iochannel, and we implement the eagain limit */
|
||||||
|
GIOChannel *iochannel;
|
||||||
|
guint iochannel_id;
|
||||||
|
|
||||||
|
/* For unix-socket based ports, socket */
|
||||||
|
GSocket *socket;
|
||||||
|
GSource *socket_source;
|
||||||
|
|
||||||
struct termios old_t;
|
struct termios old_t;
|
||||||
|
|
||||||
guint baud;
|
guint baud;
|
||||||
@@ -93,7 +102,6 @@ struct _MMPortSerialPrivate {
|
|||||||
gboolean flash_ok;
|
gboolean flash_ok;
|
||||||
|
|
||||||
guint queue_id;
|
guint queue_id;
|
||||||
guint watch_id;
|
|
||||||
guint timeout_id;
|
guint timeout_id;
|
||||||
|
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
@@ -527,9 +535,8 @@ port_serial_process_command (MMPortSerial *self,
|
|||||||
const gchar *p;
|
const gchar *p;
|
||||||
gsize written;
|
gsize written;
|
||||||
gssize send_len;
|
gssize send_len;
|
||||||
GIOStatus write_status;
|
|
||||||
|
|
||||||
if (self->priv->fd < 0 || self->priv->iochannel == NULL) {
|
if (self->priv->iochannel == NULL && self->priv->socket == NULL) {
|
||||||
g_set_error_literal (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_SEND_FAILED,
|
g_set_error_literal (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_SEND_FAILED,
|
||||||
"Sending command failed: device is not enabled");
|
"Sending command failed: device is not enabled");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -557,40 +564,81 @@ port_serial_process_command (MMPortSerial *self,
|
|||||||
p = (gchar *)&ctx->command->data[ctx->idx];
|
p = (gchar *)&ctx->command->data[ctx->idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send N bytes of the command */
|
/* GIOChannel based setup */
|
||||||
write_status = g_io_channel_write_chars (self->priv->iochannel, p, send_len, &written, error);
|
if (self->priv->iochannel) {
|
||||||
switch (write_status) {
|
GIOStatus write_status;
|
||||||
case G_IO_STATUS_ERROR:
|
|
||||||
g_prefix_error (error, "Sending command failed: ");
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
case G_IO_STATUS_EOF:
|
/* Send N bytes of the command */
|
||||||
/* We shouldn't get EOF when writing */
|
write_status = g_io_channel_write_chars (self->priv->iochannel, p, send_len, &written, error);
|
||||||
g_assert_not_reached ();
|
switch (write_status) {
|
||||||
break;
|
case G_IO_STATUS_ERROR:
|
||||||
|
g_prefix_error (error, "Sending command failed: ");
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
case G_IO_STATUS_NORMAL:
|
case G_IO_STATUS_EOF:
|
||||||
if (written > 0) {
|
/* We shouldn't get EOF when writing */
|
||||||
ctx->idx += written;
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case G_IO_STATUS_NORMAL:
|
||||||
|
if (written > 0) {
|
||||||
|
ctx->idx += written;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* If written == 0, treat as EAGAIN, so fall down */
|
||||||
|
|
||||||
|
case G_IO_STATUS_AGAIN:
|
||||||
|
/* We're in a non-blocking channel and therefore we're up to receive
|
||||||
|
* EAGAIN; just retry in this case. */
|
||||||
|
ctx->eagain_count--;
|
||||||
|
if (ctx->eagain_count <= 0) {
|
||||||
|
/* If we reach the limit of EAGAIN errors, treat as a timeout error. */
|
||||||
|
self->priv->n_consecutive_timeouts++;
|
||||||
|
g_signal_emit (self, signals[TIMED_OUT], 0, self->priv->n_consecutive_timeouts);
|
||||||
|
|
||||||
|
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_SEND_FAILED,
|
||||||
|
"Sending command failed: '%s'", strerror (errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* If written == 0, treat as EAGAIN, so fall down */
|
|
||||||
|
|
||||||
case G_IO_STATUS_AGAIN:
|
|
||||||
/* We're in a non-blocking channel and therefore we're up to receive
|
|
||||||
* EAGAIN; just retry in this case. */
|
|
||||||
ctx->eagain_count--;
|
|
||||||
if (ctx->eagain_count <= 0) {
|
|
||||||
/* If we reach the limit of EAGAIN errors, treat as a timeout error. */
|
|
||||||
self->priv->n_consecutive_timeouts++;
|
|
||||||
g_signal_emit (self, signals[TIMED_OUT], 0, self->priv->n_consecutive_timeouts);
|
|
||||||
|
|
||||||
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_SEND_FAILED,
|
|
||||||
"Sending command failed: '%s'", strerror (errno));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
/* Socket based setup */
|
||||||
|
else if (self->priv->socket) {
|
||||||
|
GError *inner_error = NULL;
|
||||||
|
|
||||||
|
/* Send N bytes of the command */
|
||||||
|
written = g_socket_send (self->priv->socket, p, send_len, NULL, &inner_error);
|
||||||
|
if (written < 0) {
|
||||||
|
/* Non-EWOULDBLOCK error? */
|
||||||
|
if (!g_error_matches (inner_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
||||||
|
g_propagate_error (error, inner_error);
|
||||||
|
g_prefix_error (error, "Sending command failed: ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're in a non-blocking socket and therefore we're up to receive
|
||||||
|
* EWOULDBLOCK; just retry in this case. */
|
||||||
|
|
||||||
|
g_error_free (inner_error);
|
||||||
|
|
||||||
|
ctx->eagain_count--;
|
||||||
|
if (ctx->eagain_count <= 0) {
|
||||||
|
/* If we reach the limit of EAGAIN errors, treat as a timeout error. */
|
||||||
|
self->priv->n_consecutive_timeouts++;
|
||||||
|
g_signal_emit (self, signals[TIMED_OUT], 0, self->priv->n_consecutive_timeouts);
|
||||||
|
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_SEND_FAILED,
|
||||||
|
"Sending command failed: '%s'", strerror (errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just keep on, will retry... */
|
||||||
|
written = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->idx += written;
|
||||||
|
} else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
|
||||||
if (ctx->idx >= ctx->command->len)
|
if (ctx->idx >= ctx->command->len)
|
||||||
ctx->done = TRUE;
|
ctx->done = TRUE;
|
||||||
@@ -824,11 +872,9 @@ parse_response (MMPortSerial *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
data_available (GIOChannel *source,
|
common_input_available (MMPortSerial *self,
|
||||||
GIOCondition condition,
|
GIOCondition condition)
|
||||||
gpointer data)
|
|
||||||
{
|
{
|
||||||
MMPortSerial *self = MM_PORT_SERIAL (data);
|
|
||||||
char buf[SERIAL_BUF_SIZE + 1];
|
char buf[SERIAL_BUF_SIZE + 1];
|
||||||
gsize bytes_read;
|
gsize bytes_read;
|
||||||
GIOStatus status;
|
GIOStatus status;
|
||||||
@@ -859,17 +905,44 @@ data_available (GIOChannel *source,
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
bytes_read = 0;
|
bytes_read = 0;
|
||||||
status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &error);
|
|
||||||
if (status == G_IO_STATUS_ERROR) {
|
if (self->priv->iochannel) {
|
||||||
if (error) {
|
status = g_io_channel_read_chars (self->priv->iochannel,
|
||||||
mm_warn ("(%s): read error: %s",
|
buf,
|
||||||
|
SERIAL_BUF_SIZE,
|
||||||
|
&bytes_read,
|
||||||
|
&error);
|
||||||
|
if (status == G_IO_STATUS_ERROR) {
|
||||||
|
if (error) {
|
||||||
|
mm_warn ("(%s): read error: %s",
|
||||||
|
mm_port_get_device (MM_PORT (self)),
|
||||||
|
error->message);
|
||||||
|
}
|
||||||
|
g_clear_error (&error);
|
||||||
|
}
|
||||||
|
} else if (self->priv->socket) {
|
||||||
|
bytes_read = g_socket_receive (self->priv->socket,
|
||||||
|
buf,
|
||||||
|
SERIAL_BUF_SIZE,
|
||||||
|
NULL, /* cancellable */
|
||||||
|
&error);
|
||||||
|
if (bytes_read == -1) {
|
||||||
|
bytes_read = 0;
|
||||||
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
|
||||||
|
status = G_IO_STATUS_AGAIN;
|
||||||
|
else
|
||||||
|
status = G_IO_STATUS_ERROR;
|
||||||
|
mm_warn ("(%s): receive error: %s",
|
||||||
mm_port_get_device (MM_PORT (self)),
|
mm_port_get_device (MM_PORT (self)),
|
||||||
error->message);
|
error->message);
|
||||||
}
|
g_clear_error (&error);
|
||||||
g_clear_error (&error);
|
} else
|
||||||
|
status = G_IO_STATUS_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no bytes read, just let g_io_channel wait for more data */
|
|
||||||
|
|
||||||
|
/* If no bytes read, just wait for more data */
|
||||||
if (bytes_read == 0)
|
if (bytes_read == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -894,28 +967,64 @@ data_available (GIOChannel *source,
|
|||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
}
|
}
|
||||||
} while ( (bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN)
|
} while ( (bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN)
|
||||||
&& (self->priv->watch_id > 0));
|
&& (self->priv->iochannel_id > 0 || self->priv->socket_source != NULL));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
iochannel_input_available (GIOChannel *iochannel,
|
||||||
|
GIOCondition condition,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
return common_input_available (MM_PORT_SERIAL (data), condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
socket_input_available (GSocket *socket,
|
||||||
|
GIOCondition condition,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
return common_input_available (MM_PORT_SERIAL (data), condition);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
data_watch_enable (MMPortSerial *self, gboolean enable)
|
data_watch_enable (MMPortSerial *self, gboolean enable)
|
||||||
{
|
{
|
||||||
if (self->priv->watch_id) {
|
if (self->priv->iochannel_id) {
|
||||||
if (enable)
|
if (enable)
|
||||||
g_warn_if_fail (self->priv->watch_id == 0);
|
g_warn_if_fail (self->priv->iochannel_id == 0);
|
||||||
|
|
||||||
g_source_remove (self->priv->watch_id);
|
g_source_remove (self->priv->iochannel_id);
|
||||||
self->priv->watch_id = 0;
|
self->priv->iochannel_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->priv->socket_source) {
|
||||||
|
if (enable)
|
||||||
|
g_warn_if_fail (self->priv->socket_source == NULL);
|
||||||
|
g_source_destroy (self->priv->socket_source);
|
||||||
|
g_source_unref (self->priv->socket_source);
|
||||||
|
self->priv->socket_source = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
g_return_if_fail (self->priv->iochannel != NULL);
|
if (self->priv->iochannel) {
|
||||||
self->priv->watch_id = g_io_add_watch (self->priv->iochannel,
|
self->priv->iochannel_id = g_io_add_watch (self->priv->iochannel,
|
||||||
G_IO_IN | G_IO_ERR | G_IO_HUP,
|
G_IO_IN | G_IO_ERR | G_IO_HUP,
|
||||||
data_available,
|
iochannel_input_available,
|
||||||
self);
|
self);
|
||||||
|
} else if (self->priv->socket) {
|
||||||
|
self->priv->socket_source = g_socket_create_source (self->priv->socket,
|
||||||
|
G_IO_IN | G_IO_ERR | G_IO_HUP,
|
||||||
|
NULL);
|
||||||
|
g_source_set_callback (self->priv->socket_source,
|
||||||
|
(GSourceFunc)socket_input_available,
|
||||||
|
self,
|
||||||
|
NULL);
|
||||||
|
g_source_attach (self->priv->socket_source, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
g_warn_if_reached ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,7 +1033,7 @@ port_connected (MMPortSerial *self, GParamSpec *pspec, gpointer user_data)
|
|||||||
{
|
{
|
||||||
gboolean connected;
|
gboolean connected;
|
||||||
|
|
||||||
if (self->priv->fd < 0)
|
if (!self->priv->iochannel && !self->priv->socket)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* When the port is connected, drop the serial port lock so PPP can do
|
/* When the port is connected, drop the serial port lock so PPP can do
|
||||||
@@ -933,7 +1042,7 @@ port_connected (MMPortSerial *self, GParamSpec *pspec, gpointer user_data)
|
|||||||
*/
|
*/
|
||||||
connected = mm_port_get_connected (MM_PORT (self));
|
connected = mm_port_get_connected (MM_PORT (self));
|
||||||
|
|
||||||
if (ioctl (self->priv->fd, (connected ? TIOCNXCL : TIOCEXCL)) < 0) {
|
if (self->priv->fd >= 0 && ioctl (self->priv->fd, (connected ? TIOCNXCL : TIOCEXCL)) < 0) {
|
||||||
mm_warn ("(%s): could not %s serial port lock: (%d) %s",
|
mm_warn ("(%s): could not %s serial port lock: (%d) %s",
|
||||||
mm_port_get_device (MM_PORT (self)),
|
mm_port_get_device (MM_PORT (self)),
|
||||||
connected ? "drop" : "re-acquire",
|
connected ? "drop" : "re-acquire",
|
||||||
@@ -989,26 +1098,29 @@ mm_port_serial_open (MMPortSerial *self, GError **error)
|
|||||||
|
|
||||||
g_get_current_time (&tv_start);
|
g_get_current_time (&tv_start);
|
||||||
|
|
||||||
/* Only open a new file descriptor if we weren't given one already */
|
/* Non-socket setup needs the fd open */
|
||||||
if (self->priv->fd < 0) {
|
if (mm_port_get_subsys (MM_PORT (self)) != MM_PORT_SUBSYS_UNIX) {
|
||||||
devfile = g_strdup_printf ("/dev/%s", device);
|
/* Only open a new file descriptor if we weren't given one already */
|
||||||
errno = 0;
|
if (self->priv->fd < 0) {
|
||||||
self->priv->fd = open (devfile, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
|
devfile = g_strdup_printf ("/dev/%s", device);
|
||||||
errno_save = errno;
|
errno = 0;
|
||||||
g_free (devfile);
|
self->priv->fd = open (devfile, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
|
||||||
}
|
errno_save = errno;
|
||||||
|
g_free (devfile);
|
||||||
|
}
|
||||||
|
|
||||||
if (self->priv->fd < 0) {
|
if (self->priv->fd < 0) {
|
||||||
/* nozomi isn't ready yet when the port appears, and it'll return
|
/* nozomi isn't ready yet when the port appears, and it'll return
|
||||||
* ENODEV when open(2) is called on it. Make sure we can handle this
|
* ENODEV when open(2) is called on it. Make sure we can handle this
|
||||||
* by returning a special error in that case.
|
* by returning a special error in that case.
|
||||||
*/
|
*/
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
MM_SERIAL_ERROR,
|
MM_SERIAL_ERROR,
|
||||||
(errno == ENODEV) ? MM_SERIAL_ERROR_OPEN_FAILED_NO_DEVICE : MM_SERIAL_ERROR_OPEN_FAILED,
|
(errno == ENODEV) ? MM_SERIAL_ERROR_OPEN_FAILED_NO_DEVICE : MM_SERIAL_ERROR_OPEN_FAILED,
|
||||||
"Could not open serial device %s: %s", device, strerror (errno_save));
|
"Could not open serial device %s: %s", device, strerror (errno_save));
|
||||||
mm_warn ("(%s) could not open serial device (%d)", device, errno_save);
|
mm_warn ("(%s) could not open serial device (%d)", device, errno_save);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Serial port specific setup */
|
/* Serial port specific setup */
|
||||||
@@ -1046,7 +1158,7 @@ mm_port_serial_open (MMPortSerial *self, GError **error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_warn_if_fail (MM_PORT_SERIAL_GET_CLASS (self)->config_fd);
|
g_warn_if_fail (MM_PORT_SERIAL_GET_CLASS (self)->config_fd);
|
||||||
if (!MM_PORT_SERIAL_GET_CLASS (self)->config_fd (self, self->priv->fd, error)) {
|
if (self->priv->fd >= 0 && !MM_PORT_SERIAL_GET_CLASS (self)->config_fd (self, self->priv->fd, error)) {
|
||||||
mm_dbg ("(%s) failed to configure serial device", device);
|
mm_dbg ("(%s) failed to configure serial device", device);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -1056,21 +1168,57 @@ mm_port_serial_open (MMPortSerial *self, GError **error)
|
|||||||
if (tv_end.tv_sec - tv_start.tv_sec > 7)
|
if (tv_end.tv_sec - tv_start.tv_sec > 7)
|
||||||
mm_warn ("(%s): open blocked by driver for more than 7 seconds!", device);
|
mm_warn ("(%s): open blocked by driver for more than 7 seconds!", device);
|
||||||
|
|
||||||
/* Create new GIOChannel */
|
if (mm_port_get_subsys (MM_PORT (self)) != MM_PORT_SUBSYS_UNIX) {
|
||||||
self->priv->iochannel = g_io_channel_unix_new (self->priv->fd);
|
/* Create new GIOChannel */
|
||||||
|
self->priv->iochannel = g_io_channel_unix_new (self->priv->fd);
|
||||||
|
|
||||||
/* We don't want UTF-8 encoding, we're playing with raw binary data */
|
/* We don't want UTF-8 encoding, we're playing with raw binary data */
|
||||||
g_io_channel_set_encoding (self->priv->iochannel, NULL, NULL);
|
g_io_channel_set_encoding (self->priv->iochannel, NULL, NULL);
|
||||||
|
|
||||||
/* We don't want to get the channel buffered */
|
/* We don't want to get the channel buffered */
|
||||||
g_io_channel_set_buffered (self->priv->iochannel, FALSE);
|
g_io_channel_set_buffered (self->priv->iochannel, FALSE);
|
||||||
|
|
||||||
/* We don't want to get blocked while writing stuff */
|
/* We don't want to get blocked while writing stuff */
|
||||||
if (!g_io_channel_set_flags (self->priv->iochannel,
|
if (!g_io_channel_set_flags (self->priv->iochannel,
|
||||||
G_IO_FLAG_NONBLOCK,
|
G_IO_FLAG_NONBLOCK,
|
||||||
error)) {
|
error)) {
|
||||||
g_prefix_error (error, "Cannot set non-blocking channel: ");
|
g_prefix_error (error, "Cannot set non-blocking channel: ");
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GSocketAddress *address;
|
||||||
|
|
||||||
|
/* Create new GSocket */
|
||||||
|
self->priv->socket = g_socket_new (G_SOCKET_FAMILY_UNIX,
|
||||||
|
G_SOCKET_TYPE_STREAM,
|
||||||
|
G_SOCKET_PROTOCOL_DEFAULT,
|
||||||
|
error);
|
||||||
|
if (!self->priv->socket) {
|
||||||
|
g_prefix_error (error, "Cannot create socket: ");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Non-blocking socket */
|
||||||
|
g_socket_set_blocking (self->priv->socket, FALSE);
|
||||||
|
|
||||||
|
/* By default, abstract socket */
|
||||||
|
address = (g_unix_socket_address_new_with_type (
|
||||||
|
device,
|
||||||
|
-1,
|
||||||
|
(g_str_has_prefix (device, "abstract:") ?
|
||||||
|
G_UNIX_SOCKET_ADDRESS_ABSTRACT :
|
||||||
|
G_UNIX_SOCKET_ADDRESS_PATH)));
|
||||||
|
|
||||||
|
/* Connect to address */
|
||||||
|
if (!g_socket_connect (self->priv->socket,
|
||||||
|
address,
|
||||||
|
NULL,
|
||||||
|
error)) {
|
||||||
|
g_prefix_error (error, "Cannot connect socket: ");
|
||||||
|
g_object_unref (address);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
g_object_unref (address);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reading watch enable */
|
/* Reading watch enable */
|
||||||
@@ -1101,8 +1249,17 @@ error:
|
|||||||
self->priv->iochannel = NULL;
|
self->priv->iochannel = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
close (self->priv->fd);
|
if (self->priv->socket) {
|
||||||
self->priv->fd = -1;
|
g_socket_close (self->priv->socket, NULL);
|
||||||
|
g_object_unref (self->priv->socket);
|
||||||
|
self->priv->socket = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->priv->fd >= 0) {
|
||||||
|
close (self->priv->fd);
|
||||||
|
self->priv->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1146,7 +1303,7 @@ mm_port_serial_close (MMPortSerial *self)
|
|||||||
|
|
||||||
mm_port_serial_flash_cancel (self);
|
mm_port_serial_flash_cancel (self);
|
||||||
|
|
||||||
if (self->priv->fd >= 0) {
|
if (self->priv->iochannel || self->priv->socket) {
|
||||||
GTimeVal tv_start, tv_end;
|
GTimeVal tv_start, tv_end;
|
||||||
struct serial_struct sinfo = { 0 };
|
struct serial_struct sinfo = { 0 };
|
||||||
|
|
||||||
@@ -1157,7 +1314,7 @@ mm_port_serial_close (MMPortSerial *self)
|
|||||||
g_get_current_time (&tv_start);
|
g_get_current_time (&tv_start);
|
||||||
|
|
||||||
/* Serial port specific setup */
|
/* Serial port specific setup */
|
||||||
if (mm_port_get_subsys (MM_PORT (self)) == MM_PORT_SUBSYS_TTY) {
|
if (self->priv->fd >= 0 && mm_port_get_subsys (MM_PORT (self)) == MM_PORT_SUBSYS_TTY) {
|
||||||
/* Paranoid: ensure our closing_wait value is still set so we ignore
|
/* Paranoid: ensure our closing_wait value is still set so we ignore
|
||||||
* pending data when closing the port. See GNOME bug #630670.
|
* pending data when closing the port. See GNOME bug #630670.
|
||||||
*/
|
*/
|
||||||
@@ -1183,8 +1340,19 @@ mm_port_serial_close (MMPortSerial *self)
|
|||||||
self->priv->iochannel = NULL;
|
self->priv->iochannel = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
close (self->priv->fd);
|
/* Close fd, if any */
|
||||||
self->priv->fd = -1;
|
if (self->priv->fd >= 0) {
|
||||||
|
close (self->priv->fd);
|
||||||
|
self->priv->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destroy socket */
|
||||||
|
if (self->priv->socket) {
|
||||||
|
data_watch_enable (self, FALSE);
|
||||||
|
g_socket_close (self->priv->socket, NULL);
|
||||||
|
g_object_unref (self->priv->socket);
|
||||||
|
self->priv->socket = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
g_get_current_time (&tv_end);
|
g_get_current_time (&tv_end);
|
||||||
|
|
||||||
@@ -1402,6 +1570,8 @@ get_speed (MMPortSerial *self, speed_t *speed, GError **error)
|
|||||||
{
|
{
|
||||||
struct termios options;
|
struct termios options;
|
||||||
|
|
||||||
|
g_assert (self->priv->fd >= 0);
|
||||||
|
|
||||||
memset (&options, 0, sizeof (struct termios));
|
memset (&options, 0, sizeof (struct termios));
|
||||||
if (tcgetattr (self->priv->fd, &options) != 0) {
|
if (tcgetattr (self->priv->fd, &options) != 0) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
@@ -1423,6 +1593,8 @@ set_speed (MMPortSerial *self, speed_t speed, GError **error)
|
|||||||
int fd, count = 4;
|
int fd, count = 4;
|
||||||
gboolean success = FALSE;
|
gboolean success = FALSE;
|
||||||
|
|
||||||
|
g_assert (self->priv->fd >= 0);
|
||||||
|
|
||||||
fd = self->priv->fd;
|
fd = self->priv->fd;
|
||||||
|
|
||||||
memset (&options, 0, sizeof (struct termios));
|
memset (&options, 0, sizeof (struct termios));
|
||||||
@@ -1536,7 +1708,7 @@ flash_do (MMPortSerial *self)
|
|||||||
|
|
||||||
ctx->flash_id = 0;
|
ctx->flash_id = 0;
|
||||||
|
|
||||||
if (self->priv->flash_ok || mm_port_get_subsys (MM_PORT (self)) == MM_PORT_SUBSYS_TTY) {
|
if (self->priv->flash_ok && mm_port_get_subsys (MM_PORT (self)) == MM_PORT_SUBSYS_TTY) {
|
||||||
if (ctx->current_speed) {
|
if (ctx->current_speed) {
|
||||||
if (!set_speed (ctx->self, ctx->current_speed, &error))
|
if (!set_speed (ctx->self, ctx->current_speed, &error))
|
||||||
g_assert (error);
|
g_assert (error);
|
||||||
@@ -1595,6 +1767,7 @@ mm_port_serial_flash (MMPortSerial *self,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Flashing only in TTY */
|
||||||
if (!self->priv->flash_ok || mm_port_get_subsys (MM_PORT (self)) != MM_PORT_SUBSYS_TTY) {
|
if (!self->priv->flash_ok || mm_port_get_subsys (MM_PORT (self)) != MM_PORT_SUBSYS_TTY) {
|
||||||
self->priv->flash_ctx = ctx;
|
self->priv->flash_ctx = ctx;
|
||||||
ctx->flash_id = g_idle_add ((GSourceFunc)flash_do, self);
|
ctx->flash_id = g_idle_add ((GSourceFunc)flash_do, self);
|
||||||
|
@@ -25,8 +25,9 @@ typedef enum { /*< underscore_name=mm_port_subsys >*/
|
|||||||
MM_PORT_SUBSYS_TTY,
|
MM_PORT_SUBSYS_TTY,
|
||||||
MM_PORT_SUBSYS_NET,
|
MM_PORT_SUBSYS_NET,
|
||||||
MM_PORT_SUBSYS_USB,
|
MM_PORT_SUBSYS_USB,
|
||||||
|
MM_PORT_SUBSYS_UNIX,
|
||||||
|
|
||||||
MM_PORT_SUBSYS_LAST = MM_PORT_SUBSYS_USB /*< skip >*/
|
MM_PORT_SUBSYS_LAST = MM_PORT_SUBSYS_UNIX /*< skip >*/
|
||||||
} MMPortSubsys;
|
} MMPortSubsys;
|
||||||
|
|
||||||
typedef enum { /*< underscore_name=mm_port_type >*/
|
typedef enum { /*< underscore_name=mm_port_type >*/
|
||||||
|
Reference in New Issue
Block a user