示例#1
0
static int modem_probe_caps(int fd, glong timeout_ms)
{
	const char *gcap_responses[] = { GCAP_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 (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, 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...%s", "");
		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 (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 *gmm_responses[] = { GMM_TAG, NULL };

		if (modem_send_command (fd, "AT+GMM\r\n")) {
			idx = modem_wait_reply (fd, 5, gmm_responses, terminators, &term_idx, &reply);
			if (0 == term_idx && 0 == idx) {
				verbose ("GMM response: %s", reply);
				ret |= parse_gmm (reply);
			}
			g_free (reply);
		}
	}

	return ret;
}
static void
real_handle_probe_response (MMPluginBase *self,
                            MMPluginBaseSupportsTask *task,
                            const char *cmd,
                            const char *response,
                            const GError *error)
{
    MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
    MMAtSerialPort *port = task_priv->probe_port;
    gboolean ignore_error = FALSE;

    /* Some modems (Huawei E160g) won't respond to +GCAP with no SIM, but
     * will respond to ATI.
     */
    if (response && strstr (response, "+CME ERROR:"))
        ignore_error = TRUE;

    if (error && !ignore_error) {
        if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) {
            /* Try GCAP again */
            if (task_priv->probe_state < PROBE_STATE_GCAP_TRY3) {
                task_priv->probe_state++;
                mm_at_serial_port_queue_command (port, "+GCAP", 3, parse_response, task);
            } else {
               /* Otherwise, if all the GCAP tries timed out, ignore the port
                * as it's probably not an AT-capable port.  Try QCDM.
                */
               try_qcdm_probe (task);
            }
            return;
        }

        /* Otherwise proceed to the next command */
    } else if (response) {
        /* Parse the response */

        switch (task_priv->probe_state) {
        case PROBE_STATE_GCAP_TRY1:
        case PROBE_STATE_GCAP_TRY2:
        case PROBE_STATE_GCAP_TRY3:
        case PROBE_STATE_ATI:
            /* Some modems don't respond to AT+GCAP, but often they put a
             * GCAP-style response as a line in the ATI response.
             */
            task_priv->probed_caps = parse_gcap (response);
            break;
        case PROBE_STATE_CPIN:
            /* Some devices (ZTE MF628/ONDA MT503HS for example) reply to
             * anything but AT+CPIN? with ERROR if the device has a PIN set.
             * Since no known CDMA modems support AT+CPIN? we can consider the
             * device a GSM device if it returns a non-error response to AT+CPIN?.
             */
            task_priv->probed_caps = parse_cpin (response);
            break;
        case PROBE_STATE_CGMM:
            /* Some models (BUSlink SCWi275u) stick stupid stuff in the CGMM
             * response but at least it allows us to identify them.
             */
            task_priv->probed_caps = parse_cgmm (response);
            break;
        default:
            break;
        }

        if (task_priv->probed_caps & CAP_GSM_OR_CDMA) {
            probe_complete (task);
            return;
        }
    }

    task_priv->probe_state++;

    /* Try a different command */
    switch (task_priv->probe_state) {
    case PROBE_STATE_GCAP_TRY2:
    case PROBE_STATE_GCAP_TRY3:
        mm_at_serial_port_queue_command (port, "+GCAP", 3, parse_response, task);
        break;
    case PROBE_STATE_ATI:
        /* After the last GCAP attempt, try ATI */
        mm_at_serial_port_queue_command (port, "I", 3, parse_response, task);
        break;
    case PROBE_STATE_CPIN:
        /* After the ATI attempt, try CPIN */
        mm_at_serial_port_queue_command (port, "+CPIN?", 3, parse_response, task);
        break;
    case PROBE_STATE_CGMM:
        /* After the CPIN attempt, try CGMM */
        mm_at_serial_port_queue_command (port, "+CGMM", 3, parse_response, task);
        break;
    default:
        /* Probably not GSM or CDMA */
        probe_complete (task);
        break;
    }
}