diff options
| -rw-r--r-- | include/gsmd/gsmd.h | 3 | ||||
| -rw-r--r-- | src/gsmd/Makefile.am | 23 | ||||
| -rw-r--r-- | src/gsmd/atcmd.c | 3 | ||||
| -rw-r--r-- | src/gsmd/gsmd.c | 22 | ||||
| -rw-r--r-- | src/gsmd/machine.c | 139 | ||||
| -rw-r--r-- | src/gsmd/machine_generic.c | 61 | ||||
| -rw-r--r-- | src/gsmd/machine_tihtc.c | 71 | ||||
| -rw-r--r-- | src/gsmd/vendor.c | 32 | ||||
| -rw-r--r-- | src/gsmd/vendor_qc.c | 104 | ||||
| -rw-r--r-- | src/gsmd/vendor_ti.c | 8 | ||||
| -rw-r--r-- | src/gsmd/vendor_tihtc.c | 305 | 
11 files changed, 755 insertions, 16 deletions
diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h index 044f65d..65ca568 100644 --- a/include/gsmd/gsmd.h +++ b/include/gsmd/gsmd.h @@ -7,6 +7,7 @@  #include <common/linux_list.h> +#include <gsmd/machineplugin.h>  #include <gsmd/vendorplugin.h>  #include <gsmd/select.h>  #include <gsmd/state.h> @@ -58,12 +59,14 @@ struct gsmd;  struct gsmd {  	unsigned int flags; +	int interpreter_ready;  	struct gsmd_fd gfd_uart;  	struct gsmd_fd gfd_sock;  	struct llparser llp;  	struct llist_head users;  	struct llist_head pending_atcmds;	/* our busy gsmd_atcmds */  	struct llist_head busy_atcmds;	/* our busy gsmd_atcmds */ +	struct gsmd_machine_plugin *machinepl;  	struct gsmd_vendor_plugin *vendorpl;  	struct gsmd_device_state dev_state; diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am index 940f610..a308739 100644 --- a/src/gsmd/Makefile.am +++ b/src/gsmd/Makefile.am @@ -1,11 +1,26 @@  INCLUDES = $(all_includes) -I$(top_srcdir)/include  AM_CFLAGS = -std=gnu99 +plugindir = $(libdir)/gsmd  sbin_PROGRAMS = gsmd -gsmd_SOURCES = gsmd.c atcmd.c select.c vendor.c usock.c unsolicited.c log.c \ -	       vendor_ti.c talloc.c operator_cache.c ext_response.c -#gsmd_LDADD = ../libgsmd/libgsmd.la -#gsmd_LDFLAGS = -dynamic +gsmd_CFLAGS = -D PLUGINDIR=\"$(plugindir)\" +gsmd_SOURCES = gsmd.c atcmd.c select.c machine.c vendor.c unsolicited.c log.c \ +	       usock.c talloc.c operator_cache.c ext_response.c +gsmd_LDADD = -ldl +gsmd_LDFLAGS = -Wl,--export-dynamic + +plugin_LTLIBRARIES = libgsmd-machine_generic.la \ +		     libgsmd-machine_tihtc.la \ +		     libgsmd-vendor_ti.la \ +		     libgsmd-vendor_tihtc.la \ +		     libgsmd-vendor_qc.la + +libgsmd_machine_generic_la_SOURCES = machine_generic.c +libgsmd_machine_tihtc_la_SOURCES = machine_tihtc.c + +libgsmd_vendor_ti_la_SOURCES = vendor_ti.c +libgsmd_vendor_tihtc_la_SOURCES = vendor_tihtc.c +libgsmd_vendor_qc_la_SOURCES = vendor_qc.c  noinst_HEADERS = gsmd.h diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c index 27c0a41..4df12dc 100644 --- a/src/gsmd/atcmd.c +++ b/src/gsmd/atcmd.c @@ -183,6 +183,7 @@ static int ml_parse(const char *buf, int len, void *ctx)  	 * an empty string or that 'ready' string, we need to init the modem */  	if (strlen(buf) == 0 ||  	    !strcmp(buf, "AT-Command Interpreter ready")) { +		g->interpreter_ready = 1;  		gsmd_initsettings(g);  		return 0;  	} @@ -375,7 +376,7 @@ static int atcmd_select_cb(int fd, unsigned int what, void *data)  	}  	/* write pending commands to UART */ -	if (what & GSMD_FD_WRITE) { +	if ((what & GSMD_FD_WRITE) && g->interpreter_ready) {  		struct gsmd_atcmd *pos, *pos2;  		llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) {  			len = strlen(pos->buf); diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c index 62eb2e0..12c7c3f 100644 --- a/src/gsmd/gsmd.c +++ b/src/gsmd/gsmd.c @@ -261,6 +261,21 @@ int main(int argc, char **argv)  		exit(1);  	} +	if (gsmd_machine_plugin_init(&g) < 0) { +		fprintf(stderr, "no machine plugins found\n"); +		exit(1); +	} + +	/* select a machine plugin and load possible vendor plugins */ +	gsmd_machine_plugin_find(&g); + +	/* initialize the machine plugin */ +	if (g.machinepl->init && +	    (g.machinepl->init(&g, fd) < 0)) { +		fprintf(stderr, "couldn't initialize machine plugin\n"); +		exit(1); +	} +  	if (atcmd_init(&g, fd) < 0) {  		fprintf(stderr, "can't initialize UART device\n");  		exit(1); @@ -282,12 +297,11 @@ int main(int argc, char **argv)  		setsid();  	} -	/* FIXME: do this dynamically */ -	ticalypso_init(); - +	/* select a vendor plugin */  	gsmd_vendor_plugin_find(&g); -	gsmd_initsettings(&g); +	if (g.interpreter_ready) +		gsmd_initsettings(&g);  	gsmd_opname_init(&g); diff --git a/src/gsmd/machine.c b/src/gsmd/machine.c new file mode 100644 index 0000000..40c08cb --- /dev/null +++ b/src/gsmd/machine.c @@ -0,0 +1,139 @@ +/* gsmd machine plugin core + * + * Written by Philipp Zabel <philipp.zabel@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <dlfcn.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include <common/linux_list.h> + +#include "gsmd.h" + +#include <gsmd/gsmd.h> +#include <gsmd/machineplugin.h> + +static LLIST_HEAD(machinepl_list); + +int gsmd_machine_plugin_register(struct gsmd_machine_plugin *pl) +{ +	llist_add(&pl->list, &machinepl_list); + +	return 0; +} + +void gsmd_machine_plugin_unregister(struct gsmd_machine_plugin *pl) +{ +	llist_del(&pl->list); +} + +int gsmd_machine_plugin_find(struct gsmd *g) +{ +	struct gsmd_machine_plugin *pl; + +	if (g->machinepl) +		return -EEXIST; + +	llist_for_each_entry(pl, &machinepl_list, list) { +		if (pl->detect(g) == 1) { +			DEBUGP("selecting machine plugin \"%s\"\n", pl->name); +			g->machinepl = pl; +			return 1; +		} +	} + +	return 0; +} + +int gsmd_machine_plugin_load(char *name) +{ +	int rc = -1; +	void *plugin; +	struct gsmd_machine_plugin *pl; +	char buf[128]; + +	DEBUGP("loading machine plugin \"%s\"\n", name); + +	snprintf(buf, sizeof(buf), PLUGINDIR"/libgsmd-machine_%s.so", name); + +	plugin = dlopen(buf, RTLD_LAZY); +	if (!plugin) { +		fprintf(stderr, "gsmd_machine_plugin_load: %s\n", dlerror()); +		return -1; +	} + +	pl = dlsym(plugin, "gsmd_machine_plugin"); +	if (pl) +		rc = gsmd_machine_plugin_register(pl); +	else +		dlclose(plugin); + +	return rc; +} + +/* maybe /etc/gsmd/cpuinfo */ +struct machines { +	char *cpuinfo; +	char *machine; +	char *vendor; +} machines[] = { +	{ "GTA01",		"generic",	"ti" }, +	{ "HTC Blueangel",	"tihtc",	"tihtc" }, +	{ "HTC Himalaya",	"tihtc",	"tihtc" }, +	{ "HTC Magician",	"tihtc",	"tihtc" }, +	{ "HTC Universal",	"generic",	"qc" }, +	{ NULL, NULL, NULL }, +}; + +int gsmd_machine_plugin_init(struct gsmd *g, int fd) +{ +	FILE *cpuinfo; +	char buf[1024]; +	char *line, *machine = NULL; +	int i, rc; + +	cpuinfo = fopen("/proc/cpuinfo", "r"); +	fread(buf, sizeof(buf), 1, cpuinfo); +	fclose(cpuinfo); +	buf[sizeof(buf)-1] = '\0'; + +	line = strtok(buf, "\n"); +	while (line = strtok(NULL, "\n")) { +		if (strncmp(line, "Hardware\t: ", 11) == 0) { +			machine = line+11; +			break; +		} +	} +	/* FIXME: do this dynamically */ +	for (i = 0; machines[i].cpuinfo; i++) { +		if (machine && strcmp(machine, machines[i].cpuinfo) == 0) { +			DEBUGP("detected %s\n", machine); +			rc = gsmd_machine_plugin_load(machines[i].machine); +			rc |= gsmd_vendor_plugin_load(machines[i].vendor); +			return rc; +		} +	} +	/* load generic machine and all vendor plugins */ +	rc = gsmd_machine_plugin_load("generic"); +	gsmd_vendor_plugin_load("ti"); +	gsmd_vendor_plugin_load("tihtc"); +	gsmd_vendor_plugin_load("qc"); +	return rc; +} diff --git a/src/gsmd/machine_generic.c b/src/gsmd/machine_generic.c new file mode 100644 index 0000000..b9e960a --- /dev/null +++ b/src/gsmd/machine_generic.c @@ -0,0 +1,61 @@ +/* generic machine plugin + * + * Written by Philipp Zabel <philipp.zabel@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + +#include "gsmd.h" + +#include <gsmd/gsmd.h> +#include <gsmd/usock.h> +#include <gsmd/event.h> +#include <gsmd/talloc.h> +#include <gsmd/extrsp.h> +#include <gsmd/machineplugin.h> + +static int generic_detect(struct gsmd *g) +{ +	/* FIXME: do actual detection of machine if we have multiple machines */ +	return 1; +} + +static int generic_init(struct gsmd *g, int fd) +{ +	int rc; + +	/* +	 * We assume that the GSM chipset can take +	 * input immediately, so we don't have to +	 * wait for the "AT-Command Interpreter ready" +	 * message before trying to send commands. +	 */ +	g->interpreter_ready = 1; + +	return 0; +} + +struct gsmd_machine_plugin gsmd_machine_plugin = { +	.name = "generic", +	.detect = &generic_detect, +	.init = &generic_init, +}; diff --git a/src/gsmd/machine_tihtc.c b/src/gsmd/machine_tihtc.c new file mode 100644 index 0000000..e1fa4da --- /dev/null +++ b/src/gsmd/machine_tihtc.c @@ -0,0 +1,71 @@ +/* TI [Calypso] with HTC firmware machine plugin + * + * Written by Philipp Zabel <philipp.zabel@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/ioctl.h> + +#include "gsmd.h" + +#include <gsmd/gsmd.h> +#include <gsmd/usock.h> +#include <gsmd/event.h> +#include <gsmd/talloc.h> +#include <gsmd/extrsp.h> +#include <gsmd/machineplugin.h> + +#define N_TIHTC 17 + +static int tihtc_detect(struct gsmd *g) +{ +	/* FIXME: do actual detection of machine if we have multiple machines */ +	return 1; +} + +static int tihtc_init(struct gsmd *g, int fd) +{ +	int ldisc = N_TIHTC; +	int rc; + +	/* +	 * Himalaya, Blueangel, Alpine and Magican +	 * power up their GSM chipsets when the +	 * tty is opened. Wait for the "AT-Command +	 * Interpreter ready" message before trying +	 * to send commands. +	 */ +	g->interpreter_ready = 0; + +	/* Set the line discipline to N_TIHTC */ +	rc = ioctl(fd, TIOCSETD, &ldisc); +	if (rc < 0) +		fprintf(stderr, "can't set line discipline\n"); + +	return rc; +} + +struct gsmd_machine_plugin gsmd_machine_plugin = { +	.name = "TI Calypso / HTC firmware", +	.detect = &tihtc_detect, +	.init = &tihtc_init, +}; diff --git a/src/gsmd/vendor.c b/src/gsmd/vendor.c index daa348a..826a7ef 100644 --- a/src/gsmd/vendor.c +++ b/src/gsmd/vendor.c @@ -20,7 +20,11 @@   *   */  +#include <dlfcn.h>  #include <errno.h> +#include <stdio.h> +#include <string.h> +#include <limits.h>  #include <common/linux_list.h> @@ -52,6 +56,7 @@ int gsmd_vendor_plugin_find(struct gsmd *g)  	llist_for_each_entry(pl, &vendorpl_list, list) {  		if (pl->detect(g) == 1) { +			DEBUGP("selecting vendor plugin \"%s\"\n", pl->name);  			g->vendorpl = pl;  			return 1;  		} @@ -59,3 +64,30 @@ int gsmd_vendor_plugin_find(struct gsmd *g)  	return 0;  } + +int gsmd_vendor_plugin_load(char *name) +{ +	int rc = -1; +	void *lib; +	struct gsmd_vendor_plugin *pl; +	char buf[PATH_MAX+1]; + +	DEBUGP("loading vendor plugin \"%s\"\n", name); + +	buf[PATH_MAX] = '\0'; +	snprintf(buf, sizeof(buf), PLUGINDIR "/libgsmd-vendor_%s.so", name); + +	lib = dlopen(buf, RTLD_LAZY); +	if (!lib) { +		fprintf(stderr, "gsmd_vendor_plugin_load: %s\n", dlerror()); +		return -1; +	} + +	pl = dlsym(lib, "gsmd_vendor_plugin"); +	if (pl) +		rc = gsmd_vendor_plugin_register(pl); +	else +		dlclose(lib); + +	return rc; +} diff --git a/src/gsmd/vendor_qc.c b/src/gsmd/vendor_qc.c new file mode 100644 index 0000000..2bb74bb --- /dev/null +++ b/src/gsmd/vendor_qc.c @@ -0,0 +1,104 @@ +/* Qualcomm [msm6250] gsmd plugin + * + * Written by Philipp Zabel <philipp.zabel@gmail.com> + * based on vendor_ti.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + +#include "gsmd.h" + +#include <gsmd/gsmd.h> +#include <gsmd/usock.h> +#include <gsmd/event.h> +#include <gsmd/talloc.h> +#include <gsmd/extrsp.h> +#include <gsmd/atcmd.h> +#include <gsmd/vendorplugin.h> +#include <gsmd/unsolicited.h> + +static int htccsq_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_SIGNAL, +					     sizeof(*aux)); +	static int rssi_table[] = { 0,5,10,15,20,25,99 }; /* FIXME */ +	unsigned int i; + +	DEBUGP("entering htccsq_parse param=`%s'\n", param); +	if (!ucmd) +		return -EINVAL; + + +	aux = (struct gsmd_evt_auxdata *) ucmd->buf; + +	i = atoi(buf); +	if (i > 6) +		i = 6; +	aux->u.signal.sigq.rssi = rssi_table[atoi(buf)]; +	aux->u.signal.sigq.ber = 99; + +	DEBUGP("sending EVT_SIGNAL\n"); +	usock_evt_send(gsmd, ucmd, GSMD_EVT_SIGNAL); + +	return 0; + +out_free_io: +	free(ucmd); +	return -EIO; +} + +static const struct gsmd_unsolicit qc_unsolicit[] = { +	{ "@HTCCSQ",	&htccsq_parse },	/* Signal Quality */ + +	/* FIXME: parse the below and generate the respective events */ + +	/* %CGREG: reports extended information about GPRS registration state */ +}; + +static int qc_detect(struct gsmd *g) +{ +	/* FIXME: do actual detection of vendor if we have multiple vendors */ +	/* open /proc/cpuinfo and check for HTC Universal? */ +	return 1; +} + +static int qc_initsettings(struct gsmd *g) +{ +	int rc; +	struct gsmd_atcmd *cmd; + +	/* enable @HTCCSQ: signal quality reports */ +	rc |= gsmd_simplecmd(g, "AT@HTCCSQ=1"); + +	return rc; +} + +struct gsmd_vendor_plugin gsmd_vendor_plugin = { +	.name = "Qualcomm msm6250", +	.num_unsolicit = ARRAY_SIZE(qc_unsolicit), +	.unsolicit = qc_unsolicit, +	.detect = &qc_detect, +	.initsettings = &qc_initsettings, +}; diff --git a/src/gsmd/vendor_ti.c b/src/gsmd/vendor_ti.c index 049433e..555afcb 100644 --- a/src/gsmd/vendor_ti.c +++ b/src/gsmd/vendor_ti.c @@ -301,16 +301,10 @@ static int ticalypso_initsettings(struct gsmd *g)  	return rc;  } -static struct gsmd_vendor_plugin plugin_ticalypso = { +struct gsmd_vendor_plugin gsmd_vendor_plugin = {  	.name = "TI Calypso",  	.num_unsolicit = ARRAY_SIZE(ticalypso_unsolicit),  	.unsolicit = ticalypso_unsolicit,  	.detect = &ticalypso_detect,  	.initsettings = &ticalypso_initsettings,  }; -  -/* FIXME: this will be _init() when we make this a plugin */ -int ticalypso_init(void) -{ -	return gsmd_vendor_plugin_register(&plugin_ticalypso); -} diff --git a/src/gsmd/vendor_tihtc.c b/src/gsmd/vendor_tihtc.c new file mode 100644 index 0000000..8add5f7 --- /dev/null +++ b/src/gsmd/vendor_tihtc.c @@ -0,0 +1,305 @@ +/* TI [Calypso] with HTC firmware gsmd plugin + * + * Written by Philipp Zabel <philipp.zabel@gmail.com> + * based on vendor_ti.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + +#include "gsmd.h" + +#include <gsmd/gsmd.h> +#include <gsmd/usock.h> +#include <gsmd/event.h> +#include <gsmd/talloc.h> +#include <gsmd/extrsp.h> +#include <gsmd/atcmd.h> +#include <gsmd/vendorplugin.h> +#include <gsmd/unsolicited.h> + +static int gsmd_test_atcb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ +	printf("`%s' returned `%s'\n", cmd->buf, resp); +	return 0; +} + +int gsmd_simplecmd(struct gsmd *gsmd, char *cmdtxt) +{ +	struct gsmd_atcmd *cmd; +	cmd = atcmd_fill(cmdtxt, strlen(cmdtxt)+1, &gsmd_test_atcb, NULL, 0); +	if (!cmd) +		return -ENOMEM; + +	return atcmd_submit(gsmd, cmd); +} + + +#if 0 +#include "vendorplugin.h" + +static int +ti_getopt(struct gsmd *gh, int optname, void *optval, int *optlen) +{ + 	switch (optname) { +	case GSMD_OPT_CIPHER_IND: +		/* FIXME: send AT%CPRI=? */ +		break; +	default: +		return -EINVAL; +	} +} + +static int +ti_setopt(struct gsmd *gh, int optname, const void *optval, int optlen) +{ +	switch (optname) { +	case GSMD_OPT_CIPHER_IND: +		/* FIXME: send AT%CPRI= */ +		break; +	default: +		return -EINVAL; +	} +} + +#endif + + +static int htccsq_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_SIGNAL, +					     sizeof(*aux)); + +	DEBUGP("entering htccsq_parse param=`%s'\n", param); +	if (!ucmd) +		return -EINVAL; + + +	aux = (struct gsmd_evt_auxdata *) ucmd->buf; + +	/* FIXME: contains values 1-5, should be mapped to 0-31 somehow? */ +	/* 2 --> 11 */ +	aux->u.signal.sigq.rssi = atoi(buf); +	aux->u.signal.sigq.ber = 99; + +	DEBUGP("sending EVT_SIGNAL\n"); +	usock_evt_send(gsmd, ucmd, GSMD_EVT_SIGNAL); + +	return 0; + +out_free_io: +	free(ucmd); +	return -EIO; +} + +static int cpri_parse(char *buf, int len, const char *param, struct gsmd *gsmd) +{ +	char *tok1, *tok2; + +	tok1 = strtok(buf, ","); +	if (!tok1) +		return -EIO; + +	tok2 = strtok(NULL, ","); +	if (!tok2) { +		switch (atoi(tok1)) { +		case 0: +			gsmd->dev_state.ciph_ind.flags &= ~GSMD_CIPHIND_ACTIVE; +			break; +		case 1: +			gsmd->dev_state.ciph_ind.flags |= GSMD_CIPHIND_ACTIVE; +			break; +		case 2: +			gsmd->dev_state.ciph_ind.flags |= GSMD_CIPHIND_DISABLED_SIM; +			break; +		} +	} else { +		struct gsmd_evt_auxdata *aux; +		struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, +							   GSMD_EVT_CIPHER, +							   sizeof(*aux)); +		if (!ucmd) +			return -ENOMEM; + +		aux = (struct gsmd_evt_auxdata *) ucmd->buf; + +		aux->u.cipher.net_state_gsm = atoi(tok1); +		aux->u.cipher.net_state_gsm = atoi(tok2); + +		usock_evt_send(gsmd, ucmd, GSMD_EVT_CIPHER); +	} + +	return 0; +} + +/* 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_send; + +	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_send; + +out_send: +	usock_evt_send(gsmd, ucmd, GSMD_EVT_OUT_STATUS); + +	return 0; + +out_free_io: +	talloc_free(ucmd); +	return -EIO; +} + +static const struct gsmd_unsolicit tihtc_unsolicit[] = { +	{ "%HTCCSQ",	&htccsq_parse },	/* Signal Quality */ +	{ "%CPRI",	&cpri_parse },	/* Ciphering Indication */ +	{ "%CPI",	&cpi_parse },	/* Call Progress Information */ + +	/* FIXME: parse the below and generate the respective events */ + +	/* %CGREG: reports extended information about GPRS registration state */ +}; + +static int cpi_detect_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ +	struct gsmd *g = ctx; +	struct gsm_extrsp *er; + +	if (strncmp(resp, "%CPI: ", 6)) +		return -EINVAL; +	resp += 6; + +	er = extrsp_parse(cmd, resp); +	if (!er) +		return -EINVAL; + +	if (extrsp_supports(er, 0, 3)) +		return gsmd_simplecmd(g, "AT%CPI=3"); +	else if (extrsp_supports(er, 0, 2)) +		return gsmd_simplecmd(g, "AT%CPI=2"); +	else +		DEBUGP("Call Progress Indication mode 2 or 3 not supported!!\n"); + +	talloc_free(er); +	return 0; +} + +static int tihtc_detect(struct gsmd *g) +{ +	/* FIXME: do actual detection of vendor if we have multiple vendors */ +	/* open /proc/cpuinfo and check for HTC Magician or HTC Blueangel? */ +	/* check for N_TIHTC ldisc? or set it ourselves? */ +	return 1; +} + +static int tihtc_initsettings(struct gsmd *g) +{ +	int rc; +	struct gsmd_atcmd *cmd; + +	/* use %CGREG */ +	//rc |= gsmd_simplecmd(g, "AT%CGREG=3"); +	/* enable %CPRI: ciphering indications */ +	rc |= gsmd_simplecmd(g, "AT%CPRI=1"); +	/* enable %HTCCSQ: signal quality reports */ +	rc |= gsmd_simplecmd(g, "AT%HTCCSQ=1"); +	/* send unsolicited commands at any time */ +	rc |= gsmd_simplecmd(g, "AT%CUNS=0"); + +	/* enable %CPI: call progress indication */ +	cmd = atcmd_fill("AT%CPI=?", 9, &cpi_detect_cb, g, 0); +	if (cmd) +		atcmd_submit(g, cmd); + +	return rc; +} + +struct gsmd_vendor_plugin gsmd_vendor_plugin = { +	.name = "TI Calypso / HTC firmware", +	.num_unsolicit = ARRAY_SIZE(tihtc_unsolicit), +	.unsolicit = tihtc_unsolicit, +	.detect = &tihtc_detect, +	.initsettings = &tihtc_initsettings, +};  | 
