static gboolean wdm_probe_qmi (MMPortProbe *self) { PortProbeRunTask *task = self->priv->task; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return FALSE; #if defined WITH_QMI mm_dbg ("(%s/%s) probing QMI...", g_udev_device_get_subsystem (self->priv->port), g_udev_device_get_name (self->priv->port)); /* Create a port and try to open it */ task->qmi_port = mm_qmi_port_new (g_udev_device_get_name (self->priv->port)); mm_qmi_port_open (task->qmi_port, FALSE, NULL, (GAsyncReadyCallback)qmi_port_open_ready, self); #else /* If not compiled with QMI support, just assume we won't have any QMI port */ mm_port_probe_set_result_qmi (self, FALSE); port_probe_run_task_complete (task, TRUE, NULL); #endif /* WITH_QMI */ return FALSE; }
static gboolean serial_probe_at (MMPortProbe *self) { PortProbeRunTask *task = self->priv->task; task->source_id = 0; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return FALSE; /* If AT probing cancelled, end this partial probing */ if (g_cancellable_is_cancelled (task->at_probing_cancellable)) { mm_dbg ("(%s) no need to launch probing for AT support", self->priv->name); task->at_result_processor (self, NULL); serial_probe_schedule (self); return FALSE; } mm_at_serial_port_queue_command ( MM_AT_SERIAL_PORT (task->serial), task->at_commands->command, task->at_commands->timeout, task->at_probing_cancellable, (MMAtSerialResponseFn)serial_probe_at_parse_response, self); return FALSE; }
static void serial_probe_schedule (MMPortProbe *self) { PortProbeRunTask *task = self->priv->task; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return; /* Cleanup */ task->at_result_processor = NULL; task->at_commands = NULL; /* If we got some custom initialization commands requested, go on with them * first. */ if (task->at_custom_init) { task->at_result_processor = serial_probe_at_custom_init_result_processor; task->at_commands = task->at_custom_init; } /* AT check requested and not already probed? */ else if ((task->flags & MM_PORT_PROBE_AT) && !(self->priv->flags & MM_PORT_PROBE_AT)) { /* Prepare AT probing */ task->at_result_processor = serial_probe_at_result_processor; task->at_commands = at_probing; } /* Vendor requested and not already probed? */ else if ((task->flags & MM_PORT_PROBE_AT_VENDOR) && !(self->priv->flags & MM_PORT_PROBE_AT_VENDOR)) { /* Prepare AT vendor probing */ task->at_result_processor = serial_probe_at_vendor_result_processor; task->at_commands = vendor_probing; } /* Product requested and not already probed? */ else if ((task->flags & MM_PORT_PROBE_AT_PRODUCT) && !(self->priv->flags & MM_PORT_PROBE_AT_PRODUCT)) { /* Prepare AT product probing */ task->at_result_processor = serial_probe_at_product_result_processor; task->at_commands = product_probing; } /* If a next AT group detected, go for it */ if (task->at_result_processor && task->at_commands) { task->source_id = g_idle_add ((GSourceFunc)serial_probe_at, self); return; } /* QCDM requested and not already probed? */ if ((task->flags & MM_PORT_PROBE_QCDM) && !(self->priv->flags & MM_PORT_PROBE_QCDM)) { task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, self); return; } /* All done! Finish asynchronously */ port_probe_run_task_complete (task, TRUE, NULL); }
static void serial_probe_qcdm_parse_response (MMQcdmSerialPort *port, GByteArray *response, GError *error, MMPortProbe *self) { QcdmResult *result; gint err = QCDM_SUCCESS; gboolean is_qcdm = FALSE; /* Just the initial poke; ignore it */ if (!self) return; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return; if (!error) { /* Parse the response */ result = qcdm_cmd_version_info_result ((const gchar *) response->data, response->len, &err); if (!result) { mm_warn ("(%s) failed to parse QCDM version info command result: %d", self->priv->name, err); } else { /* yay, probably a QCDM port */ is_qcdm = TRUE; qcdm_result_unref (result); } } /* Set probing result */ mm_port_probe_set_result_qcdm (self, is_qcdm); /* Reschedule probing */ serial_probe_schedule (self); }
static gboolean serial_open_at (MMPortProbe *self) { PortProbeRunTask *task = self->priv->task; GError *error = NULL; task->source_id = 0; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return FALSE; /* Create AT serial port if not done before */ if (!task->serial) { task->serial = MM_SERIAL_PORT (mm_at_serial_port_new (self->priv->name)); if (!task->serial) { port_probe_run_task_complete ( task, FALSE, g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "(%s) couldn't create AT port", self->priv->name)); return FALSE; } g_object_set (task->serial, MM_SERIAL_PORT_SEND_DELAY, task->at_send_delay, MM_PORT_CARRIER_DETECT, FALSE, MM_SERIAL_PORT_SPEW_CONTROL, TRUE, NULL); mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (task->serial), mm_serial_parser_v1_parse, mm_serial_parser_v1_new (), mm_serial_parser_v1_destroy); } /* Try to open the port */ if (!mm_serial_port_open (task->serial, &error)) { /* Abort if maximum number of open tries reached */ if (++task->at_open_tries > 4) { /* took too long to open the port; give up */ port_probe_run_task_complete ( task, FALSE, g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "(%s) failed to open port after 4 tries", self->priv->name)); } else if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED_NO_DEVICE)) { /* this is nozomi being dumb; try again */ task->source_id = g_timeout_add_seconds (1, (GSourceFunc)serial_open_at, self); } else { port_probe_run_task_complete ( task, FALSE, g_error_new (MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED, "(%s) failed to open port: %s", self->priv->name, (error ? error->message : "unknown error"))); } g_clear_error (&error); return FALSE; } /* success, start probing */ task->buffer_full_id = g_signal_connect (task->serial, "buffer-full", G_CALLBACK (serial_buffer_full), self); mm_serial_port_flash (MM_SERIAL_PORT (task->serial), 100, TRUE, (MMSerialFlashFn)serial_flash_done, self); return FALSE; }
static void serial_probe_at_parse_response (MMAtSerialPort *port, GString *response, GError *error, MMPortProbe *self) { PortProbeRunTask *task = self->priv->task; GVariant *result = NULL; GError *result_error = NULL; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return; /* If AT probing cancelled, end this partial probing */ if (g_cancellable_is_cancelled (task->at_probing_cancellable)) { mm_dbg ("(%s) no need to keep on probing the port for AT support", self->priv->name); task->at_result_processor (self, NULL); serial_probe_schedule (self); return; } if (!task->at_commands->response_processor (task->at_commands->command, response->str, !!task->at_commands[1].command, error, &result, &result_error)) { /* Were we told to abort the whole probing? */ if (result_error) { port_probe_run_task_complete ( task, FALSE, g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "(%s) error while probing AT features: %s", self->priv->name, result_error->message)); g_error_free (result_error); return; } /* Go on to next command */ task->at_commands++; if (!task->at_commands->command) { /* Was it the last command in the group? If so, * end this partial probing */ task->at_result_processor (self, NULL); /* Reschedule */ serial_probe_schedule (self); return; } /* Schedule the next command in the probing group */ task->source_id = g_idle_add ((GSourceFunc)serial_probe_at, self); return; } /* Run result processor. * Note that custom init commands are allowed to not return anything */ task->at_result_processor (self, result); if (result) g_variant_unref (result); /* Reschedule probing */ serial_probe_schedule (self); }
static gboolean serial_probe_qcdm (MMPortProbe *self) { PortProbeRunTask *task = self->priv->task; GError *error = NULL; GByteArray *verinfo = NULL; GByteArray *verinfo2; gint len; task->source_id = 0; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return FALSE; mm_dbg ("(%s) probing QCDM...", self->priv->name); /* If open, close the AT port */ if (task->serial) { mm_serial_port_close (task->serial); g_object_unref (task->serial); } /* Open the QCDM port */ task->serial = MM_SERIAL_PORT (mm_qcdm_serial_port_new (self->priv->name)); if (!task->serial) { port_probe_run_task_complete ( task, FALSE, g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "(%s) Couldn't create QCDM port", self->priv->name)); return FALSE; } /* Try to open the port */ if (!mm_serial_port_open (task->serial, &error)) { port_probe_run_task_complete ( task, FALSE, g_error_new (MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED, "(%s) Failed to open QCDM port: %s", self->priv->name, (error ? error->message : "unknown error"))); g_clear_error (&error); return FALSE; } /* Build up the probe command */ verinfo = g_byte_array_sized_new (50); len = qcdm_cmd_version_info_new ((gchar *) verinfo->data, 50); if (len <= 0) { g_byte_array_free (verinfo, TRUE); port_probe_run_task_complete ( task, FALSE, g_error_new (MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED, "(%s) Failed to create QCDM versin info command", self->priv->name)); return FALSE; } verinfo->len = len; /* Queuing the command takes ownership over it; dup it for the second try */ verinfo2 = g_byte_array_sized_new (verinfo->len); g_byte_array_append (verinfo2, verinfo->data, verinfo->len); /* Send the command twice; the ports often need to be woken up */ mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial), verinfo, 3, NULL, (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response, NULL); mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial), verinfo2, 3, NULL, (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response, self); return FALSE; }
static gboolean serial_probe_qcdm (MMPortProbe *self) { PortProbeRunTask *task = self->priv->task; GError *error = NULL; GByteArray *verinfo = NULL; GByteArray *verinfo2; gint len; guint8 marker = 0x7E; task->source_id = 0; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return FALSE; mm_dbg ("(%s/%s) probing QCDM...", g_udev_device_get_subsystem (self->priv->port), g_udev_device_get_name (self->priv->port)); /* If open, close the AT port */ if (task->serial) { mm_serial_port_close (task->serial); g_object_unref (task->serial); } /* Open the QCDM port */ task->serial = MM_SERIAL_PORT (mm_qcdm_serial_port_new (g_udev_device_get_name (self->priv->port))); if (!task->serial) { port_probe_run_task_complete ( task, FALSE, g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "(%s/%s) Couldn't create QCDM port", g_udev_device_get_subsystem (self->priv->port), g_udev_device_get_name (self->priv->port))); return FALSE; } /* Try to open the port */ if (!mm_serial_port_open (task->serial, &error)) { port_probe_run_task_complete ( task, FALSE, g_error_new (MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED, "(%s/%s) Failed to open QCDM port: %s", g_udev_device_get_subsystem (self->priv->port), g_udev_device_get_name (self->priv->port), (error ? error->message : "unknown error"))); g_clear_error (&error); return FALSE; } /* Build up the probe command; 0x7E is the frame marker, so put one at the * beginning of the buffer to ensure that the device discards any AT * commands that probing might have sent earlier. Should help devices * respond more quickly and speed up QCDM probing. */ verinfo = g_byte_array_sized_new (10); g_byte_array_append (verinfo, &marker, 1); len = qcdm_cmd_version_info_new ((char *) (verinfo->data + 1), 9); if (len <= 0) { g_byte_array_free (verinfo, TRUE); port_probe_run_task_complete ( task, FALSE, g_error_new (MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED, "(%s/%s) Failed to create QCDM versin info command", g_udev_device_get_subsystem (self->priv->port), g_udev_device_get_name (self->priv->port))); return FALSE; } verinfo->len = len + 1; /* Queuing the command takes ownership over it; save it for the second try */ verinfo2 = g_byte_array_sized_new (verinfo->len); g_byte_array_append (verinfo2, verinfo->data, verinfo->len); g_object_set_data_full (G_OBJECT (self), "cmd2", verinfo2, (GDestroyNotify) g_byte_array_unref); mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial), verinfo, 3, NULL, (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response, self); return FALSE; }
static void serial_probe_qcdm_parse_response (MMQcdmSerialPort *port, GByteArray *response, GError *error, MMPortProbe *self) { QcdmResult *result; gint err = QCDM_SUCCESS; gboolean is_qcdm = FALSE; gboolean retry = FALSE; PortProbeRunTask *task = self->priv->task; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return; if (!error) { /* Parse the response */ result = qcdm_cmd_version_info_result ((const gchar *) response->data, response->len, &err); if (!result) { mm_warn ("(%s/%s) failed to parse QCDM version info command result: %d", g_udev_device_get_subsystem (self->priv->port), g_udev_device_get_name (self->priv->port), err); retry = TRUE; } else { /* yay, probably a QCDM port */ is_qcdm = TRUE; qcdm_result_unref (result); } } else { if (!g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) mm_dbg ("QCDM probe error: (%d) %s", error->code, error->message); retry = TRUE; } if (retry) { GByteArray *cmd2; cmd2 = g_object_steal_data (G_OBJECT (self), "cmd2"); if (cmd2) { /* second try */ mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial), cmd2, 3, NULL, (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response, self); return; } /* no more retries left */ } /* Set probing result */ mm_port_probe_set_result_qcdm (self, is_qcdm); /* Reschedule probing */ serial_probe_schedule (self); }