r2309 - in trunk/src/host/qemu-neo1973: gnokiigsm hw

andrew at sita.openmoko.org andrew at sita.openmoko.org
Wed Jun 20 20:19:15 CEST 2007


Author: andrew
Date: 2007-06-20 20:19:13 +0200 (Wed, 20 Jun 2007)
New Revision: 2309

Modified:
   trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c
   trunk/src/host/qemu-neo1973/hw/modem.c
   trunk/src/host/qemu-neo1973/hw/neo1973.c
Log:
Add a GSM modem power up delay so that the modem doesn't start before gsmd (gsmd should probably be started before the power gpio asserted to avoid timing issue).
Clean up parts of the AT parser.
Disable the AT greeting, make gsmd happy.


Modified: trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c
===================================================================
--- trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c	2007-06-20 14:27:40 UTC (rev 2308)
+++ trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c	2007-06-20 18:19:13 UTC (rev 2309)
@@ -343,19 +343,21 @@
 	char *string_val[];
 };
 
-bool	gn_atem_parse_option(char *buf, struct gn_atem_op *op, char *val)
+bool	gn_atem_parse_option(char **buf, struct gn_atem_op *op, char *val)
 {
 	char	buffer[MAX_LINE_LENGTH], **strval;
 	int	len;
-	if (buf[0] == 0 || (buf[0] == '?' && buf[1] == 0)) {
+	if ((*buf)[0] == 0 || ((*buf)[0] == '?' && (*buf)[1] == 0)) {
+		*buf += strlen(*buf);
 		gsprintf(buffer, MAX_LINE_LENGTH, "%s: %s\r\n", op->op, val);
 		gn_atem_string_out(buffer);
 		return (false);
 	}
 
-	if (*buf++ != '=')
+	if (*(*buf) ++ != '=')
 		return (true);
-	if (!strcasecmp(buf, "?")) {
+	if (!strcasecmp(*buf, "?")) {
+		(*buf) ++;
 		len = gsprintf(buffer, MAX_LINE_LENGTH, "%s: ", op->op);
 		switch (op->type) {
 		case gn_var_string:
@@ -392,17 +394,22 @@
 	switch (op->type) {
 	case gn_var_string:
 		for (strval = op->string_val; *strval; strval++)
-			if (!strcasecmp(buf, *strval)) {
+			if (!strcasecmp(*buf, *strval)) {
 				gsprintf(val, MAX_LINE_LENGTH,
 						"\"%s\"", *strval);
+				*buf += strlen(*buf);
 				return (false);
 			}
 		break;
 
 	case gn_var_bool:
-		if (!strcasecmp(buf, "0") || !strcasecmp(buf, "1")) {
-			strncpy(val, buf, MAX_LINE_LENGTH);
+		switch (gn_atem_num_get(buf)) {
+		case 0:
+			strcpy(val, "0");
 			return (false);
+		case 1:
+			strcpy(val, "1");
+			return (false);
 		}
 		break;
 
@@ -577,7 +584,6 @@
 	},
 };
 
-
 /* Parser for standard AT commands.  cmd_buffer must be null terminated. */
 void	gn_atem_at_parse(char *cmd_buffer)
 {
@@ -585,7 +591,8 @@
 	int regno, val;
 	char str[256];
 
-	if (!cmd_buffer[0]) return;
+	if (!cmd_buffer[0])
+		return;
 
 	if (strncasecmp (cmd_buffer, "AT", 2) != 0) {
 		gn_atem_modem_result(MR_ERROR);
@@ -786,7 +793,7 @@
 			}
 			break;
 
-		  /* Handle AT* commands (Nokia proprietary I think) */
+		/* Handle AT* commands (Nokia proprietary I think) */
 		case '*':
 			buf++;
 			if (!strcasecmp(buf, "NOKIATEST")) {
@@ -807,7 +814,8 @@
 
 			/* AT+WS46 is wireless network selection */
 			if (strncasecmp(buf, "WS46", 3) == 0) {
-				if (!gn_atem_parse_option(buf + 4,
+				buf += 4;
+				if (!gn_atem_parse_option(&buf,
 						&gn_atem_op_ws46, data.ws46))
 					break;
 			}
@@ -851,7 +859,8 @@
 		case '%':
 			buf++;
 			if (strncasecmp(buf, "BAND", 3) == 0) {
-				if (!gn_atem_parse_option(buf + 4,
+				buf += 4;
+				if (!gn_atem_parse_option(&buf,
 						&gn_atem_op_band, data.band))
 					break;
 			}
@@ -1281,101 +1290,103 @@
 
 	/* AT+CSCS is character set selection */
 	if (strncasecmp(*buf, "SCS", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_cscs, data.cscs);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_cscs, data.cscs);
 	}
 
 	/* AT+CIMI is international mobile subscriber identity */
 	if (strcasecmp(*buf, "IMI") == 0) {
+		buf[0] += 3;
 		gn_atem_string_out("QEMU_IMSI\r\n");
 		return (false);
 	}
 
 	/* AT+CMUX is multiplexing mode */
 	if (strncasecmp(*buf, "MUX", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_cmux, data.cmux);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_cmux, data.cmux);
 	}
 
 	/* AT+CSTA is address type selection */
 	if (strncasecmp(*buf, "STA", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_csta, data.csta);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_csta, data.csta);
 	}
 
 	/* AT+CMOD is call mode */
 	if (strncasecmp(*buf, "MOD", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_cmod, data.cmod);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_cmod, data.cmod);
 	}
 
 	/* AT+CBST is bearer service type */
 	if (strncasecmp(*buf, "BST", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_cbst, data.cbst);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_cbst, data.cbst);
 	}
 
 	/* AT+CRLP is radio link protocol */
 	if (strncasecmp(*buf, "RLP", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_crlp, data.crlp);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_crlp, data.crlp);
 	}
 
+	/* AT+CRC is cellular result codes */
+	if (strncasecmp(*buf, "RC", 2) == 0) {
+		buf[0] += 2;
+		return gn_atem_parse_option(buf, &gn_atem_op_crc, data.crc);
+	}
+
 	/* AT+CR is reporting control */
 	if (strncasecmp(*buf, "R", 1) == 0) {
-		return gn_atem_parse_option(buf[0] + 1,
-				&gn_atem_op_cr, data.cr);
+		buf[0] += 1;
+		return gn_atem_parse_option(buf, &gn_atem_op_cr, data.cr);
 	}
 
 	/* AT+CEER is extended error report */
 	if (strncasecmp(*buf, "EER", 3) == 0) {
+		buf[0] += 3;
 		gn_atem_string_out("+CEER: 0,0,5,16,normal call clearing\r\n");
 		return (false);
 	}
 
-	/* AT+CRC is cellular result codes */
-	if (strncasecmp(*buf, "RC", 2) == 0) {
-		return gn_atem_parse_option(buf[0] + 2,
-				&gn_atem_op_crc, data.crc);
-	}
-
 	/* AT+CSNS is single numbering scheme */
 	if (strncasecmp(*buf, "SNS", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_csns, data.csns);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_csns, data.csns);
 	}
 
 	/* AT+CREG is network registration */
 	if (strncasecmp(*buf, "REG", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_creg, data.creg);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_creg, data.creg);
 	}
 
 	/* AT+COPS is PLMN selection */
 	if (strncasecmp(*buf, "OPS", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_cops, data.cops);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_cops, data.cops);
 	}
 
 	/* AT+CPAS is phone activity status */
 	if (strncasecmp(*buf, "PAS", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_cpas, data.cpas);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_cpas, data.cpas);
 	}
 
 	/* AT+CFUN is phone functionality */
 	if (strncasecmp(*buf, "FUN", 3) == 0) {
-		return gn_atem_parse_option(buf[0] + 3,
-				&gn_atem_op_cfun, data.cfun);
+		buf[0] += 3;
+		return gn_atem_parse_option(buf, &gn_atem_op_cfun, data.cfun);
 	}
 
 	if (strncasecmp(*buf, "BC", 2) == 0) {
-		return gn_atem_parse_option(buf[0] + 2,
-				&gn_atem_op_cbc, data.cbc);
+		buf[0] += 2;
+		return gn_atem_parse_option(buf, &gn_atem_op_cbc, data.cbc);
 	}
-	if (strncasecmp(*buf, "CSSN", 2) == 0) {
-		return gn_atem_parse_option(buf[0] + 2,
-				&gn_atem_op_cssn, data.cssn);
+	if (strncasecmp(*buf, "CSSN", 4) == 0) {
+		buf[0] += 4;
+		return gn_atem_parse_option(buf, &gn_atem_op_cssn, data.cssn);
 	}
 
 	return (true);
@@ -1516,13 +1527,12 @@
    command mode - data pump is used when connected.  */
 void	gn_atem_string_out(char *buffer)
 {
-	int	count = 0;
 	char	out_char;
 
-	while (count < strlen(buffer)) {
+	while (*buffer) {
 
 		/* Translate CR/LF/BS as appropriate */
-		switch (buffer[count]) {
+		switch (*buffer) {
 			case '\r':
 				out_char = ModemRegisters[REG_CR];
 				break;
@@ -1533,11 +1543,11 @@
 				out_char = ModemRegisters[REG_BS];
 				break;
 			default:
-				out_char = buffer[count];
+				out_char = *buffer;
 				break;
 		}
 
 		sm->info->write(sm->info->opaque, "%c", out_char);
-		count++;
+		buffer ++;
 	}
 }

Modified: trunk/src/host/qemu-neo1973/hw/modem.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/modem.c	2007-06-20 14:27:40 UTC (rev 2308)
+++ trunk/src/host/qemu-neo1973/hw/modem.c	2007-06-20 18:19:13 UTC (rev 2309)
@@ -167,8 +167,10 @@
     case CHR_IOCTL_MODEM_HANDSHAKE:
         if (!s->enable)
             return -ENOTSUP;
+#if 0
         if (*(int *) arg)
             modem_resp(s, "AT-Command Interpreter Ready\r\nOK\r\n");
+#endif
         break;
 
     default:

Modified: trunk/src/host/qemu-neo1973/hw/neo1973.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/neo1973.c	2007-06-20 14:27:40 UTC (rev 2308)
+++ trunk/src/host/qemu-neo1973/hw/neo1973.c	2007-06-20 18:19:13 UTC (rev 2309)
@@ -70,6 +70,7 @@
     i2c_slave *wm;
     i2c_slave *lcm;
     CharDriverState *modem;
+    QEMUTimer *modem_timer;
     qemu_irq *kbd_pic;
     const char *kernel;
 };
@@ -102,10 +103,29 @@
         neo_printf("Modem reset.\n");
 }
 
+static void neo_modem_switch_tick(void *opaque)
+{
+    struct neo_board_s *s = (struct neo_board_s *) opaque;
+    modem_enable(s->modem, 1);
+}
+
 static void neo_modem_switch(void *opaque, int line, int level)
 {
     struct neo_board_s *s = (struct neo_board_s *) opaque;
-    modem_enable(s->modem, level);
+
+    /* The GSM modem seems to take a little while to power up and
+     * start talking to the serial.  This turns out to be critical because
+     * before gsmd runs and disables Local Echo for the UART, everything
+     * that the modem outputs is looped back and confuses the parser.
+     */
+    if (level)
+        qemu_mod_timer(s->modem_timer, qemu_get_clock(vm_clock) +
+                        (ticks_per_sec >> 4));
+    else {
+        qemu_del_timer(s->modem_timer);
+        modem_enable(s->modem, 0);
+    }
+
     neo_printf("Modem powered %s.\n", level ? "up" : "down");
 }
 
@@ -359,10 +379,9 @@
 static void neo_gsm_setup(struct neo_board_s *s)
 {
     s->modem = modem_init();
+    s->modem_timer = qemu_new_timer(vm_clock, neo_modem_switch_tick, s);
 
-#if 0
     s3c_uart_attach(s->cpu->uart[0], s->modem);
-#endif
 }
 
 static void neo_reset(void *opaque)





More information about the commitlog mailing list