diff options
Diffstat (limited to 'src/gsmd')
-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 |
10 files changed, 752 insertions, 16 deletions
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, +}; |