diff options
Diffstat (limited to 'src/gsmd')
| -rw-r--r-- | src/gsmd/atcmd.c | 58 | ||||
| -rw-r--r-- | src/gsmd/gsmd.c | 45 | ||||
| -rw-r--r-- | src/gsmd/sms_cb.c | 3 | ||||
| -rw-r--r-- | src/gsmd/unsolicited.c | 35 | ||||
| -rw-r--r-- | src/gsmd/usock.c | 59 | ||||
| -rw-r--r-- | src/gsmd/vendor_ti.c | 93 | 
6 files changed, 240 insertions, 53 deletions
diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c index 7f95465..c5c0a04 100644 --- a/src/gsmd/atcmd.c +++ b/src/gsmd/atcmd.c @@ -14,6 +14,7 @@  #include <gsmd/ts0707.h>  #include <gsmd/gsmd.h>  #include <gsmd/atcmd.h> +#include <gsmd/talloc.h>  #include <gsmd/unsolicited.h>  /* libgsmd / gsmd AT command interpreter / parser / constructor @@ -22,6 +23,8 @@   * Written for First International Computer, Inc., Taiwan   */  +static void *__atcmd_ctx; +  enum final_result_codes {  	GSMD_RESULT_OK = 0,  	GSMD_RESULT_ERR = 1, @@ -153,7 +156,7 @@ static int parse_final_result(const char *res)  static int ml_parse(const char *buf, int len, void *ctx)  {  	struct gsmd *g = ctx; -	struct gsmd_atcmd *cmd; +	struct gsmd_atcmd *cmd = NULL;  	int rc = 0, final = 0;  	DEBUGP("buf=`%s'(%d)\n", buf, len); @@ -165,7 +168,9 @@ static int ml_parse(const char *buf, int len, void *ctx)  	/* responses come in order, so first response has to be for first  	 * command we sent, i.e. first entry in list */ -	cmd = llist_entry(g->busy_atcmds.next, struct gsmd_atcmd, list); +	if (!llist_empty(&g->busy_atcmds)) +		cmd = llist_entry(g->busy_atcmds.next, +				  struct gsmd_atcmd, list);  	/* we have to differentiate between the following cases:  	 * @@ -194,15 +199,16 @@ static int ml_parse(const char *buf, int len, void *ctx)  			unsigned long err_nr;  			err_nr = strtoul(colon+1, NULL, 10);  			DEBUGP("error number %lu\n", err_nr); -			cmd->ret = err_nr; +			if (cmd) +				cmd->ret = err_nr;  			final = 1;  			goto final_cb;  		} -		if (strncmp(buf, &cmd->buf[2], colon-buf)) { +		if (!cmd || strncmp(buf, &cmd->buf[2], colon-buf)) {  			/* Assuming Case 'B' */  			DEBUGP("extd reply `%s' to cmd `%s', must be " -			       "unsolicited\n", buf, &cmd->buf[2]); +			       "unsolicited\n", buf, cmd ? &cmd->buf[2] : "NONE");  			colon++;  			if (colon > buf+len)  				colon = NULL; @@ -216,19 +222,21 @@ static int ml_parse(const char *buf, int len, void *ctx)  			/* contine, not 'B' */  		} -		if (cmd->buf[2] != '+') { -			gsmd_log(GSMD_ERROR, "extd reply to non-extd command?\n"); -			return -EINVAL; -		} +		if (cmd) { +			if (cmd->buf[2] != '+') { +				gsmd_log(GSMD_ERROR, "extd reply to non-extd command?\n"); +				return -EINVAL; +			} -		/* if we survive till here, it's a valid extd response -		 * to an extended command and thus Case 'A' */ +			/* if we survive till here, it's a valid extd response +			 * to an extended command and thus Case 'A' */ -		/* FIXME: solve multi-line responses ! */ -		if (cmd->buflen < len) -			len = cmd->buflen; +			/* FIXME: solve multi-line responses ! */ +			if (cmd->buflen < len) +				len = cmd->buflen; -		memcpy(cmd->buf, buf, len); +			memcpy(cmd->buf, buf, len); +		}  	} else {  		if (!strcmp(buf, "RING")) {  			/* this is the only non-extended unsolicited return @@ -237,18 +245,20 @@ static int ml_parse(const char *buf, int len, void *ctx)  		}  		if (!strcmp(buf, "ERROR") || -		    ((g->flags & GSMD_FLAG_V0) && cmd->buf[0] == '4')) { +		    ((g->flags & GSMD_FLAG_V0) && buf[0] == '4')) {  			/* Part of Case 'C' */  			DEBUGP("unspecified error\n"); -			cmd->ret = 4; +			if (cmd) +				cmd->ret = 4;  			final = 1;  			goto final_cb;  		}  		if (!strncmp(buf, "OK", 2) -		    || ((g->flags & GSMD_FLAG_V0) && cmd->buf[0] == '0')) { +		    || ((g->flags & GSMD_FLAG_V0) && buf[0] == '0')) {  			/* Part of Case 'C' */ -			cmd->ret = 0; +			if (cmd) +				cmd->ret = 0;  			final = 1;  			goto final_cb;  		} @@ -274,8 +284,10 @@ static int ml_parse(const char *buf, int len, void *ctx)  final_cb:  	/* if we reach here, the final result code of a command has been reached */ +	if (!cmd) +		return rc; -	if (cmd->ret != 0) +	if (cmd && cmd->ret != 0)  		generate_event_from_cme(g, cmd->ret);  	if (!cmd->cb) { @@ -292,7 +304,7 @@ final_cb:  	if (final) {  		/* remove from list of currently executing cmds */  		llist_del(&cmd->list); -		free(cmd); +		talloc_free(cmd);  		/* if we're finished with current commands, but still have pending  		 * commands: we want to WRITE again */ @@ -377,7 +389,7 @@ struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen,  	if (rlen > buflen)  		buflen = rlen; -	atcmd = malloc(sizeof(*atcmd)+ buflen); +	atcmd = talloc_size(__atcmd_ctx, sizeof(*atcmd)+ buflen);  	if (!atcmd)  		return NULL; @@ -421,6 +433,8 @@ void atcmd_drain(int fd)  /* init atcmd parser */  int atcmd_init(struct gsmd *g, int sockfd)  { +	__atcmd_ctx = talloc_named_const(gsmd_tallocs, 1, "atcmds"); +  	g->gfd_uart.fd = sockfd;  	g->gfd_uart.when = GSMD_FD_READ;  	g->gfd_uart.data = g; diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c index c56e74c..a16e6b5 100644 --- a/src/gsmd/gsmd.c +++ b/src/gsmd/gsmd.c @@ -5,6 +5,7 @@  #include <errno.h>  #include <fcntl.h>  #include <termios.h> +#include <signal.h>  #define _GNU_SOURCE  #include <getopt.h> @@ -19,6 +20,7 @@  #include <gsmd/select.h>  #include <gsmd/usock.h>  #include <gsmd/vendorplugin.h> +#include <gsmd/talloc.h>  static int gsmd_test_atcb(struct gsmd_atcmd *cmd, void *ctx, char *resp)  { @@ -40,8 +42,22 @@ int gsmd_initsettings(struct gsmd *gsmd)  {  	int rc; +	/* echo on, verbose */  	rc |= gsmd_simplecmd(gsmd, "ATE0V1"); -	rc |= gsmd_simplecmd(gsmd, "AT+CRC=1;+CREG=2;+CMEE=1;+CLIP=1;+COLP=1;+CTZR=1;+CFUN=1"); +	/* use +CRING instead of RING */ +	rc |= gsmd_simplecmd(gsmd, "AT+CRC=1"); +	/* enable +CREG: unsolicited response if registration status changes */ +	rc |= gsmd_simplecmd(gsmd, "AT+CREG=2"); +	/* use +CME ERROR: instead of ERROR */ +	rc |= gsmd_simplecmd(gsmd, "AT+CMEE=1"); +	/* use +CLIP: to indicate CLIP */ +	rc |= gsmd_simplecmd(gsmd, "AT+CLIP=1"); +	/* use +COLP: to indicate COLP */ +	rc |= gsmd_simplecmd(gsmd, "AT+COLP=1"); +	/* use +CTZR: to report time zone changes */ +	rc |= gsmd_simplecmd(gsmd, "AT+CTZR=1"); +	/* power on the phone */ +	rc |= gsmd_simplecmd(gsmd, "AT+CFUN=1");  	if (gsmd->vendorpl && gsmd->vendorpl->initsettings)  		return gsmd->vendorpl->initsettings(gsmd); @@ -108,6 +124,7 @@ static struct option opts[] = {  	{ "device", 1, NULL, 'p' },  	{ "speed", 1, NULL, 's' },  	{ "logfile", 1, NULL, 'l' }, +	{ "leak-report", 0, NULL, 'L' },  	{ 0, 0, 0, 0 }  }; @@ -125,6 +142,20 @@ static void print_help(void)  	       );  } +static void sig_handler(int signr) +{ +	switch (signr) { +	case SIGTERM: +	case SIGINT: +		talloc_report_full(gsmd_tallocs, stderr); +		exit(0); +		break; +	case SIGUSR1: +		talloc_report_full(gsmd_tallocs, stderr); +		break; +	} +} +  int main(int argc, char **argv)  {  	int fd, argch;  @@ -134,12 +165,22 @@ int main(int argc, char **argv)  	char *device = "/dev/ttyUSB0";  	char *logfile = "syslog"; +	signal(SIGTERM, sig_handler); +	signal(SIGINT, sig_handler); +	signal(SIGSEGV, sig_handler); +	signal(SIGUSR1, sig_handler); +	 +	gsmd_tallocs = talloc_named_const(NULL, 1, "GSMD"); +  	/*FIXME: parse commandline, set daemonize, device, ... */ -	while ((argch = getopt_long(argc, argv, "Vdhp:s:l:", opts, NULL)) != -1) { +	while ((argch = getopt_long(argc, argv, "VLdhp:s:l:", opts, NULL)) != -1) {  		switch (argch) {  		case 'V':  			/* FIXME */  			break; +		case 'L': +			talloc_enable_leak_report_full(); +			break;  		case 'd':  			daemonize = 1;  			break; diff --git a/src/gsmd/sms_cb.c b/src/gsmd/sms_cb.c index 5ca8956..5c62333 100644 --- a/src/gsmd/sms_cb.c +++ b/src/gsmd/sms_cb.c @@ -62,8 +62,7 @@ struct gsmd_sms_storage {  static int usock_cpms_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)  {  	struct gsmd_user *gu = ctx; -	struct gsmd_ucmd *ucmd = malloc(sizeof(*ucmd) + -					sizeof(struct gsmd_sms_storage)); +	struct gsmd_ucmd *ucmd = ucmd_alloc(sizeof(struct gsmd_sms_storage));  	DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu); diff --git a/src/gsmd/unsolicited.c b/src/gsmd/unsolicited.c index 57a4e59..0c12f32 100644 --- a/src/gsmd/unsolicited.c +++ b/src/gsmd/unsolicited.c @@ -11,10 +11,11 @@  #include <gsmd/event.h>  #include <gsmd/ts0707.h>  #include <gsmd/unsolicited.h> +#include <gsmd/talloc.h>  struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t len)  { -	struct gsmd_ucmd *ucmd = malloc(sizeof(*ucmd)+len); +	struct gsmd_ucmd *ucmd = ucmd_alloc(len);  	if (!ucmd)  		return NULL; @@ -29,11 +30,10 @@ struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t le  static struct gsmd_ucmd *ucmd_copy(const struct gsmd_ucmd *orig)  { -	int size = sizeof(*orig) + orig->hdr.len; -	struct gsmd_ucmd *copy = malloc(size); +	struct gsmd_ucmd *copy = ucmd_alloc(orig->hdr.len);  	if (copy) -		memcpy(copy, orig, size); +		memcpy(copy, orig, orig->hdr.len);  	return copy;  } @@ -47,17 +47,25 @@ int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt)  	llist_for_each_entry(gu, &gsmd->users, list) {  		if (gu->subscriptions & (1 << evt)) { -			struct gsmd_ucmd *cpy = ucmd_copy(ucmd); -			usock_cmd_enqueue(ucmd, gu); -			num_sent++; -			ucmd = cpy; -			if (!ucmd) { -				fprintf(stderr, "can't allocate memory for copy of ucmd\n"); -				return num_sent; +			if (num_sent == 0) +				usock_cmd_enqueue(ucmd, gu); +			else { +				struct gsmd_ucmd *cpy = ucmd_copy(ucmd); +				if (!cpy) { +					fprintf(stderr,  +						"can't allocate memory for " +						"copy of ucmd\n"); +					return num_sent; +				} +				usock_cmd_enqueue(cpy, gu);  			} +			num_sent++;  		}  	} +	if (num_sent == 0) +		talloc_free(ucmd); +  	return num_sent;  } @@ -101,7 +109,7 @@ static int cring_parse(char *buf, int len, const char *param, struct gsmd *gsmd)  		aux->u.call.type = GSMD_CALL_FAX;  	} else if (!strncmp(param, "GPRS ", 5)) {  		/* FIXME: change event type to GPRS */ -		free(ucmd); +		talloc_free(ucmd);  		return 0;  	}  	/* FIXME: parse all the ALT* profiles, Chapter 6.11 */ @@ -322,7 +330,8 @@ int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param)  			rc = vpl->unsolicit[i].parse(buf, len, colon, g);  			if (rc < 0)   				gsmd_log(GSMD_ERROR, "error %d during parse of " -					 "unsolicied response `%s'\n", rc, buf); +					 "vendor unsolicied response `%s'\n", +					 rc, buf);  			return rc;  		}  	} diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c index 42f8099..4f2ba4f 100644 --- a/src/gsmd/usock.c +++ b/src/gsmd/usock.c @@ -3,6 +3,7 @@  #include <unistd.h>  #include <string.h>  #include <errno.h> +#include <ctype.h>  #include <sys/socket.h>  #include <sys/un.h> @@ -14,6 +15,15 @@  #include <gsmd/select.h>  #include <gsmd/atcmd.h>  #include <gsmd/usock.h> +#include <gsmd/talloc.h> + +static void *__ucmd_ctx, *__gu_ctx; + +struct gsmd_ucmd *ucmd_alloc(int extra_size) +{ +	return talloc_size(__ucmd_ctx,  +			   sizeof(struct gsmd_ucmd) + extra_size); +}  void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu)  { @@ -31,7 +41,7 @@ static int usock_cmd_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)  {  	struct gsmd_user *gu = ctx;  	int rlen = strlen(resp)+1; -	struct gsmd_ucmd *ucmd = malloc(sizeof(*ucmd)+rlen); +	struct gsmd_ucmd *ucmd = ucmd_alloc(rlen);  	DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu); @@ -83,6 +93,8 @@ static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,  {  	struct gsmd_atcmd *cmd = NULL;  	struct gsmd_addr *ga; +	struct gsmd_dtmf *gd; +	int atcmd_len;  	switch (gph->msg_subtype) {  	case GSMD_VOICECALL_DIAL: @@ -92,6 +104,8 @@ static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,  		ga->number[GSMD_ADDR_MAXLEN] = '\0';  		cmd = atcmd_fill("ATD", 5 + strlen(ga->number),  				 &usock_cmd_cb, gu, gph->id); +		if (!cmd) +			return -ENOMEM;  		sprintf(cmd->buf, "ATD%s;", ga->number);  		/* FIXME: number type! */  		break; @@ -101,6 +115,26 @@ static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,  	case GSMD_VOICECALL_ANSWER:  		cmd = atcmd_fill("ATA", 4, &usock_cmd_cb, gu, gph->id);  		break; +	case GSMD_VOICECALL_DTMF: +		if (len < sizeof(*gph) + sizeof(*gd)) +			return -EINVAL; + +		gd = (struct gsmd_dtmf *) ((void *)gph + sizeof(*gph)); +		if (len < sizeof(*gph) + sizeof(*gd) + gd->len) +			return -EINVAL; + +		/* FIXME: we don't yet support DTMF of multiple digits */ +		if (gd->len != 1) +			return -EINVAL; + +		atcmd_len = 1 + strlen("AT+VTS=") + (gd->len * 2); +		cmd = atcmd_fill("AT+VTS=", atcmd_len, &usock_cmd_cb, +				 gu, gph->id); +		if (!cmd) +			return -ENOMEM; + +		sprintf(cmd->buf, "AT+VTS=%c;", gd->dtmf[0]); +		break;  	default:  		return -EINVAL;  	} @@ -173,11 +207,12 @@ static int network_vmail_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)  {  	struct gsmd_user *gu = ctx;  	struct gsmd_voicemail *vmail; -	struct gsmd_ucmd *ucmd = malloc(sizeof(*ucmd)+sizeof(*vmail)); +	struct gsmd_ucmd *ucmd;  	char *comma;  	DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu); +	ucmd = ucmd_alloc(sizeof(*vmail));  	if (!ucmd)  		return -ENOMEM; @@ -218,7 +253,7 @@ static int network_vmail_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)  out_free_einval:  	gsmd_log(GSMD_ERROR, "can't understand voicemail response\n"); -	free(ucmd); +	talloc_free(ucmd);  	return -EINVAL;  } @@ -227,7 +262,7 @@ static struct gsmd_ucmd *gsmd_ucmd_fill(int len, u_int8_t msg_type, u_int8_t msg  {  	struct gsmd_ucmd *ucmd; -	ucmd = malloc(sizeof(*ucmd)+len); +	ucmd = ucmd_alloc(len);  	if (!ucmd)  		return NULL; @@ -256,7 +291,7 @@ static int network_sigq_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)  	gsq->rssi = atoi(resp);  	comma = strchr(resp, ',');  	if (!comma) { -		free(ucmd); +		talloc_free(ucmd);  		return -EIO;  	}  	gsq->ber = atoi(comma+1); @@ -336,12 +371,14 @@ static int gsmd_usock_user_cb(int fd, unsigned int what, void *data)  		/* read data from socket, determine what he wants */  		rcvlen = read(fd, buf, sizeof(buf));  		if (rcvlen == 0) { +			DEBUGP("EOF, this client has just vanished\n");  			/* EOF, this client has just vanished */  			gsmd_unregister_fd(&gu->gfd);  			close(fd);  			/* destroy whole user structure */  			llist_del(&gu->list); -			/* FIXME: delete budy ucmds from finished_ucmds */ +			/* FIXME: delete busy ucmds from finished_ucmds */ +			talloc_free(gu);  			return 0;  		} else if (rcvlen < 0)  			return rcvlen; @@ -370,8 +407,9 @@ static int gsmd_usock_user_cb(int fd, unsigned int what, void *data)  				break;  			} +			DEBUGP("successfully sent cmd %p to user %p, freeing\n", ucmd, gu);  			llist_del(&ucmd->list); -			free(ucmd); +			talloc_free(ucmd);  		}  		if (llist_empty(&gu->finished_ucmds))  			gu->gfd.when &= ~GSMD_FD_WRITE; @@ -389,7 +427,7 @@ static int gsmd_usock_cb(int fd, unsigned int what, void *data)  	/* FIXME: implement this */  	if (what & GSMD_FD_READ) {  		/* new incoming connection */ -		newuser = malloc(sizeof(*newuser)); +		newuser = talloc(__gu_ctx, struct gsmd_user);  		if (!newuser)  			return -ENOMEM; @@ -397,7 +435,7 @@ static int gsmd_usock_cb(int fd, unsigned int what, void *data)  		if (newuser->gfd.fd < 0) {  			DEBUGP("error accepting incoming conn: `%s'\n",  				strerror(errno)); -			free(newuser); +			talloc_free(newuser);  		}  		newuser->gfd.when = GSMD_FD_READ;  		newuser->gfd.data = newuser; @@ -419,6 +457,9 @@ int usock_init(struct gsmd *g)  	struct sockaddr_un sun;  	int fd, rc; +	__ucmd_ctx = talloc_named_const(gsmd_tallocs, 1, "ucmd"); +	__gu_ctx = talloc_named_const(gsmd_tallocs, 1, "gsmd_user"); +  	fd = socket(PF_UNIX, GSMD_UNIX_SOCKET_TYPE, 0);  	if (fd < 0)  		return fd; diff --git a/src/gsmd/vendor_ti.c b/src/gsmd/vendor_ti.c index 53ca7ed..6ec12c5 100644 --- a/src/gsmd/vendor_ti.c +++ b/src/gsmd/vendor_ti.c @@ -43,7 +43,7 @@ ti_setopt(struct gsmd *gh, int optname, const void *optval, int optlen)  #endif -static int csq_parse(char *buf, int len, char *param, +static int csq_parse(char *buf, int len, const char *param,  		     struct gsmd *gsmd)  {  	char *tok; @@ -57,7 +57,7 @@ static int csq_parse(char *buf, int len, char *param,  	aux = (struct gsmd_evt_auxdata *) ucmd->buf; -	tok = strtok(param, ","); +	tok = strtok(buf, ",");  	if (!tok)  		goto out_free_io; @@ -81,12 +81,85 @@ out_free_io:  static int cpri_parse(char *buf, int len, const char *param, struct gsmd *gsmd)  { - +	/* FIXME: parse ciphering indication */  } +/* Call Progress Information */  static int cpi_parse(char *buf, int len, const char *param, struct gsmd *gsmd)  { +	char *tok; +	struct gsmd_evt_auxdata *aux; +	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, +						   GSMD_EVT_OUT_STATUS, +						   sizeof(*aux)); +	 +	DEBUGP("entering cpi_parse param=`%s'\n", param); +	if (!ucmd) +		return -EINVAL; +	 +	aux = (struct gsmd_evt_auxdata *) ucmd->buf; + +	/* Format: cId, msgType, ibt, tch, dir,[mode],[number],[type],[alpha],[cause],line */ + +	/* call ID */ +	tok = strtok(buf, ","); +	if (!tok) +		goto out_free_io; +	/* message type (layer 3) */ +	tok = strtok(NULL, ","); +	if (!tok) +		goto out_free_io; +	aux->u.call_status.prog = atoi(tok); + +	/* in-band tones */ +	tok = strtok(NULL, ","); +	if (!tok) +		goto out_free_io; + +	if (*tok == '1') +		aux->u.call_status.ibt = 1; +	else +		aux->u.call_status.ibt = 0; +	 +	/* TCH allocated */ +	tok = strtok(NULL, ","); +	if (!tok) +		goto out_free_io; + +	if (*tok == '1') +		aux->u.call_status.tch = 1; +	else +		aux->u.call_status.tch = 0; +	 +	/* direction */ +	tok = strtok(NULL, ","); +	if (!tok) +		goto out_free_io; +	 +	switch (*tok) { +	case '0': +	case '1': +	case '2': +	case '3': +		aux->u.call_status.dir = (*tok - '0'); +		break; +	default: +		break; +	} + +	/* mode */ +	tok = strtok(NULL, ","); +	if (!tok) +		goto out_free_io; +	 +	usock_evt_send(gsmd, ucmd, GSMD_EVT_OUT_STATUS); + +	return 0; + +out_free_io: +	free(ucmd); +	return -EIO;  }  static const struct gsmd_unsolicit ticalypso_unsolicit[] = { @@ -114,13 +187,23 @@ static int ticalypso_detect(struct gsmd *g)  static int ticalypso_initsettings(struct gsmd *g)  { -	return gsmd_simplecmd(g, "AT\%CPI=3;\%CPRI=1;\%CSQ=1"); +	int rc; +	/* enable %CPI: call progress indication */ +	rc = gsmd_simplecmd(g, "AT\%CPI=3"); +	/* enable %CPRI: ciphering indications */ +	rc |= gsmd_simplecmd(g, "AT\%CPRI=1"); +	/* enable %CSQ: signal quality reports */ +	rc |= gsmd_simplecmd(g, "AT\%CSQ=1"); +	/* send unsolicited commands at any time */ +	rc |= gsmd_simplecmd(g, "AT\%CUNS=0"); + +	return rc;  }  static struct gsmd_vendor_plugin plugin_ticalypso = {  	.name = "TI Calypso",  	.num_unsolicit = ARRAY_SIZE(ticalypso_unsolicit), -	.unsolicit = &ticalypso_unsolicit, +	.unsolicit = ticalypso_unsolicit,  	.detect = &ticalypso_detect,  	.initsettings = &ticalypso_initsettings,  };  | 
