summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/gsmd/gsmd.h3
-rw-r--r--src/gsmd/Makefile.am23
-rw-r--r--src/gsmd/atcmd.c3
-rw-r--r--src/gsmd/gsmd.c22
-rw-r--r--src/gsmd/machine.c139
-rw-r--r--src/gsmd/machine_generic.c61
-rw-r--r--src/gsmd/machine_tihtc.c71
-rw-r--r--src/gsmd/vendor.c32
-rw-r--r--src/gsmd/vendor_qc.c104
-rw-r--r--src/gsmd/vendor_ti.c8
-rw-r--r--src/gsmd/vendor_tihtc.c305
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,
+};
personal git repositories of Harald Welte. Your mileage may vary