core: don't allow concurrent flashes on the same device
Previously, a few operations (like disable) could trigger a modem flash in parallel with another flash. That's wrong, don't allow that. At the same time, add in finer-grained error checking on serial port speed operations, and fix a GSM generic bug that would send the POWER_UP string on disable.
This commit is contained in:
@@ -15,4 +15,22 @@
|
||||
</tp:docstring>
|
||||
</tp:error>
|
||||
|
||||
<tp:error name="Connected">
|
||||
<tp:docstring>
|
||||
Operation could not be performed while the modem is connected.
|
||||
</tp:docstring>
|
||||
</tp:error>
|
||||
|
||||
<tp:error name="Disconnected">
|
||||
<tp:docstring>
|
||||
Operation could not be performed while the modem is disconnected.
|
||||
</tp:docstring>
|
||||
</tp:error>
|
||||
|
||||
<tp:error name="OperationInProgress">
|
||||
<tp:docstring>
|
||||
Operation could not be performed because it is already in progress.
|
||||
</tp:docstring>
|
||||
</tp:error>
|
||||
|
||||
</tp:errors>
|
||||
|
@@ -402,11 +402,17 @@ mbm_emrdy_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
enable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = user_data;
|
||||
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem);
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->have_emrdy) {
|
||||
/* Modem is ready, no need to check EMRDY */
|
||||
do_init (port, info);
|
||||
@@ -427,8 +433,16 @@ disable_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
disable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
disable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_queue_command (port, "+CMER=0", 5, disable_done, user_data);
|
||||
}
|
||||
|
||||
@@ -449,18 +463,20 @@ enable (MMModem *modem,
|
||||
g_assert (primary);
|
||||
|
||||
if (do_enable) {
|
||||
if (mm_serial_port_open (primary, &info->error))
|
||||
mm_serial_port_flash (primary, 100, enable_flash_done, info);
|
||||
|
||||
if (info->error)
|
||||
if (!mm_serial_port_open (primary, &info->error)) {
|
||||
g_assert (info->error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_flash (primary, 100, enable_flash_done, info);
|
||||
} else {
|
||||
mm_serial_port_queue_command (primary, "+CREG=0", 100, NULL, NULL);
|
||||
mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem));
|
||||
if (mm_port_get_connected (MM_PORT (primary)))
|
||||
mm_serial_port_flash (primary, 1000, disable_flash_done, info);
|
||||
else
|
||||
disable_flash_done (primary, info);
|
||||
disable_flash_done (primary, NULL, info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -94,8 +94,16 @@ pre_init_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
enable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = user_data;
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data);
|
||||
}
|
||||
|
||||
@@ -110,8 +118,16 @@ disable_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
disable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
disable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = user_data;
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_queue_command (port, "+CFUN=0", 5, disable_done, user_data);
|
||||
}
|
||||
|
||||
@@ -136,13 +152,15 @@ enable (MMModem *modem,
|
||||
if (mm_port_get_connected (MM_PORT (primary)))
|
||||
mm_serial_port_flash (primary, 1000, disable_flash_done, info);
|
||||
else
|
||||
disable_flash_done (primary, info);
|
||||
disable_flash_done (primary, NULL, info);
|
||||
} else {
|
||||
if (mm_serial_port_open (primary, &info->error))
|
||||
mm_serial_port_flash (primary, 100, enable_flash_done, info);
|
||||
|
||||
if (info->error)
|
||||
if (!mm_serial_port_open (primary, &info->error)) {
|
||||
g_assert (info->error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_flash (primary, 100, enable_flash_done, info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -84,16 +84,32 @@ init_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
enable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = user_data;
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_queue_command (port, "Z E0 V1 X4 &C1 +CMEE=1", 3, init_done, user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
disable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
disable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = user_data;
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_close (port);
|
||||
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
|
||||
mm_callback_info_schedule (info);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -118,13 +134,15 @@ enable (MMModem *modem,
|
||||
if (mm_port_get_connected (MM_PORT (primary)))
|
||||
mm_serial_port_flash (primary, 1000, disable_flash_done, info);
|
||||
else
|
||||
disable_flash_done (primary, info);
|
||||
disable_flash_done (primary, NULL, info);
|
||||
} else {
|
||||
if (mm_serial_port_open (primary, &info->error))
|
||||
mm_serial_port_flash (primary, 100, enable_flash_done, info);
|
||||
|
||||
if (info->error)
|
||||
if (!mm_serial_port_open (primary, &info->error)) {
|
||||
g_assert (info->error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_flash (primary, 100, enable_flash_done, info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -95,8 +95,16 @@ pre_init_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
enable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data);
|
||||
}
|
||||
|
||||
@@ -111,8 +119,16 @@ disable_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
disable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
disable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_queue_command (port, "+CFUN=0", 5, disable_done, user_data);
|
||||
}
|
||||
|
||||
@@ -137,13 +153,15 @@ enable (MMModem *modem,
|
||||
if (mm_port_get_connected (MM_PORT (primary)))
|
||||
mm_serial_port_flash (primary, 1000, disable_flash_done, info);
|
||||
else
|
||||
disable_flash_done (primary, info);
|
||||
disable_flash_done (primary, NULL, info);
|
||||
} else {
|
||||
if (mm_serial_port_open (primary, &info->error))
|
||||
mm_serial_port_flash (primary, 100, enable_flash_done, info);
|
||||
|
||||
if (info->error)
|
||||
if (!mm_serial_port_open (primary, &info->error)) {
|
||||
g_assert (info->error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_flash (primary, 100, enable_flash_done, info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -69,6 +69,8 @@ mm_modem_error_get_type (void)
|
||||
ENUM_ENTRY (MM_MODEM_ERROR_GENERAL, "General"),
|
||||
ENUM_ENTRY (MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED, "OperationNotSupported"),
|
||||
ENUM_ENTRY (MM_MODEM_ERROR_CONNECTED, "Connected"),
|
||||
ENUM_ENTRY (MM_MODEM_ERROR_DISCONNECTED, "Disconnected"),
|
||||
ENUM_ENTRY (MM_MODEM_ERROR_OPERATION_IN_PROGRESS, "OperationInProgress"),
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@@ -35,7 +35,9 @@ GType mm_serial_error_get_type (void);
|
||||
enum {
|
||||
MM_MODEM_ERROR_GENERAL = 0,
|
||||
MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED = 1,
|
||||
MM_MODEM_ERROR_CONNECTED = 2
|
||||
MM_MODEM_ERROR_CONNECTED = 2,
|
||||
MM_MODEM_ERROR_DISCONNECTED = 3,
|
||||
MM_MODEM_ERROR_OPERATION_IN_PROGRESS = 4
|
||||
};
|
||||
|
||||
#define MM_MODEM_ERROR (mm_modem_error_quark ())
|
||||
|
@@ -218,8 +218,17 @@ init_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
flash_done (MMSerialPort *port, gpointer user_data)
|
||||
flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
||||
|
||||
if (error) {
|
||||
/* Flash failed for some reason */
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_queue_command (port, "Z E0 V1 X4 &C1", 3, init_done, user_data);
|
||||
}
|
||||
|
||||
@@ -240,11 +249,13 @@ enable (MMModem *modem,
|
||||
return;
|
||||
}
|
||||
|
||||
if (mm_serial_port_open (priv->primary, &info->error))
|
||||
mm_serial_port_flash (priv->primary, 100, flash_done, info);
|
||||
|
||||
if (info->error)
|
||||
if (!mm_serial_port_open (priv->primary, &info->error)) {
|
||||
g_assert (info->error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_flash (priv->primary, 100, flash_done, info);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -283,12 +294,19 @@ connect (MMModem *modem,
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
disconnect_flash_done (MMSerialPort *port,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
||||
MMGenericCdmaPrivate *priv;
|
||||
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem);
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem);
|
||||
mm_port_set_connected (priv->data, FALSE);
|
||||
mm_callback_info_schedule (info);
|
||||
}
|
||||
|
@@ -369,11 +369,17 @@ init_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
enable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = user_data;
|
||||
char *cmd = NULL;
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_INIT_CMD, &cmd, NULL);
|
||||
mm_serial_port_queue_command (port, cmd, 3, init_done, user_data);
|
||||
g_free (cmd);
|
||||
@@ -390,12 +396,20 @@ disable_done (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
disable_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
disable_flash_done (MMSerialPort *port,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = user_data;
|
||||
char *cmd = NULL;
|
||||
|
||||
g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL);
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_DOWN_CMD, &cmd, NULL);
|
||||
if (cmd && strlen (cmd))
|
||||
mm_serial_port_queue_command (port, cmd, 5, disable_done, user_data);
|
||||
else
|
||||
@@ -423,13 +437,15 @@ enable (MMModem *modem,
|
||||
if (mm_port_get_connected (MM_PORT (priv->primary)))
|
||||
mm_serial_port_flash (priv->primary, 1000, disable_flash_done, info);
|
||||
else
|
||||
disable_flash_done (priv->primary, info);
|
||||
disable_flash_done (priv->primary, NULL, info);
|
||||
} else {
|
||||
if (mm_serial_port_open (priv->primary, &info->error))
|
||||
mm_serial_port_flash (priv->primary, 100, enable_flash_done, info);
|
||||
|
||||
if (info->error)
|
||||
if (!mm_serial_port_open (priv->primary, &info->error)) {
|
||||
g_assert (info->error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_serial_port_flash (priv->primary, 100, enable_flash_done, info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1037,11 +1053,19 @@ connect (MMModem *modem,
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_flash_done (MMSerialPort *port, gpointer user_data)
|
||||
disconnect_flash_done (MMSerialPort *port,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
||||
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
|
||||
|
||||
if (error) {
|
||||
info->error = g_error_copy (error);
|
||||
mm_callback_info_schedule (info);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_port_set_connected (priv->data, FALSE);
|
||||
mm_callback_info_schedule (info);
|
||||
}
|
||||
|
@@ -205,6 +205,9 @@ dispose (GObject *object)
|
||||
{
|
||||
MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (object);
|
||||
|
||||
if (MM_IS_SERIAL_PORT (priv->port))
|
||||
mm_serial_port_flash_cancel (MM_SERIAL_PORT (priv->port));
|
||||
|
||||
g_object_unref (priv->port);
|
||||
g_object_unref (priv->physdev);
|
||||
g_free (priv->driver);
|
||||
@@ -459,12 +462,8 @@ parse_response (MMSerialPort *port,
|
||||
}
|
||||
|
||||
static void
|
||||
flash_done (MMSerialPort *port, gpointer user_data)
|
||||
flash_done (MMSerialPort *port, GError *error, gpointer user_data)
|
||||
{
|
||||
MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
|
||||
MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
|
||||
|
||||
task_priv->probe_id = 0;
|
||||
mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, user_data);
|
||||
}
|
||||
|
||||
@@ -506,7 +505,7 @@ mm_plugin_base_probe_port (MMPluginBase *self,
|
||||
|
||||
g_debug ("(%s): probe requested by plugin '%s'", name, priv->name);
|
||||
task_priv->probe_port = serial;
|
||||
task_priv->probe_id = mm_serial_port_flash (serial, 100, flash_done, task);
|
||||
mm_serial_port_flash (serial, 100, flash_done, task);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@@ -77,8 +77,93 @@ typedef struct {
|
||||
guint queue_schedule;
|
||||
guint watch_id;
|
||||
guint timeout_id;
|
||||
|
||||
guint flash_id;
|
||||
} MMSerialPortPrivate;
|
||||
|
||||
#if 0
|
||||
static const char *
|
||||
baud_to_string (int baud)
|
||||
{
|
||||
const char *speed = NULL;
|
||||
|
||||
switch (baud) {
|
||||
case B0:
|
||||
speed = "0";
|
||||
break;
|
||||
case B50:
|
||||
speed = "50";
|
||||
break;
|
||||
case B75:
|
||||
speed = "75";
|
||||
break;
|
||||
case B110:
|
||||
speed = "110";
|
||||
break;
|
||||
case B150:
|
||||
speed = "150";
|
||||
break;
|
||||
case B300:
|
||||
speed = "300";
|
||||
break;
|
||||
case B600:
|
||||
speed = "600";
|
||||
break;
|
||||
case B1200:
|
||||
speed = "1200";
|
||||
break;
|
||||
case B2400:
|
||||
speed = "2400";
|
||||
break;
|
||||
case B4800:
|
||||
speed = "4800";
|
||||
break;
|
||||
case B9600:
|
||||
speed = "9600";
|
||||
break;
|
||||
case B19200:
|
||||
speed = "19200";
|
||||
break;
|
||||
case B38400:
|
||||
speed = "38400";
|
||||
break;
|
||||
case B57600:
|
||||
speed = "57600";
|
||||
break;
|
||||
case B115200:
|
||||
speed = "115200";
|
||||
break;
|
||||
case B460800:
|
||||
speed = "460800";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
void
|
||||
mm_serial_port_print_config (MMSerialPort *port, const char *detail)
|
||||
{
|
||||
MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (port);
|
||||
struct termio stbuf;
|
||||
int err;
|
||||
|
||||
err = ioctl (priv->fd, TCGETA, &stbuf);
|
||||
if (err) {
|
||||
g_warning ("*** %s (%s): (%s) TCGETA error %d",
|
||||
__func__, detail, mm_port_get_device (MM_PORT (port)), errno);
|
||||
return;
|
||||
}
|
||||
|
||||
g_message ("*** %s (%s): (%s) baud rate: %d (%s)",
|
||||
__func__, detail, mm_port_get_device (MM_PORT (port)),
|
||||
stbuf.c_cflag & CBAUD,
|
||||
baud_to_string (stbuf.c_cflag & CBAUD));
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
GRegex *regex;
|
||||
MMSerialUnsolicitedMsgFn callback;
|
||||
@@ -241,7 +326,7 @@ parse_stopbits (guint i)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
config_fd (MMSerialPort *self)
|
||||
config_fd (MMSerialPort *self, GError **error)
|
||||
{
|
||||
MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
|
||||
struct termio stbuf;
|
||||
@@ -255,7 +340,13 @@ config_fd (MMSerialPort *self)
|
||||
parity = parse_parity (priv->parity);
|
||||
stopbits = parse_stopbits (priv->stopbits);
|
||||
|
||||
ioctl (priv->fd, TCGETA, &stbuf);
|
||||
memset (&stbuf, 0, sizeof (struct termio));
|
||||
if (ioctl (priv->fd, TCGETA, &stbuf) != 0) {
|
||||
g_warning ("%s (%s): TCGETA error: %d",
|
||||
__func__,
|
||||
mm_port_get_device (MM_PORT (self)),
|
||||
errno);
|
||||
}
|
||||
|
||||
stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
|
||||
stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
|
||||
@@ -269,8 +360,11 @@ config_fd (MMSerialPort *self)
|
||||
stbuf.c_cflag |= (speed | bits | CREAD | 0 | parity | stopbits);
|
||||
|
||||
if (ioctl (priv->fd, TCSETA, &stbuf) < 0) {
|
||||
g_warning ("(%s) cannot control device (errno %d)",
|
||||
mm_port_get_device (MM_PORT (self)), errno);
|
||||
g_set_error (error,
|
||||
MM_MODEM_ERROR,
|
||||
MM_MODEM_ERROR_GENERAL,
|
||||
"%s: failed to set serial port attributes; errno %d",
|
||||
__func__, errno);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -401,8 +495,10 @@ mm_serial_port_got_response (MMSerialPort *self, GError *error)
|
||||
MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
|
||||
MMQueueData *info;
|
||||
|
||||
if (priv->timeout_id)
|
||||
if (priv->timeout_id) {
|
||||
g_source_remove (priv->timeout_id);
|
||||
priv->timeout_id = 0;
|
||||
}
|
||||
|
||||
info = (MMQueueData *) g_queue_pop_head (priv->queue);
|
||||
if (info) {
|
||||
@@ -689,9 +785,7 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!config_fd (self)) {
|
||||
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
|
||||
"Could not open serial device %s: %s", device, strerror (errno));
|
||||
if (!config_fd (self, error)) {
|
||||
close (priv->fd);
|
||||
priv->fd = -1;
|
||||
return FALSE;
|
||||
@@ -725,6 +819,11 @@ mm_serial_port_close (MMSerialPort *self)
|
||||
priv->channel = NULL;
|
||||
}
|
||||
|
||||
if (priv->flash_id > 0) {
|
||||
g_source_remove (priv->flash_id);
|
||||
priv->flash_id = 0;
|
||||
}
|
||||
|
||||
ioctl (priv->fd, TCSETA, &priv->old_t);
|
||||
close (priv->fd);
|
||||
priv->fd = -1;
|
||||
@@ -789,81 +888,158 @@ typedef struct {
|
||||
gpointer user_data;
|
||||
} FlashInfo;
|
||||
|
||||
static speed_t
|
||||
get_speed (MMSerialPort *self)
|
||||
static gboolean
|
||||
get_speed (MMSerialPort *self, speed_t *speed, GError **error)
|
||||
{
|
||||
struct termios options;
|
||||
|
||||
memset (&options, 0, sizeof (struct termios));
|
||||
tcgetattr (MM_SERIAL_PORT_GET_PRIVATE (self)->fd, &options);
|
||||
|
||||
return cfgetospeed (&options);
|
||||
if (tcgetattr (MM_SERIAL_PORT_GET_PRIVATE (self)->fd, &options) != 0) {
|
||||
g_set_error (error,
|
||||
MM_MODEM_ERROR,
|
||||
MM_MODEM_ERROR_GENERAL,
|
||||
"%s: tcgetattr() error %d",
|
||||
__func__, errno);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_speed (MMSerialPort *self, speed_t speed)
|
||||
*speed = cfgetospeed (&options);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_speed (MMSerialPort *self, speed_t speed, GError **error)
|
||||
{
|
||||
struct termios options;
|
||||
int fd;
|
||||
int fd, count = 4;
|
||||
gboolean success = FALSE;
|
||||
|
||||
fd = MM_SERIAL_PORT_GET_PRIVATE (self)->fd;
|
||||
|
||||
memset (&options, 0, sizeof (struct termios));
|
||||
tcgetattr (fd, &options);
|
||||
if (tcgetattr (fd, &options) != 0) {
|
||||
g_set_error (error,
|
||||
MM_MODEM_ERROR,
|
||||
MM_MODEM_ERROR_GENERAL,
|
||||
"%s: tcgetattr() error %d",
|
||||
__func__, errno);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cfsetispeed (&options, speed);
|
||||
cfsetospeed (&options, speed);
|
||||
|
||||
options.c_cflag |= (CLOCAL | CREAD);
|
||||
tcsetattr (fd, TCSANOW, &options);
|
||||
|
||||
while (count-- > 0) {
|
||||
if (tcsetattr (fd, TCSANOW, &options) == 0) {
|
||||
success = TRUE;
|
||||
break; /* Operation successful */
|
||||
}
|
||||
|
||||
static void
|
||||
flash_done (gpointer data)
|
||||
{
|
||||
FlashInfo *info = (FlashInfo *) data;
|
||||
/* Try a few times if EAGAIN */
|
||||
if (errno == EAGAIN)
|
||||
g_usleep (100000);
|
||||
else {
|
||||
/* If not EAGAIN, hard error */
|
||||
g_set_error (error,
|
||||
MM_MODEM_ERROR,
|
||||
MM_MODEM_ERROR_GENERAL,
|
||||
"%s: tcsetattr() error %d",
|
||||
__func__, errno);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
info->callback (info->port, info->user_data);
|
||||
if (!success) {
|
||||
g_set_error (error,
|
||||
MM_MODEM_ERROR,
|
||||
MM_MODEM_ERROR_GENERAL,
|
||||
"%s: tcsetattr() retry timeout",
|
||||
__func__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_slice_free (FlashInfo, info);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
flash_do (gpointer data)
|
||||
{
|
||||
FlashInfo *info = (FlashInfo *) data;
|
||||
MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (info->port);
|
||||
GError *error = NULL;
|
||||
|
||||
set_speed (info->port, info->current_speed);
|
||||
priv->flash_id = 0;
|
||||
|
||||
if (!set_speed (info->port, info->current_speed, &error))
|
||||
g_assert (error);
|
||||
|
||||
info->callback (info->port, error, info->user_data);
|
||||
g_clear_error (&error);
|
||||
g_slice_free (FlashInfo, info);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
guint
|
||||
gboolean
|
||||
mm_serial_port_flash (MMSerialPort *self,
|
||||
guint32 flash_time,
|
||||
MMSerialFlashFn callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
FlashInfo *info;
|
||||
guint id;
|
||||
MMSerialPortPrivate *priv;
|
||||
speed_t cur_speed = 0;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_val_if_fail (MM_IS_SERIAL_PORT (self), 0);
|
||||
g_return_val_if_fail (callback != NULL, 0);
|
||||
g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE);
|
||||
g_return_val_if_fail (callback != NULL, FALSE);
|
||||
|
||||
priv = MM_SERIAL_PORT_GET_PRIVATE (self);
|
||||
|
||||
if (priv->flash_id > 0) {
|
||||
error = g_error_new_literal (MM_MODEM_ERROR,
|
||||
MM_MODEM_ERROR_OPERATION_IN_PROGRESS,
|
||||
"Modem is already being flashed.");
|
||||
callback (self, error, user_data);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!get_speed (self, &cur_speed, &error)) {
|
||||
callback (self, error, user_data);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info = g_slice_new0 (FlashInfo);
|
||||
info->port = self;
|
||||
info->current_speed = get_speed (self);
|
||||
info->current_speed = cur_speed;
|
||||
info->callback = callback;
|
||||
info->user_data = user_data;
|
||||
|
||||
set_speed (self, B0);
|
||||
if (!set_speed (self, B0, &error)) {
|
||||
callback (self, error, user_data);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
id = g_timeout_add_full (G_PRIORITY_DEFAULT,
|
||||
flash_time,
|
||||
flash_do,
|
||||
info,
|
||||
flash_done);
|
||||
priv->flash_id = g_timeout_add (flash_time, flash_do, info);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return id;
|
||||
void
|
||||
mm_serial_port_flash_cancel (MMSerialPort *self)
|
||||
{
|
||||
MMSerialPortPrivate *priv;
|
||||
|
||||
g_return_if_fail (MM_IS_SERIAL_PORT (self));
|
||||
|
||||
priv = MM_SERIAL_PORT_GET_PRIVATE (self);
|
||||
|
||||
if (priv->flash_id > 0) {
|
||||
g_source_remove (priv->flash_id);
|
||||
priv->flash_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@@ -53,6 +53,7 @@ typedef void (*MMSerialResponseFn) (MMSerialPort *port,
|
||||
gpointer user_data);
|
||||
|
||||
typedef void (*MMSerialFlashFn) (MMSerialPort *port,
|
||||
GError *error,
|
||||
gpointer user_data);
|
||||
|
||||
struct _MMSerialPort {
|
||||
@@ -94,10 +95,11 @@ void mm_serial_port_queue_command_cached (MMSerialPort *self,
|
||||
MMSerialResponseFn callback,
|
||||
gpointer user_data);
|
||||
|
||||
guint mm_serial_port_flash (MMSerialPort *self,
|
||||
gboolean mm_serial_port_flash (MMSerialPort *self,
|
||||
guint32 flash_time,
|
||||
MMSerialFlashFn callback,
|
||||
gpointer user_data);
|
||||
void mm_serial_port_flash_cancel (MMSerialPort *self);
|
||||
|
||||
#endif /* MM_SERIAL_PORT_H */
|
||||
|
||||
|
Reference in New Issue
Block a user