diff options
author | OpenEmbedded Project <openembedded-devel@lists.openembedded.org> | 2007-10-07 00:34:07 +0000 |
---|---|---|
committer | OpenEmbedded Project <openembedded-devel@lists.openembedded.org> | 2007-10-07 00:34:07 +0000 |
commit | 2f8521c6d1173dd650d9ae2bba8c18e690fa3b1f (patch) | |
tree | 06bc2b997b60797bc42f696f3427f92890089d2b /packages/gsm | |
parent | 0d0bf315513039bd8560ac91865c7174e789d675 (diff) | |
parent | 6e90aae26efa66553063b74b9afa9563b70fb982 (diff) |
merge of '603b2d0c7e4ad80e5779bd3bbdb822331cc0ea2b'
and '6ab53da82d157971966f5a17d0c29d54df22cac9'
Diffstat (limited to 'packages/gsm')
19 files changed, 2227 insertions, 136 deletions
diff --git a/packages/gsm/files/0001-Introduce-ports.patch b/packages/gsm/files/0001-Introduce-ports.patch new file mode 100644 index 0000000000..b3ba3cb957 --- /dev/null +++ b/packages/gsm/files/0001-Introduce-ports.patch @@ -0,0 +1,710 @@ +From 516d67c679101d1503dbd4c0613bcd6ff1b604e4 Mon Sep 17 00:00:00 2001 +From: Andrzej Zaborowski <balrog@zabor.org> +Date: Wed, 19 Sep 2007 14:03:28 +0200 +Subject: [PATCH] Introduce ports. + +--- + include/gsmd/atcmd.h | 2 +- + include/gsmd/gsmd.h | 7 +- + include/gsmd/uart.h | 28 ++++++ + include/gsmd/vendorplugin.h | 4 +- + src/gsmd/Makefile.am | 2 +- + src/gsmd/atcmd.c | 177 +++++++++++++++++--------------------- + src/gsmd/gsmd.c | 64 ++------------ + src/gsmd/uart.c | 202 +++++++++++++++++++++++++++++++++++++++++++ + 8 files changed, 328 insertions(+), 158 deletions(-) + create mode 100644 include/gsmd/uart.h + create mode 100644 src/gsmd/uart.c + +diff --git a/include/gsmd/atcmd.h b/include/gsmd/atcmd.h +index 0d6c62a..a1af6a0 100644 +--- a/include/gsmd/atcmd.h ++++ b/include/gsmd/atcmd.h +@@ -9,7 +9,7 @@ typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp); + + extern struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id); + extern int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd); +-extern int atcmd_init(struct gsmd *g, int sockfd); ++extern int atcmd_init(struct gsmd *g, struct gsmd_port *port); + extern void atcmd_drain(int fd); + + #endif /* __GSMD__ */ +diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h +index ed334f1..4afdf66 100644 +--- a/include/gsmd/gsmd.h ++++ b/include/gsmd/gsmd.h +@@ -10,6 +10,7 @@ + #include <gsmd/machineplugin.h> + #include <gsmd/vendorplugin.h> + #include <gsmd/select.h> ++#include <gsmd/uart.h> + #include <gsmd/state.h> + + void *gsmd_tallocs; +@@ -52,6 +53,7 @@ enum llparse_state { + #define MLPARSE_BUF_SIZE 65535 + + struct llparser { ++ struct gsmd_port *port; + enum llparse_state state; + unsigned int len; + unsigned int flags; +@@ -70,7 +72,7 @@ struct gsmd; + struct gsmd { + unsigned int flags; + int interpreter_ready; +- struct gsmd_fd gfd_uart; ++ struct gsmd_uart uart; + struct gsmd_fd gfd_sock; + struct llparser llp; + struct llist_head users; +@@ -81,9 +83,10 @@ struct gsmd { + struct gsmd_device_state dev_state; + + struct llist_head operators; /* cached list of operator names */ +- unsigned char *mlbuf; /* ml_parse buffer */ ++ char *mlbuf; /* ml_parse buffer */ + unsigned int mlbuf_len; + int mlunsolicited; ++ int clear_to_send; + }; + + struct gsmd_user { +diff --git a/include/gsmd/uart.h b/include/gsmd/uart.h +new file mode 100644 +index 0000000..a006fa7 +--- /dev/null ++++ b/include/gsmd/uart.h +@@ -0,0 +1,28 @@ ++#ifndef __GSMD_UART_H ++#define __GSMD_UART_H ++ ++#ifdef __GSMD__ ++ ++struct gsmd_port { ++ int (*write)(struct gsmd_port *port, const char data[], int len); ++ int (*set_break)(struct gsmd_port *port, int state); ++ /* more parameters here */ ++ int (*newdata_cb)(void *opaque, const char data[], int len); ++ void *newdata_opaque; ++}; ++ ++struct gsmd_uart { ++ struct gsmd_port port; ++ struct gsmd_fd gfd; ++ char txfifo[2048]; ++ int tx_start; ++ int tx_len; ++}; ++ ++extern int set_baudrate(int fd, int baudrate, int hwflow); ++extern void uart_drain(int fd); ++extern int uart_init(struct gsmd_uart *uart, int sockfd); ++ ++#endif /* __GSMD__ */ ++ ++#endif +diff --git a/include/gsmd/vendorplugin.h b/include/gsmd/vendorplugin.h +index 1911fef..1c82790 100644 +--- a/include/gsmd/vendorplugin.h ++++ b/include/gsmd/vendorplugin.h +@@ -11,8 +11,8 @@ struct gsmd_unsolicit; + + struct gsmd_vendor_plugin { + struct llist_head list; +- unsigned char *name; +- unsigned char *ext_chars; ++ char *name; ++ char *ext_chars; + unsigned int num_unsolicit; + const struct gsmd_unsolicit *unsolicit; + int (*detect)(struct gsmd *g); +diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am +index 9ac45ee..110b757 100644 +--- a/src/gsmd/Makefile.am ++++ b/src/gsmd/Makefile.am +@@ -13,7 +13,7 @@ sbin_PROGRAMS = gsmd + 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 timer.c operator_cache.c ext_response.c \ +- sms_cb.c sms_pdu.c ++ sms_cb.c sms_pdu.c uart.c + gsmd_LDADD = -ldl + gsmd_LDFLAGS = -Wl,--export-dynamic + +diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c +index 2ef6a10..27dfa41 100644 +--- a/src/gsmd/atcmd.c ++++ b/src/gsmd/atcmd.c +@@ -159,7 +159,8 @@ static int llparse_byte(struct llparser *llp, char byte) + return ret; + } + +-static int llparse_string(struct llparser *llp, char *buf, unsigned int len) ++static int llparse_string(struct llparser *llp, const char *buf, ++ unsigned int len) + { + while (len--) { + int rc = llparse_byte(llp, *(buf++)); +@@ -187,6 +188,55 @@ static int llparse_init(struct llparser *llp) + return 0; + } + ++/* See if we can now send more commands to the port */ ++static void atcmd_wake_queue(struct gsmd *g) ++{ ++ int len, rc; ++ char *cr; ++ ++ /* write pending commands to UART */ ++ while (g->interpreter_ready && g->clear_to_send) { ++ struct gsmd_atcmd *pos, *pos2; ++ llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) { ++ cr = strchr(pos->cur, '\n'); ++ if (cr) ++ len = cr - pos->cur; ++ else ++ len = pos->buflen; ++ rc = g->llp.port->write(g->llp.port, pos->cur, len); ++ if (rc == 0) { ++ gsmd_log(GSMD_ERROR, ++ "write returns 0, aborting\n"); ++ break; ++ } ++ if (cr && rc == len) ++ rc ++; /* Skip the \n */ ++ pos->buflen -= rc; ++ pos->cur += rc; ++ g->llp.port->write(g->llp.port, "\r", 1); ++ ++ if (!pos->buflen) { ++ /* success: remove from global list of ++ * to-be-sent atcmds */ ++ llist_del(&pos->list); ++ /* append to global list of executing atcmds */ ++ llist_add_tail(&pos->list, &g->busy_atcmds); ++ ++ /* we only send one cmd at the moment */ ++ g->clear_to_send = 0; ++ break; ++ } else { ++ /* The write was short or the atcmd has more ++ * lines to send after a "> ". */ ++ if (rc < len) ++ break; ++ g->clear_to_send = 0; ++ break; ++ } ++ } ++ } ++} ++ + /* mid-level parser */ + + static int parse_final_result(const char *res) +@@ -216,6 +266,7 @@ static int ml_parse(const char *buf, int len, void *ctx) + g->interpreter_ready = 1; + gsmd_initsettings(g); + gmsd_alive_start(g); ++ atcmd_wake_queue(g); + return 0; + } + +@@ -316,6 +367,7 @@ static int ml_parse(const char *buf, int len, void *ctx) + } else { + DEBUGP("Calling cmd->cb()\n"); + cmd->resp = g->mlbuf; ++ g->mlbuf[g->mlbuf_len] = 0; + rc = cmd->cb(cmd, cmd->ctx, cmd->resp); + DEBUGP("Clearing mlbuf\n"); + } +@@ -370,12 +422,15 @@ static int ml_parse(const char *buf, int len, void *ctx) + if (g->mlbuf_len) + g->mlbuf[g->mlbuf_len ++] = '\n'; + DEBUGP("Appending buf to mlbuf\n"); +- if (len > MLPARSE_BUF_SIZE - g->mlbuf_len) ++ if (len > MLPARSE_BUF_SIZE - g->mlbuf_len) { + len = MLPARSE_BUF_SIZE - g->mlbuf_len; ++ gsmd_log(GSMD_NOTICE, "g->mlbuf overrun\n"); ++ } + memcpy(g->mlbuf + g->mlbuf_len, buf, len); + g->mlbuf_len += len; + + if (g->mlunsolicited) { ++ g->mlbuf[g->mlbuf_len] = 0; + rc = unsolicited_parse(g, g->mlbuf, g->mlbuf_len, + strchr(g->mlbuf, ':') + 1); + if (rc == -EAGAIN) { +@@ -422,8 +477,11 @@ final_cb: + + /* if we're finished with current commands, but still have pending + * commands: we want to WRITE again */ +- if (llist_empty(&g->busy_atcmds) && !llist_empty(&g->pending_atcmds)) +- g->gfd_uart.when |= GSMD_FD_WRITE; ++ if (llist_empty(&g->busy_atcmds)) { ++ g->clear_to_send = 1; ++ if (!llist_empty(&g->pending_atcmds)) ++ atcmd_wake_queue(g); ++ } + + return rc; + } +@@ -433,85 +491,23 @@ static int atcmd_prompt(void *data) + { + struct gsmd *g = data; + +- g->gfd_uart.when |= GSMD_FD_WRITE; ++ g->clear_to_send = 1; ++ atcmd_wake_queue(g); + } + + /* callback to be called if [virtual] UART has some data for us */ +-static int atcmd_select_cb(int fd, unsigned int what, void *data) ++static int atcmd_newdata_cb(void *opaque, const char data[], int len) + { +- int len, rc; +- static char rxbuf[1024]; +- struct gsmd *g = data; +- char *cr; +- +- if (what & GSMD_FD_READ) { +- memset(rxbuf, 0, sizeof(rxbuf)); +- while ((len = read(fd, rxbuf, sizeof(rxbuf)))) { +- if (len < 0) { +- if (errno == EAGAIN) +- return 0; +- gsmd_log(GSMD_NOTICE, "ERROR reading from fd %u: %d (%s)\n", fd, len, +- strerror(errno)); +- return len; +- } +- rc = llparse_string(&g->llp, rxbuf, len); +- if (rc < 0) { +- gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc); +- return rc; +- } +- } +- } +- +- /* write pending commands to UART */ +- if ((what & GSMD_FD_WRITE) && g->interpreter_ready) { +- struct gsmd_atcmd *pos, *pos2; +- llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) { +- cr = strchr(pos->cur, '\n'); +- if (cr) +- len = cr - pos->cur; +- else +- len = pos->buflen - 1; /* assuming zero-terminated strings */ +- rc = write(fd, pos->cur, len); +- if (rc == 0) { +- gsmd_log(GSMD_ERROR, "write returns 0, aborting\n"); +- break; +- } else if (rc < 0) { +- gsmd_log(GSMD_ERROR, "error during write to fd %d: %d\n", +- fd, rc); +- return rc; +- } +- if (!cr || rc == len) +- rc ++; /* Skip the \n or \0 */ +- pos->buflen -= rc; +- pos->cur += rc; +- write(fd, "\r", 1); +- +- if (!pos->buflen) { +- /* success: remove from global list of +- * to-be-sent atcmds */ +- llist_del(&pos->list); +- /* append to global list of executing atcmds */ +- llist_add_tail(&pos->list, &g->busy_atcmds); +- +- /* we only send one cmd at the moment */ +- break; +- } else { +- /* The write was short or the atcmd has more +- * lines to send after a "> ". */ +- if (rc < len) +- return 0; +- break; +- } +- } ++ struct gsmd *g = opaque; ++ int rc; + +- /* Either pending_atcmds is empty or a command has to wait */ +- g->gfd_uart.when &= ~GSMD_FD_WRITE; +- } ++ rc = llparse_string(&g->llp, data, len); ++ if (rc < 0) ++ gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc); + +- return 0; ++ return rc; + } + +- + struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, + atcmd_cb_t cb, void *ctx, u_int16_t id) + { +@@ -544,36 +540,18 @@ int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd) + { + DEBUGP("submitting command `%s'\n", cmd->buf); + +- if (llist_empty(&g->pending_atcmds)) +- g->gfd_uart.when |= GSMD_FD_WRITE; ++ llist_empty(&g->pending_atcmds); + llist_add_tail(&cmd->list, &g->pending_atcmds); ++ atcmd_wake_queue(g); + + return 0; + } + +-void atcmd_drain(int fd) +-{ +- int rc; +- struct termios t; +- rc = tcflush(fd, TCIOFLUSH); +- rc = tcgetattr(fd, &t); +- DEBUGP("c_iflag = 0x%08x, c_oflag = 0x%08x, c_cflag = 0x%08x, c_lflag = 0x%08x\n", +- t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); +- t.c_iflag = t.c_oflag = 0; +- cfmakeraw(&t); +- rc = tcsetattr(fd, TCSANOW, &t); +-} +- + /* init atcmd parser */ +-int atcmd_init(struct gsmd *g, int sockfd) ++int atcmd_init(struct gsmd *g, struct gsmd_port *port) + { + __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; +- g->gfd_uart.cb = &atcmd_select_cb; +- + INIT_LLIST_HEAD(&g->pending_atcmds); + INIT_LLIST_HEAD(&g->busy_atcmds); + +@@ -581,7 +559,9 @@ int atcmd_init(struct gsmd *g, int sockfd) + + g->mlbuf_len = 0; + g->mlunsolicited = 0; ++ g->clear_to_send = 1; + ++ g->llp.port = port; + g->llp.cur = g->llp.buf; + g->llp.len = sizeof(g->llp.buf); + g->llp.cb = &ml_parse; +@@ -589,5 +569,8 @@ int atcmd_init(struct gsmd *g, int sockfd) + g->llp.ctx = g; + g->llp.flags = LGSM_ATCMD_F_EXTENDED; + +- return gsmd_register_fd(&g->gfd_uart); ++ port->newdata_opaque = g; ++ port->newdata_cb = atcmd_newdata_cb; ++ ++ return 0; + } +diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c +index 51b4f2c..846bd17 100644 +--- a/src/gsmd/gsmd.c ++++ b/src/gsmd/gsmd.c +@@ -26,7 +26,6 @@ + #include <string.h> + #include <errno.h> + #include <fcntl.h> +-#include <termios.h> + #include <signal.h> + + #define _GNU_SOURCE +@@ -247,56 +246,6 @@ int gsmd_initsettings(struct gsmd *gsmd) + return atcmd_submit(gsmd, cmd); + } + +-struct bdrt { +- int bps; +- u_int32_t b; +-}; +- +-static struct bdrt bdrts[] = { +- { 0, B0 }, +- { 9600, B9600 }, +- { 19200, B19200 }, +- { 38400, B38400 }, +- { 57600, B57600 }, +- { 115200, B115200 }, +- { 230400, B230400 }, +- { 460800, B460800 }, +- { 921600, B921600 }, +-}; +- +-static int set_baudrate(int fd, int baudrate, int hwflow) +-{ +- int i; +- u_int32_t bd = 0; +- struct termios ti; +- +- for (i = 0; i < ARRAY_SIZE(bdrts); i++) { +- if (bdrts[i].bps == baudrate) +- bd = bdrts[i].b; +- } +- if (bd == 0) +- return -EINVAL; +- +- i = tcgetattr(fd, &ti); +- if (i < 0) +- return i; +- +- i = cfsetispeed(&ti, B0); +- if (i < 0) +- return i; +- +- i = cfsetospeed(&ti, bd); +- if (i < 0) +- return i; +- +- if (hwflow) +- ti.c_cflag |= CRTSCTS; +- else +- ti.c_cflag &= ~CRTSCTS; +- +- return tcsetattr(fd, 0, &ti); +-} +- + static int gsmd_initialize(struct gsmd *g) + { + INIT_LLIST_HEAD(&g->users); +@@ -478,14 +427,19 @@ int main(int argc, char **argv) + if (wait >= 0) + g.interpreter_ready = !wait; + +- if (atcmd_init(&g, fd) < 0) { ++ if (uart_init(&g.uart, fd) < 0) { + fprintf(stderr, "can't initialize UART device\n"); + exit(1); + } + +- write(fd, "\r", 1); +- sleep(1); +- atcmd_drain(fd); ++ if (atcmd_init(&g, &g.uart.port) < 0) { ++ fprintf(stderr, "can't initialize AT parser\n"); ++ exit(1); ++ } ++ write(fd, "\r", 1); ++ sleep(1); ++ ++ uart_drain(fd); + + if (usock_init(&g) < 0) { + fprintf(stderr, "can't open unix socket\n"); +diff --git a/src/gsmd/uart.c b/src/gsmd/uart.c +new file mode 100644 +index 0000000..22a4a5c +--- /dev/null ++++ b/src/gsmd/uart.c +@@ -0,0 +1,202 @@ ++/* Wrapper for the physical UART in a struct gsmd_port abstraction. ++ * ++ * Copyright (C) 2007 OpenMoko, Inc. ++ * Written by Andrzej Zaborowski <andrew@openedhand.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., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++#include <string.h> ++#include <fcntl.h> ++#include <termios.h> ++#include <unistd.h> ++#include <errno.h> ++ ++#include "gsmd.h" ++ ++#include <gsmd/gsmd.h> ++ ++void uart_drain(int fd) ++{ ++ int rc; ++ struct termios t; ++ rc = tcflush(fd, TCIOFLUSH); ++ rc = tcgetattr(fd, &t); ++ DEBUGP( ++ "c_iflag = 0x%08x, c_oflag = 0x%08x, " ++ "c_cflag = 0x%08x, c_lflag = 0x%08x\n", ++ t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); ++ t.c_iflag = t.c_oflag = 0; ++ cfmakeraw(&t); ++ rc = tcsetattr(fd, TCSANOW, &t); ++} ++ ++struct bdrt { ++ int bps; ++ u_int32_t b; ++}; ++ ++static struct bdrt bdrts[] = { ++ { 0, B0 }, ++ { 9600, B9600 }, ++ { 19200, B19200 }, ++ { 38400, B38400 }, ++ { 57600, B57600 }, ++ { 115200, B115200 }, ++ { 230400, B230400 }, ++ { 460800, B460800 }, ++ { 921600, B921600 }, ++}; ++ ++int set_baudrate(int fd, int baudrate, int hwflow) ++{ ++ int i; ++ u_int32_t bd = 0; ++ struct termios ti; ++ ++ for (i = 0; i < ARRAY_SIZE(bdrts); i++) { ++ if (bdrts[i].bps == baudrate) ++ bd = bdrts[i].b; ++ } ++ if (bd == 0) ++ return -EINVAL; ++ ++ i = tcgetattr(fd, &ti); ++ if (i < 0) ++ return i; ++ ++ i = cfsetispeed(&ti, B0); ++ if (i < 0) ++ return i; ++ ++ i = cfsetospeed(&ti, bd); ++ if (i < 0) ++ return i; ++ ++ if (hwflow) ++ ti.c_cflag |= CRTSCTS; ++ else ++ ti.c_cflag &= ~CRTSCTS; ++ ++ return tcsetattr(fd, 0, &ti); ++} ++ ++static int uart_select_cb(int fd, unsigned int what, void *data) ++{ ++ struct gsmd_uart *uart = (struct gsmd_uart *) data; ++ static char rxbuf[2048]; ++ int rc, len; ++ ++ if ((what & GSMD_FD_READ) && uart->port.newdata_cb) { ++ while ((len = read(fd, rxbuf, sizeof(rxbuf)))) { ++ if (len < 0) { ++ if (errno == EAGAIN || errno == EINTR) ++ return 0; ++ gsmd_log(GSMD_NOTICE, "ERROR reading from " ++ "fd %u: %d (%s)\n", fd, errno, ++ strerror(errno)); ++ return -errno; ++ } ++ ++ rc = uart->port.newdata_cb( ++ uart->port.newdata_opaque, ++ rxbuf, ++ len); ++ if (rc < 0) ++ return rc; ++ } ++ } ++ ++ /* Write pending data to UART. */ ++ if ((what & GSMD_FD_WRITE) && uart->tx_len) { ++ while (uart->tx_start + uart->tx_len >= sizeof(uart->txfifo)) { ++ len = sizeof(uart->txfifo) - uart->tx_start; ++ rc = write(fd, &uart->txfifo[uart->tx_start], len); ++ if (rc < 0 && errno != EINTR) { ++ if (errno == EAGAIN) ++ return 0; ++ gsmd_log(GSMD_NOTICE, "ERROR writing " ++ "fd %u: %d (%s)\n", fd, errno, ++ strerror(errno)); ++ return -errno; ++ } ++ ++ if (rc > 0) { ++ uart->tx_start += rc; ++ uart->tx_len -= rc; ++ } ++ } ++ uart->tx_start &= sizeof(uart->txfifo) - 1; ++ ++ while (uart->tx_len) { ++ rc = write(fd, &uart->txfifo[uart->tx_start], ++ uart->tx_len); ++ if (rc < 0 && errno != EINTR) { ++ if (errno == EAGAIN) ++ return 0; ++ gsmd_log(GSMD_NOTICE, "ERROR writing " ++ "fd %u: %d (%s)\n", fd, errno, ++ strerror(errno)); ++ return -errno; ++ } ++ ++ if (rc > 0) { ++ uart->tx_start += rc; ++ uart->tx_len -= rc; ++ } ++ } ++ ++ /* If we reached here, there's no more data for the moment. */ ++ uart->gfd.when &= ~GSMD_FD_WRITE; ++ } ++ ++ return 0; ++} ++ ++static int uart_write(struct gsmd_port *port, const char data[], int len) ++{ ++ struct gsmd_uart *uart = (struct gsmd_uart *) port; ++ int start = (uart->tx_start + uart->tx_len) & ++ (sizeof(uart->txfifo) - 1); ++ int space = sizeof(uart->txfifo) - start; ++ ++ if (uart->tx_len + len > sizeof(uart->txfifo)) ++ len = sizeof(uart->txfifo) - uart->tx_len; ++ ++ if (len) ++ uart->gfd.when |= GSMD_FD_WRITE; ++ ++ if (len > space) { ++ memcpy(uart->txfifo + start, data, space); ++ memcpy(uart->txfifo, data + space, len - space); ++ } else ++ memcpy(uart->txfifo + start, data, len); ++ ++ uart->tx_len += len; ++ return len; ++} ++ ++int uart_init(struct gsmd_uart *uart, int sockfd) ++{ ++ uart->gfd.fd = sockfd; ++ uart->gfd.when = GSMD_FD_READ; ++ uart->gfd.data = uart; ++ uart->gfd.cb = &uart_select_cb; ++ ++ uart->port.write = uart_write; ++ ++ return gsmd_register_fd(&uart->gfd); ++} +-- +1.5.2.1 + diff --git a/packages/gsm/files/0002-Flush-all-pending-commands-before-restarting-the-mod.patch b/packages/gsm/files/0002-Flush-all-pending-commands-before-restarting-the-mod.patch new file mode 100644 index 0000000000..3683596389 --- /dev/null +++ b/packages/gsm/files/0002-Flush-all-pending-commands-before-restarting-the-mod.patch @@ -0,0 +1,74 @@ +From 1078f7aced63c6216bffe649930b97c9ccf9a16e Mon Sep 17 00:00:00 2001 +From: Andrzej Zaborowski <balrog@zabor.org> +Date: Wed, 19 Sep 2007 14:04:50 +0200 +Subject: [PATCH] Flush all pending commands before restarting the modem initialisation. + +--- + include/gsmd/gsmd.h | 1 + + src/gsmd/atcmd.c | 21 +++++++++++++++++++++ + src/gsmd/timer.c | 8 ++++++++ + 3 files changed, 30 insertions(+), 0 deletions(-) + +diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h +index 4afdf66..6ac9d8e 100644 +--- a/include/gsmd/gsmd.h ++++ b/include/gsmd/gsmd.h +@@ -131,6 +131,7 @@ struct gsmd_timer { + + int gsmd_timer_init(void); + void gmsd_timer_check_n_run(void); ++void gsmd_timer_reset(void); + + struct gsmd_timer *gsmd_timer_alloc(void); + int gsmd_timer_register(struct gsmd_timer *timer); +diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c +index 27dfa41..2f6cee2 100644 +--- a/src/gsmd/atcmd.c ++++ b/src/gsmd/atcmd.c +@@ -264,6 +264,27 @@ static int ml_parse(const char *buf, int len, void *ctx) + if (strlen(buf) == 0 || + !strcmp(buf, "AT-Command Interpreter ready")) { + g->interpreter_ready = 1; ++ g->clear_to_send = 1; ++ ++ /* Flush current queue and reinitialise */ ++ while (!llist_empty(&g->busy_atcmds)) { ++ cmd = llist_entry(g->busy_atcmds.next, ++ struct gsmd_atcmd, list); ++ gsmd_log(GSMD_NOTICE, "discarding busy cmd %s\n", ++ cmd->buf); ++ llist_del(&cmd->list); ++ talloc_free(cmd); ++ } ++ while (!llist_empty(&g->pending_atcmds)) { ++ cmd = llist_entry(g->pending_atcmds.next, ++ struct gsmd_atcmd, list); ++ gsmd_log(GSMD_NOTICE, "discarding pending cmd %s\n", ++ cmd->buf); ++ llist_del(&cmd->list); ++ talloc_free(cmd); ++ } ++ ++ gsmd_timer_reset(); + gsmd_initsettings(g); + gmsd_alive_start(g); + atcmd_wake_queue(g); +diff --git a/src/gsmd/timer.c b/src/gsmd/timer.c +index 5200690..8877275 100644 +--- a/src/gsmd/timer.c ++++ b/src/gsmd/timer.c +@@ -215,3 +215,11 @@ void gsmd_timer_unregister(struct gsmd_timer *timer) + /* re-calculate next expiration */ + calc_next_expiration(); + } ++ ++void gsmd_timer_reset(void) ++{ ++ while (!llist_empty(&gsmd_timers)) ++ /* TODO: free associated resources (e.g timer->cancel_cb()) */ ++ llist_del(&llist_entry(gsmd_timers.next, ++ struct gsmd_timer, list)->list); ++} +-- +1.5.2.1 + diff --git a/packages/gsm/files/0003-Correctly-segment-incoming-usock-data-into-packets.patch b/packages/gsm/files/0003-Correctly-segment-incoming-usock-data-into-packets.patch new file mode 100644 index 0000000000..984acc9369 --- /dev/null +++ b/packages/gsm/files/0003-Correctly-segment-incoming-usock-data-into-packets.patch @@ -0,0 +1,77 @@ +From 8af1bb4a0d0df9baa80859c5f7f56cbd7634aded Mon Sep 17 00:00:00 2001 +From: Andrzej Zaborowski <balrog@zabor.org> +Date: Wed, 19 Sep 2007 14:06:19 +0200 +Subject: [PATCH] Correctly segment incoming usock data into packets, handler short reads. + +--- + include/gsmd/gsmd.h | 2 ++ + src/gsmd/usock.c | 20 ++++++++++++++++---- + 2 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h +index 6ac9d8e..acec02a 100644 +--- a/include/gsmd/gsmd.h ++++ b/include/gsmd/gsmd.h +@@ -95,6 +95,8 @@ struct gsmd_user { + struct gsmd *gsmd; + struct gsmd_fd gfd; /* the socket */ + u_int32_t subscriptions; /* bitmaks of subscribed event groups */ ++ char usock_fifo[1024]; ++ int usock_len; + + struct llist_head pb_readrg_list; /* our READRG phonebook list */ + struct llist_head pb_find_list; /* our FIND phonebook list */ +diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c +index 32e98d0..bac5f0c 100644 +--- a/src/gsmd/usock.c ++++ b/src/gsmd/usock.c +@@ -1529,14 +1529,15 @@ static int usock_rcv_pcmd(struct gsmd_user *gu, char *buf, int len) + static int gsmd_usock_user_cb(int fd, unsigned int what, void *data) + { + struct gsmd_user *gu = data; ++ struct gsmd_msg_hdr *gph; + + /* FIXME: check some kind of backlog and limit it */ + + if (what & GSMD_FD_READ) { +- char buf[1024]; + int rcvlen; + /* read data from socket, determine what he wants */ +- rcvlen = read(fd, buf, sizeof(buf)); ++ rcvlen = read(fd, gu->usock_fifo + gu->usock_len, ++ sizeof(gu->usock_fifo) - gu->usock_len); + if (rcvlen == 0) { + DEBUGP("EOF, this client has just vanished\n"); + /* EOF, this client has just vanished */ +@@ -1549,8 +1550,18 @@ static int gsmd_usock_user_cb(int fd, unsigned int what, void *data) + return 0; + } else if (rcvlen < 0) + return rcvlen; +- else +- return usock_rcv_pcmd(gu, buf, rcvlen); ++ ++ gu->usock_len += rcvlen; ++ gph = (struct gsmd_msg_hdr *) gu->usock_fifo; ++ while (gu->usock_len >= sizeof(*gph) && ++ gu->usock_len >= sizeof(*gph) + gph->len) { ++ usock_rcv_pcmd(gu, gu->usock_fifo, gu->usock_len); ++ gu->usock_len -= sizeof(*gph) + gph->len; ++ memmove(gu->usock_fifo, ++ gu->usock_fifo + sizeof(*gph) + ++ gph->len, ++ gu->usock_len); ++ } + } + + if (what & GSMD_FD_WRITE) { +@@ -1609,6 +1620,7 @@ static int gsmd_usock_cb(int fd, unsigned int what, void *data) + newuser->gfd.cb = &gsmd_usock_user_cb; + newuser->gsmd = g; + newuser->subscriptions = 0xffffffff; ++ newuser->usock_len = 0; + INIT_LLIST_HEAD(&newuser->finished_ucmds); + INIT_LLIST_HEAD(&newuser->pb_readrg_list); + INIT_LLIST_HEAD(&newuser->pb_find_list); +-- +1.5.2.1 + diff --git a/packages/gsm/files/0004-Handle-read-and-write-return-values.patch b/packages/gsm/files/0004-Handle-read-and-write-return-values.patch new file mode 100644 index 0000000000..f5e7a7902d --- /dev/null +++ b/packages/gsm/files/0004-Handle-read-and-write-return-values.patch @@ -0,0 +1,176 @@ +From 421b0fa14fefbd13a455c20380fecddda616b41a Mon Sep 17 00:00:00 2001 +From: Andrzej Zaborowski <balrog@zabor.org> +Date: Wed, 19 Sep 2007 18:30:36 +0200 +Subject: [PATCH] Handle read() and write() return values. + +--- + include/libgsmd/libgsmd.h | 3 +- + src/gsmd/usock.c | 38 ++++++++++++++++----------- + src/libgsmd/lgsm_internals.h | 2 + + src/libgsmd/libgsmd.c | 58 ++++++++++++++++++++++++++--------------- + 4 files changed, 63 insertions(+), 38 deletions(-) + +diff --git a/include/libgsmd/libgsmd.h b/include/libgsmd/libgsmd.h +index fc56890..db15aa9 100644 +--- a/include/libgsmd/libgsmd.h ++++ b/include/libgsmd/libgsmd.h +@@ -65,6 +65,7 @@ extern int lgsm_subscriptions(struct lgsm_handle *lh, u_int32_t subscriptions); + + extern struct gsmd_msg_hdr *lgsm_gmh_fill(int type, int subtype, int payload_len); + extern int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh); +-extern int lgsm_handle_packet(struct lgsm_handle *lh, char *buf, int len); ++extern int lgsm_handle_packet(struct lgsm_handle *lh, ++ const char *buf, int len); + + #endif +diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c +index bac5f0c..2283600 100644 +--- a/src/gsmd/usock.c ++++ b/src/gsmd/usock.c +@@ -1569,23 +1569,29 @@ static int gsmd_usock_user_cb(int fd, unsigned int what, void *data) + struct gsmd_ucmd *ucmd, *uctmp; + llist_for_each_entry_safe(ucmd, uctmp, &gu->finished_ucmds, + list) { +- int rc; +- +- rc = write(fd, &ucmd->hdr, sizeof(ucmd->hdr) + ucmd->hdr.len); +- if (rc < 0) { +- DEBUGP("write return %d\n", rc); +- return rc; +- } +- if (rc == 0) { +- DEBUGP("write returns zero!!\n"); +- break; ++ const void *pos = &ucmd->hdr; ++ size_t len = sizeof(ucmd->hdr) + ucmd->hdr.len; ++ ++ while (len) { ++ ssize_t rc; ++ ++ rc = write(fd, pos, len); ++ if (rc < 0 && errno != EINTR) { ++ DEBUGP("write returned %s\n", ++ strerror(errno)); ++ return rc; ++ } ++ if (rc == 0 && pos == &ucmd->hdr) { ++ DEBUGP("write returns zero!!\n"); ++ return 0; ++ } ++ if (rc > 0) { ++ len -= rc; ++ pos += rc; ++ } + } +- if (rc != sizeof(ucmd->hdr) + ucmd->hdr.len) { +- DEBUGP("short write\n"); +- break; +- } +- +- DEBUGP("successfully sent cmd %p to user %p, freeing\n", ucmd, gu); ++ DEBUGP("successfully sent cmd %p to user %p, " ++ "freeing\n", ucmd, gu); + llist_del(&ucmd->list); + talloc_free(ucmd); + } +diff --git a/src/libgsmd/lgsm_internals.h b/src/libgsmd/lgsm_internals.h +index c826723..f1b1a23 100644 +--- a/src/libgsmd/lgsm_internals.h ++++ b/src/libgsmd/lgsm_internals.h +@@ -8,6 +8,8 @@ struct lgsm_handle { + int fd; + lgsm_msg_handler *handler[__NUM_GSMD_MSGS]; + enum lgsm_netreg_state netreg_state; ++ char usock_fifo[1024]; ++ int usock_len; + }; + + int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh); +diff --git a/src/libgsmd/libgsmd.c b/src/libgsmd/libgsmd.c +index 9906ea8..cc804ed 100644 +--- a/src/libgsmd/libgsmd.c ++++ b/src/libgsmd/libgsmd.c +@@ -86,34 +86,37 @@ static int lgsm_open_backend(struct lgsm_handle *lh, const char *device) + } + + /* handle a packet that was received on the gsmd socket */ +-int lgsm_handle_packet(struct lgsm_handle *lh, char *buf, int len) ++int lgsm_handle_packet(struct lgsm_handle *lh, const char *buf, int len) + { + struct gsmd_msg_hdr *gmh; + lgsm_msg_handler *handler; + int rc = 0; + +- while (len) { +- if (len < sizeof(*gmh)) +- return -EINVAL; +- gmh = (struct gsmd_msg_hdr *) buf; +- +- if (len - sizeof(*gmh) < gmh->len) +- return -EINVAL; +- len -= sizeof(*gmh) + gmh->len; +- buf += sizeof(*gmh) + gmh->len; +- +- if (gmh->msg_type >= __NUM_GSMD_MSGS) +- return -EINVAL; +- +- handler = lh->handler[gmh->msg_type]; ++ if (lh->usock_len + len > sizeof(lh->usock_fifo)) ++ return -ENOMEM; + +- if (handler) ++ memcpy(lh->usock_fifo + lh->usock_len, buf, len); ++ lh->usock_len += len; ++ gmh = (struct gsmd_msg_hdr *) lh->usock_fifo; ++ while (lh->usock_len >= sizeof(*gmh) && ++ lh->usock_len >= sizeof(*gmh) + gmh->len) { ++ if (gmh->msg_type < __NUM_GSMD_MSGS && ++ (handler = lh->handler[gmh->msg_type])) + rc |= handler(lh, gmh); +- else +- fprintf(stderr, "unable to handle packet type=%u\n", +- gmh->msg_type); ++ else { ++ fprintf(stderr, "unable to handle packet " ++ "type=%u id=%u\n", ++ gmh->msg_type, gmh->id); ++ rc |= EINVAL; ++ } ++ ++ lh->usock_len -= gmh->len + sizeof(*gmh); ++ memmove(lh->usock_fifo, ++ lh->usock_fifo + gmh->len + sizeof(*gmh), ++ lh->usock_len); + } +- return rc; ++ ++ return -rc; + } + + int lgsm_register_handler(struct lgsm_handle *lh, int type, lgsm_msg_handler *handler) +@@ -193,8 +196,21 @@ static u_int16_t next_msg_id; + + int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh) + { ++ ssize_t rc; ++ size_t len = sizeof(*gmh) + gmh->len; ++ const void *pos = gmh; ++ + gmh->id = next_msg_id++; +- return send(lh->fd, (char *) gmh, sizeof(*gmh) + gmh->len, 0); ++ while (len) { ++ rc = send(lh->fd, pos, len, 0); ++ if (rc < 0 && errno != EINTR) ++ return -errno; ++ if (rc > 0) { ++ len -= rc; ++ pos += rc; ++ } ++ } ++ return 0; + } + + struct gsmd_msg_hdr *lgsm_gmh_fill(int type, int subtype, int payload_len) +-- +1.5.2.1 + diff --git a/packages/gsm/files/0005-Add-ask-ds-option-forSMS.patch b/packages/gsm/files/0005-Add-ask-ds-option-forSMS.patch new file mode 100644 index 0000000000..e9f49bd7d2 --- /dev/null +++ b/packages/gsm/files/0005-Add-ask-ds-option-forSMS.patch @@ -0,0 +1,130 @@ +diff --git a/include/gsmd/usock.h b/include/gsmd/usock.h +index 236ad78..66cdf48 100644 +--- a/include/gsmd/usock.h ++++ b/include/gsmd/usock.h +@@ -332,6 +332,7 @@ struct gsmd_sms { + struct gsmd_sms_submit { + struct gsmd_addr addr; + struct gsmd_sms payload; ++ int ask_ds; + }; + + /* Refer to GSM 07.05 subclause 4.4 */ +diff --git a/include/libgsmd/sms.h b/include/libgsmd/sms.h +index 3ada62d..9808442 100644 +--- a/include/libgsmd/sms.h ++++ b/include/libgsmd/sms.h +@@ -46,6 +46,7 @@ struct lgsm_sms { + enum gsmd_sms_alphabet alpha; + u_int8_t data[LGSM_SMS_DATA_MAXLEN+1]; + int length; ++ int ask_ds; + }; + + /* GSM 03.40 subclause 9.2.2.2 and GSM 07.05 subclause 4.4 and subclause 3.1 */ +diff --git a/src/gsmd/sms_pdu.c b/src/gsmd/sms_pdu.c +index d1235dd..d461999 100644 +--- a/src/gsmd/sms_pdu.c ++++ b/src/gsmd/sms_pdu.c +@@ -247,7 +247,8 @@ int sms_pdu_make_smssubmit(char *dest, const struct gsmd_sms_submit *src) + GSMD_SMS_TP_MTI_SUBMIT | + (0 << 2) | /* Reject Duplicates: 0 */ + GSMD_SMS_TP_VPF_NOT_PRESENT | +- GSMD_SMS_TP_SRR_STATUS_REQUEST | ++ (src->ask_ds ? GSMD_SMS_TP_SRR_STATUS_REQUEST : ++ GSMD_SMS_TP_SRR_NOT_REQUEST) | + (src->payload.has_header ? GSMD_SMS_TP_UDHI_WITH_HEADER : + GSMD_SMS_TP_UDHI_NO_HEADER) | + GSMD_SMS_TP_RP_NOT_SET; +diff --git a/src/libgsmd/libgsmd_sms.c b/src/libgsmd/libgsmd_sms.c +index 22d7dbf..bbc8689 100644 +--- a/src/libgsmd/libgsmd_sms.c ++++ b/src/libgsmd/libgsmd_sms.c +@@ -126,6 +126,7 @@ int lgsm_sms_send(struct lgsm_handle *lh, + if (lgsm_number2addr(&gss->addr, sms->addr, 1)) + return -EINVAL; + ++ gss->ask_ds = sms->ask_ds; + gss->payload.has_header = 0; + gss->payload.length = sms->length; + gss->payload.coding_scheme = sms->alpha; +@@ -161,6 +162,7 @@ int lgsm_sms_write(struct lgsm_handle *lh, + if (lgsm_number2addr(&gsw->sms.addr, sms_write->sms.addr, 1)) + return -EINVAL; + ++ gsw->sms.ask_ds = sms_write->sms.ask_ds; + gsw->sms.payload.has_header = 0; + gsw->sms.payload.length = sms_write->sms.length; + gsw->sms.payload.coding_scheme = sms_write->sms.alpha; +diff --git a/src/util/shell.c b/src/util/shell.c +index f902126..f26e17e 100644 +--- a/src/util/shell.c ++++ b/src/util/shell.c +@@ -355,7 +355,7 @@ static int shell_help(void) + "\tsd\tSMS Delete (sd=index,delflg)\n" + "\tsl\tSMS List (sl=stat)\n" + "\tsr\tSMS Read (sr=index)\n" +- "\tss\tSMS Send (ss=number,text|[\"text\"])\n" ++ "\tss\tSMS Send (ss=ask_ds,number,text|[\"text\"])\n" + "\tsw\tSMS Write (sw=stat,number,text)\n" + "\tsm\tSMS Storage stats\n" + "\tsM\tSMS Set preferred storage (sM=mem1,mem2,mem3)\n" +@@ -563,33 +563,29 @@ int shell_main(struct lgsm_handle *lgsmh) + struct lgsm_sms sms; + + ptr = strchr(buf, '='); ++ sms.ask_ds = atoi(ptr+1); + fcomma = strchr(buf, ','); +- if (!ptr || !fcomma) { +- printf("Wrong command format\n"); +- } else { +- strncpy(sms.addr, ptr+1, fcomma-ptr-1); +- sms.addr[fcomma-ptr-1] = '\0'; +- +- /* todo define \" to allow " in text */ +- if (fcomma[1] == '"' && +- !strchr(fcomma+2, '"')) { ++ lcomma = strchr(fcomma+1, ','); ++ strncpy(sms.addr, fcomma+1, lcomma-fcomma-1); ++ sms.addr[lcomma-fcomma-1] = '\0'; ++ /* todo define \" to allow " in text */ ++ if (lcomma[1]=='"' && ++ !strchr(lcomma+2, '"')) { + /* read until closing '"' */ + rc = fscanf(stdin, "%[^\"]\"", +- fcomma+strlen(fcomma)); ++ lcomma+strlen(lcomma)); + if (rc == EOF) { + printf("EOF\n"); + return -1; + } + /* remove brackets */ +- fcomma++; +- fcomma[strlen(fcomma)] = '\0'; +- } +- +- printf("Send SMS\n"); +- packing_7bit_character(fcomma+1, &sms); ++ lcomma++; ++ lcomma[strlen(lcomma)] = '\0'; ++ } ++ printf("Send SMS\n"); ++ packing_7bit_character(lcomma+1, &sms); + +- lgsm_sms_send(lgsmh, &sms); +- } ++ lgsm_sms_send(lgsmh, &sms); + } else if ( !strncmp(buf, "sw", 2)) { + printf("Write SMS\n"); + struct lgsm_sms_write sms_write; +@@ -603,6 +599,7 @@ int shell_main(struct lgsm_handle *lgsmh) + sms_write.sms.addr[lcomma-fcomma-1] = '\0'; + packing_7bit_character( + lcomma+1, &sms_write.sms); ++ sms_write.sms.ask_ds = 0; + + lgsm_sms_write(lgsmh, &sms_write); + } else if (!strncmp(buf, "sm", 2)) { +-- +1.5.2.1 + diff --git a/packages/gsm/files/024_sms-text-in-bracket.patch b/packages/gsm/files/024_sms-text-in-bracket.patch new file mode 100644 index 0000000000..32a1ca33ff --- /dev/null +++ b/packages/gsm/files/024_sms-text-in-bracket.patch @@ -0,0 +1,70 @@ +http://bugzilla.openmoko.org/cgi-bin/bugzilla/show_bug.cgi?id=834 + +From: Kristian Mueller <kristian@mput.de> +Subject: [PATCH] libgsmd-tool does not allow sms with more than one word + +libgsmd-tool only allows for command strings without spaces. +SMS messages with more than one word will be parsed as multible commands. +The patch introduces SMS message text in bracket and fixes a NULL pointer +reference on mailformed "ss" commands. + +Signed-off-by: Jim Huang <jserv@openmoko.org> +--- + src/util/shell.c | 32 ++++++++++++++++++++++++++------ + 1 file changed, 26 insertions(+), 6 deletions(-) + +Index: gsm/src/util/shell.c +=================================================================== +--- gsm.orig/src/util/shell.c 2007-08-31 16:15:30.000000000 +0800 ++++ gsm/src/util/shell.c 2007-09-17 23:35:31.000000000 +0800 +@@ -389,7 +389,7 @@ + "\tsd\tSMS Delete (sd=index,delflg)\n" + "\tsl\tSMS List (sl=stat)\n" + "\tsr\tSMS Read (sr=index)\n" +- "\tss\tSMS Send (ss=number,text)\n" ++ "\tss\tSMS Send (ss=number,text|[\"text\"])\n" + "\tsw\tSMS Write (sw=stat,number,text)\n" + "\tsm\tSMS Storage stats\n" + "\tsM\tSMS Set preferred storage (sM=mem1,mem2,mem3)\n" +@@ -612,16 +612,36 @@ + + lgsm_sms_read(lgsmh, atoi(ptr+1)); + } else if ( !strncmp(buf, "ss", 2)) { +- printf("Send SMS\n"); + struct lgsm_sms sms; + + ptr = strchr(buf, '='); + fcomma = strchr(buf, ','); +- strncpy(sms.addr, ptr+1, fcomma-ptr-1); +- sms.addr[fcomma-ptr-1] = '\0'; +- packing_7bit_character(fcomma+1, &sms); ++ if (!ptr || !fcomma) { ++ printf("Wrong command format\n"); ++ } else { ++ strncpy(sms.addr, ptr+1, fcomma-ptr-1); ++ sms.addr[fcomma-ptr-1] = '\0'; ++ ++ /* todo define \" to allow " in text */ ++ if (fcomma[1] == '"' && ++ !strchr(fcomma+2, '"')) { ++ /* read until closing '"' */ ++ rc = fscanf(stdin, "%[^\"]\"", ++ fcomma+strlen(fcomma)); ++ if (rc == EOF) { ++ printf("EOF\n"); ++ return -1; ++ } ++ /* remove brackets */ ++ fcomma++; ++ fcomma[strlen(fcomma)] = '\0'; ++ } ++ ++ printf("Send SMS\n"); ++ packing_7bit_character(fcomma+1, &sms); + +- lgsm_sms_send(lgsmh, &sms); ++ lgsm_sms_send(lgsmh, &sms); ++ } + } else if ( !strncmp(buf, "sw", 2)) { + printf("Write SMS\n"); + struct lgsm_sms_write sms_write; diff --git a/packages/gsm/files/025_sms-status-report.patch b/packages/gsm/files/025_sms-status-report.patch new file mode 100644 index 0000000000..560e72e380 --- /dev/null +++ b/packages/gsm/files/025_sms-status-report.patch @@ -0,0 +1,133 @@ +From: Erin Yueh <erin_yueh@openmoko.com> +Subject: [PATCH] SMS status report + +I made a patch for SMS status report. It can change SMS-Submit messages +and ask for a status report. When the destination address receives our +message, the service center will send a SMS-STATUS-REPORT to us. We can +tell what messages we sent by TP-MR (message reference number) value and +can know the sending result by TP-ST (Status) value from status report +messages. + +PS. if you don't want to ask a status report, you can change this value +back. Replace "GSMD_SMS_TP_SRR_STATUS_REQUEST" with +"GSMD_SMS_TP_SRR_NOT_REQUEST". +header[pos ++] = + GSMD_SMS_TP_MTI_SUBMIT | + (0 << 2) | /* Reject Duplicates: 0 */ + GSMD_SMS_TP_VPF_NOT_PRESENT | +- GSMD_SMS_TP_SRR_NOT_REQUEST | ++ GSMD_SMS_TP_SRR_STATUS_REQUEST | + (src->payload.has_header ? GSMD_SMS_TP_UDHI_WITH_HEADER : + GSMD_SMS_TP_UDHI_NO_HEADER) | + GSMD_SMS_TP_RP_NOT_SET; + +Signed-off-by: Jim Huang <jserv@openmoko.org> +--- + src/gsmd/sms_pdu.c | 54 +++++++++++++++++++++++++++++++++++++++++++----------- + src/util/event.c | 6 +++++- + 2 files changed, 48 insertions(+), 12 deletions(-) + +Index: gsm/src/gsmd/sms_pdu.c +=================================================================== +--- gsm.orig/src/gsmd/sms_pdu.c 2007-09-06 11:14:34.000000000 +0800 ++++ gsm/src/gsmd/sms_pdu.c 2007-09-17 23:39:20.000000000 +0800 +@@ -139,6 +139,17 @@ + /* Skip TP-PID */ + len -= 9; + src += 9; ++ ++ /* TP-UDL */ ++ dst->payload.length = src[0]; ++ i = sms_data_bytelen(dst->payload.coding_scheme, src[0]); ++ ++ /* TP-UD */ ++ if (len < 1 + i || i > GSMD_SMS_DATA_MAXLEN) ++ return 1; ++ memcpy(dst->payload.data, src + 1, i); ++ dst->payload.data[i] = 0; ++ + break; + case GSMD_SMS_TP_MTI_SUBMIT: + if (len < 4) +@@ -179,23 +190,44 @@ + src += vpf ? 3 : 2; + + memset(dst->time_stamp, 0, 7); ++ ++ /* TP-UDL */ ++ dst->payload.length = src[0]; ++ i = sms_data_bytelen(dst->payload.coding_scheme, src[0]); ++ ++ /* TP-UD */ ++ if (len < 1 + i || i > GSMD_SMS_DATA_MAXLEN) ++ return 1; ++ memcpy(dst->payload.data, src + 1, i); ++ dst->payload.data[i] = 0; + break; + case GSMD_SMS_TP_MTI_STATUS_REPORT: +- /* TODO */ ++ if (len < 3) ++ return 1; ++ ++ /* TP-MR set it gsmd_sms_list.index*/ ++ dst->index = (int) src[1]; ++ /* TP-STATUS set it to coding_scheme */ ++ dst->payload.coding_scheme = (int) src[len-1]; ++ /* TP-RA */ ++ i = sms_number_bytelen(src[3], src[2]); ++ if (len < 13 + i) ++ return 1; ++ if (sms_address2ascii(&dst->addr, src + 2)) ++ return 1; ++ len -= 4 + i; ++ src += 4 + i; ++ /* TP-SCTS */ ++ memcpy(dst->time_stamp, src, 7); ++ /* TP-UD */ ++ dst->payload.length = 0; ++ dst->payload.data[0] = 0; ++ break; + default: + /* Unknown PDU type */ + return 1; + } + +- /* TP-UDL */ +- dst->payload.length = src[0]; +- i = sms_data_bytelen(dst->payload.coding_scheme, src[0]); +- +- /* TP-UD */ +- if (len < 1 + i || i > GSMD_SMS_DATA_MAXLEN) +- return 1; +- memcpy(dst->payload.data, src + 1, i); +- dst->payload.data[i] = 0; + + return 0; + } +@@ -215,7 +247,7 @@ + GSMD_SMS_TP_MTI_SUBMIT | + (0 << 2) | /* Reject Duplicates: 0 */ + GSMD_SMS_TP_VPF_NOT_PRESENT | +- GSMD_SMS_TP_SRR_NOT_REQUEST | ++ GSMD_SMS_TP_SRR_STATUS_REQUEST | + (src->payload.has_header ? GSMD_SMS_TP_UDHI_WITH_HEADER : + GSMD_SMS_TP_UDHI_NO_HEADER) | + GSMD_SMS_TP_RP_NOT_SET; +Index: gsm/src/util/event.c +=================================================================== +--- gsm.orig/src/util/event.c 2007-09-06 11:14:34.000000000 +0800 ++++ gsm/src/util/event.c 2007-09-17 23:39:47.000000000 +0800 +@@ -128,8 +128,12 @@ + static int inds_handler(struct lgsm_handle *lh, int evt, + struct gsmd_evt_auxdata *aux) + { +- if (aux->u.ds.inlined) ++ if (aux->u.ds.inlined) { ++ struct gsmd_sms_list *sms; ++ sms = (struct gsmd_sms_list *) aux->data; + printf("EVENT: Incoming Status Report\n"); ++ printf("message ref = %d, status = %d\n", sms->index,sms->payload.coding_scheme); ++ } + else + printf("EVENT: Incoming Status Report stored at location %i\n", + aux->u.ds.index); diff --git a/packages/gsm/files/027_phonebook-find-and-read-range-support.patch b/packages/gsm/files/027_phonebook-find-and-read-range-support.patch new file mode 100644 index 0000000000..ea0f12daac --- /dev/null +++ b/packages/gsm/files/027_phonebook-find-and-read-range-support.patch @@ -0,0 +1,423 @@ +From: Sean Chiang <sean_chiang@openmoko.com> +Subject: [PATCH] Improvement for find and read phonebooks in gsmd + +This patch is an improvement for find and read phonebooks. +After clients make a request to find / read phonebooks, then clients +should make a request to retrieve all the records. + +Signed-off-by: Jim Huang <jserv@openmoko.org> +--- + include/gsmd/gsmd.h | 3 + include/gsmd/usock.h | 20 +++- + include/libgsmd/phonebook.h | 6 + + src/gsmd/usock.c | 184 +++++++++++++++++++++++++++++++++++----- + src/libgsmd/libgsmd_phonebook.c | 48 ++++++++++ + 5 files changed, 238 insertions(+), 23 deletions(-) + +Index: gsm/include/libgsmd/phonebook.h +=================================================================== +--- gsm.orig/include/libgsmd/phonebook.h 2007-08-31 16:15:29.000000000 +0800 ++++ gsm/include/libgsmd/phonebook.h 2007-09-17 23:48:41.000000000 +0800 +@@ -106,4 +106,10 @@ + /* Get the location range/nlength/tlength supported */ + extern int lgsm_pb_get_support(struct lgsm_handle *lh); + ++/* Retrieve the records of READRG request */ ++extern int lgsm_pb_retrieve_readrg(struct lgsm_handle *lh, int num); ++ ++/* Retrieve the records of FIND request */ ++extern int lgsm_pb_retrieve_find(struct lgsm_handle *lh, int num); ++ + #endif +Index: gsm/include/gsmd/gsmd.h +=================================================================== +--- gsm.orig/include/gsmd/gsmd.h 2007-08-31 16:15:29.000000000 +0800 ++++ gsm/include/gsmd/gsmd.h 2007-09-17 23:48:41.000000000 +0800 +@@ -92,6 +92,9 @@ + struct gsmd *gsmd; + struct gsmd_fd gfd; /* the socket */ + u_int32_t subscriptions; /* bitmaks of subscribed event groups */ ++ ++ struct llist_head pb_readrg_list; /* our READRG phonebook list */ ++ struct llist_head pb_find_list; /* our FIND phonebook list */ + }; + + #define GSMD_DEBUG 1 /* debugging information */ +Index: gsm/include/gsmd/usock.h +=================================================================== +--- gsm.orig/include/gsmd/usock.h 2007-08-31 16:15:29.000000000 +0800 ++++ gsm/include/gsmd/usock.h 2007-09-17 23:48:56.000000000 +0800 +@@ -194,6 +194,8 @@ + GSMD_PHONEBOOK_GET_SUPPORT = 6, + GSMD_PHONEBOOK_LIST_STORAGE = 7, + GSMD_PHONEBOOK_SET_STORAGE = 8, ++ GSMD_PHONEBOOK_RETRIEVE_READRG = 9, ++ GSMD_PHONEBOOK_RETRIEVE_FIND = 10, + }; + + /* Type-of-Address, Numbering-Plan-Identification field, GSM 03.40, 9.1.2.5 */ +@@ -431,7 +433,6 @@ + char text[GSMD_PB_TEXT_MAXLEN+1]; + } __attribute__ ((packed)); + +- + /* Refer to GSM 07.07 subclause 8.13 */ + /* FIXME: the tlength depends on SIM, use +CPBR=? to get */ + struct gsmd_phonebook_find { +@@ -471,8 +472,18 @@ + char opname_longalpha[16]; + }; + ++/* Refer to GSM 07.07 subclause 8.11 */ ++struct gsmd_phonebook_mem { ++ u_int8_t type[3]; ++ u_int8_t pad; ++ u_int16_t used; ++ u_int16_t total; ++} __attribute__ ((packed)); ++ + struct gsmd_phonebook_storage { +- char storage[3]; ++ /* FIXME the amount of phonebook storage should be dynamic */ ++ u_int8_t num; ++ struct gsmd_phonebook_mem mem[20]; + } __attribute__ ((packed)); + + /* Subscriber number information from 3GPP TS 07.07, Clause 7.1 */ +@@ -517,6 +528,11 @@ + char buf[]; + } __attribute__ ((packed)); + ++struct gsmd_phonebooks { ++ struct llist_head list; ++ struct gsmd_phonebook pb; ++} __attribute__ ((packed)); ++ + extern struct gsmd_ucmd *ucmd_alloc(int extra_size); + extern int usock_init(struct gsmd *g); + extern void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu); +Index: gsm/src/libgsmd/libgsmd_phonebook.c +=================================================================== +--- gsm.orig/src/libgsmd/libgsmd_phonebook.c 2007-08-31 16:15:29.000000000 +0800 ++++ gsm/src/libgsmd/libgsmd_phonebook.c 2007-09-17 23:48:41.000000000 +0800 +@@ -33,7 +33,7 @@ + gmh->data[2] = '\0'; + + rc = lgsm_send(lh, gmh); +- if (rc < gmh->len + 3) { ++ if (rc < gmh->len + sizeof(*gmh)) { + lgsm_gmh_free(gmh); + return -EIO; + } +@@ -177,3 +177,49 @@ + { + return lgsm_send_simple(lh, GSMD_MSG_PHONEBOOK, GSMD_PHONEBOOK_GET_SUPPORT); + } ++ ++int lgsm_pb_retrieve_readrg(struct lgsm_handle *lh, int num) ++{ ++ struct gsmd_msg_hdr *gmh; ++ int rc; ++ ++ gmh = lgsm_gmh_fill(GSMD_MSG_PHONEBOOK, ++ GSMD_PHONEBOOK_RETRIEVE_READRG, sizeof(int)); ++ if (!gmh) ++ return -ENOMEM; ++ ++ *(int *)(gmh->data) = num; ++ ++ rc = lgsm_send(lh, gmh); ++ if (rc < gmh->len + sizeof(*gmh)) { ++ lgsm_gmh_free(gmh); ++ return -EIO; ++ } ++ ++ lgsm_gmh_free(gmh); ++ ++ return 0; ++} ++ ++int lgsm_pb_retrieve_find(struct lgsm_handle *lh, int num) ++{ ++ struct gsmd_msg_hdr *gmh; ++ int rc; ++ ++ gmh = lgsm_gmh_fill(GSMD_MSG_PHONEBOOK, ++ GSMD_PHONEBOOK_RETRIEVE_FIND, sizeof(int)); ++ if (!gmh) ++ return -ENOMEM; ++ ++ *(int *)(gmh->data) = num; ++ ++ rc = lgsm_send(lh, gmh); ++ if (rc < gmh->len + sizeof(*gmh)) { ++ lgsm_gmh_free(gmh); ++ return -EIO; ++ } ++ ++ lgsm_gmh_free(gmh); ++ ++ return 0; ++} +Index: gsm/src/gsmd/usock.c +=================================================================== +--- gsm.orig/src/gsmd/usock.c 2007-08-31 16:15:30.000000000 +0800 ++++ gsm/src/gsmd/usock.c 2007-09-17 23:53:34.000000000 +0800 +@@ -1035,21 +1035,56 @@ + + static int phonebook_find_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) + { +- struct gsmd_user *gu = ctx; +- struct gsmd_ucmd *ucmd; +- ++ struct gsmd_user *gu = ctx; ++ struct gsmd_ucmd *ucmd; ++ struct gsmd_phonebooks *gps; ++ char *fcomma, *lcomma, *ptr1, *ptr2 = NULL; ++ int *num; ++ + DEBUGP("resp: %s\n", resp); + +- /* FIXME: using link list, also we need to handle the case of +- * no query result */ +- ucmd = gsmd_ucmd_fill(strlen(resp) + 1, GSMD_MSG_PHONEBOOK, ++ /* ++ * [+CPBF: <index1>,<number>,<type>,<text>[[...] ++ * <CR><LF>+CPBF: <index2>,<unmber>,<type>,<text>]] ++ */ ++ ucmd = gsmd_ucmd_fill(sizeof(int), GSMD_MSG_PHONEBOOK, + GSMD_PHONEBOOK_FIND, 0); + if (!ucmd) + return -ENOMEM; + +- strcpy(ucmd->buf, resp); ++ num = (int*) ucmd->buf; ++ ++ *num = 0; ++ ++ ptr1 = strtok(resp, "\n"); ++ ++ while (ptr1) { ++ gps = (struct gsmd_phonebooks *) malloc(sizeof(struct gsmd_phonebooks)); ++ ptr2 = strchr(ptr1, ' '); ++ gps->pb.index = atoi(ptr2+1); ++ ++ fcomma = strchr(ptr1, '"'); ++ lcomma = strchr(fcomma+1, '"'); ++ strncpy(gps->pb.numb, fcomma + 1, (lcomma-fcomma-1)); ++ gps->pb.numb[(lcomma - fcomma) - 1] = '\0'; ++ ++ gps->pb.type = atoi(lcomma + 2); ++ ++ ptr2 = strrchr(ptr1, ','); ++ fcomma = ptr2 + 1; ++ lcomma = strchr(fcomma + 1, '"'); ++ strncpy(gps->pb.text, fcomma + 1, (lcomma - fcomma - 1)); ++ gps->pb.text[(lcomma - fcomma) - 1] = '\0'; ++ ++ llist_add_tail(&gps->list, &gu->pb_find_list); ++ ++ (*num)++; ++ ++ ptr1 = strtok(NULL, "\n"); ++ } + + usock_cmd_enqueue(ucmd, gu); ++ + return 0; + } + +@@ -1102,22 +1137,51 @@ + { + struct gsmd_user *gu = ctx; + struct gsmd_ucmd *ucmd; ++ struct gsmd_phonebooks *gps; ++ char *fcomma, *lcomma, *ptr1, *ptr2 = NULL; ++ int *num; + + DEBUGP("resp: %s\n", resp); + + /* +- * +CPBR: 4,"1234",129,"6C5F745E7965" +- * +CPBR: 5,"5678",129,"800062115BB6" +- * +CPBR: 6,"7890",129,"810280AA591A" +- * +CPBR: 8,"36874",129,"005300650061006E" +- * ++ * [+CPBR: <index1>,<number>,<type>,<text>[[...] ++ * <CR><LF>+CPBR: <index2>,<unmber>,<type>,<text>]] + */ +- ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK, ++ ucmd = gsmd_ucmd_fill(sizeof(int), GSMD_MSG_PHONEBOOK, + GSMD_PHONEBOOK_READRG, 0); + if (!ucmd) + return -ENOMEM; + +- strcpy(ucmd->buf, resp); ++ num = (int*) ucmd->buf; ++ ++ *num = 0; ++ ++ ptr1 = strtok(resp, "\n"); ++ ++ while(ptr1) { ++ gps = (struct gsmd_phonebooks *) malloc(sizeof(struct gsmd_phonebooks)); ++ ptr2 = strchr(ptr1, ' '); ++ gps->pb.index = atoi(ptr2+1); ++ ++ fcomma = strchr(ptr1, '"'); ++ lcomma = strchr(fcomma+1, '"'); ++ strncpy(gps->pb.numb, fcomma + 1, (lcomma-fcomma-1)); ++ gps->pb.numb[(lcomma - fcomma) - 1] = '\0'; ++ ++ gps->pb.type = atoi(lcomma + 2); ++ ++ ptr2 = strrchr(ptr1, ','); ++ fcomma = ptr2 + 1; ++ lcomma = strchr(fcomma + 1, '"'); ++ strncpy(gps->pb.text, fcomma + 1, (lcomma - fcomma - 1)); ++ gps->pb.text[(lcomma - fcomma) - 1] = '\0'; ++ ++ llist_add_tail(&gps->list, &gu->pb_readrg_list); ++ ++ (*num)++; ++ ++ ptr1 = strtok(NULL, "\n"); ++ } + + usock_cmd_enqueue(ucmd, gu); + +@@ -1209,22 +1273,38 @@ + static int phonebook_list_storage_cb(struct gsmd_atcmd *cmd, + void *ctx, char *resp) + { +- /* +CPBS: ("EN","BD","FD","DC","LD","RC","LR","MT","AD", +- * "SM","SD","MC","LM","AF","ON","UD") */ + /* TODO; using link list ; need to handle command error */ + struct gsmd_user *gu = ctx; + struct gsmd_ucmd *ucmd; ++ struct gsmd_phonebook_storage *gps; ++ char *ptr; + + DEBUGP("resp: %s\n", resp); + +- ucmd = gsmd_ucmd_fill(strlen(resp) + 1, ++ /* ++ * +CPBS: (<storage>s) ++ */ ++ ++ ucmd = gsmd_ucmd_fill(sizeof(*gps), + GSMD_MSG_PHONEBOOK, + GSMD_PHONEBOOK_LIST_STORAGE, 0); + + if (!ucmd) + return -ENOMEM; + +- strcpy(ucmd->buf, resp); ++ gps = (struct gsmd_phonebook_storage *) ucmd->buf; ++ gps->num = 0; ++ ++ if (!strncmp(resp, "+CPBS", 5)) { ++ char* delim = "(,"; ++ ptr = strpbrk(resp, delim); ++ while ( ptr ) { ++ strncpy(gps->mem[gps->num].type, ptr+2, 2); ++ gps->mem[gps->num].type[2] = '\0'; ++ ptr = strpbrk(ptr+2, delim); ++ gps->num++; ++ } ++ } + + usock_cmd_enqueue(ucmd, gu); + +@@ -1235,11 +1315,13 @@ + struct gsmd_msg_hdr *gph,int len) + { + struct gsmd_atcmd *cmd = NULL; ++ struct gsmd_ucmd *ucmd = NULL; + struct gsmd_phonebook_readrg *gpr; + struct gsmd_phonebook *gp; + struct gsmd_phonebook_find *gpf; +- int *index; +- int atcmd_len; ++ struct gsmd_phonebooks *cur, *cur2; ++ int *index, *num; ++ int atcmd_len, i; + char *storage; + char buf[1024]; + +@@ -1343,6 +1425,66 @@ + cmd = atcmd_fill("AT+CPBR=?", 9+1, + &phonebook_get_support_cb, gu, gph->id); + break; ++ case GSMD_PHONEBOOK_RETRIEVE_READRG: ++ if (len < sizeof(*gph) + sizeof(int)) ++ return -EINVAL; ++ ++ num = (int *) ((void *)gph + sizeof(*gph)); ++ ++ ucmd = gsmd_ucmd_fill(sizeof(struct gsmd_phonebook)*(*num), ++ GSMD_MSG_PHONEBOOK, ++ GSMD_PHONEBOOK_RETRIEVE_READRG, 0); ++ if (!ucmd) ++ return -ENOMEM; ++ ++ gp = (struct gsmd_phonebook*) ucmd->buf; ++ ++ if (!llist_empty(&gu->pb_readrg_list)) { ++ ++ llist_for_each_entry_safe(cur, cur2, ++ &gu->pb_readrg_list, list) { ++ gp->index = cur->pb.index; ++ strcpy(gp->numb, cur->pb.numb); ++ gp->type = cur->pb.type; ++ strcpy(gp->text, cur->pb.text); ++ gp++; ++ ++ llist_del(&cur->list); ++ free(cur); ++ } ++ } ++ ++ usock_cmd_enqueue(ucmd, gu); ++ ++ break; ++ case GSMD_PHONEBOOK_RETRIEVE_FIND: ++ if (len < sizeof(*gph) + sizeof(int)) ++ return -EINVAL; ++ ++ num = (int *) ((void *)gph + sizeof(*gph)); ++ ++ ucmd = gsmd_ucmd_fill(sizeof(struct gsmd_phonebook)*(*num), GSMD_MSG_PHONEBOOK, ++ GSMD_PHONEBOOK_RETRIEVE_FIND, 0); ++ if (!ucmd) ++ return -ENOMEM; ++ ++ gp = (struct gsmd_phonebook*) ucmd->buf; ++ ++ if (!llist_empty(&gu->pb_find_list)) { ++ llist_for_each_entry_safe(cur, cur2, &gu->pb_find_list, list) { ++ gp->index = cur->pb.index; ++ strcpy(gp->numb, cur->pb.numb); ++ gp->type = cur->pb.type; ++ strcpy(gp->text, cur->pb.text); ++ gp++; ++ ++ llist_del(&cur->list); ++ free(cur); ++ } ++ } ++ ++ usock_cmd_enqueue(ucmd, gu); ++ break; + default: + return -EINVAL; + } +@@ -1468,6 +1610,8 @@ + newuser->gsmd = g; + newuser->subscriptions = 0xffffffff; + INIT_LLIST_HEAD(&newuser->finished_ucmds); ++ INIT_LLIST_HEAD(&newuser->pb_readrg_list); ++ INIT_LLIST_HEAD(&newuser->pb_find_list); + + llist_add(&newuser->list, &g->users); + gsmd_register_fd(&newuser->gfd); diff --git a/packages/gsm/files/028_shell-phonebook-find-and-read-range-support.patch b/packages/gsm/files/028_shell-phonebook-find-and-read-range-support.patch new file mode 100644 index 0000000000..db07a5df35 --- /dev/null +++ b/packages/gsm/files/028_shell-phonebook-find-and-read-range-support.patch @@ -0,0 +1,264 @@ +From: Sean Chiang <sean_chiang@openmoko.com> +Subject: [PATCH] improvement for find and read phonebooks in shell + +This patch improves the functions to find and read phonebooks in shell. + +Besides prr and pf, I add two new commands pRr and pRf to retrieve the +phonebook. + +Signed-off-by: Jim Huang <jserv@openmoko.org> + +Index: gsm/src/util/shell.c +=================================================================== +--- gsm.orig/src/util/shell.c 2007-09-17 23:57:51.000000000 +0800 ++++ gsm/src/util/shell.c 2007-09-17 23:59:04.000000000 +0800 +@@ -34,8 +34,6 @@ + #include <gsmd/usock.h> + #include <gsmd/ts0705.h> + +-#include <common/linux_list.h> +- + #ifndef __GSMD__ + #define __GSMD__ + #include <gsmd/talloc.h> +@@ -43,9 +41,8 @@ + #endif + + #define STDIN_BUF_SIZE 1024 +- +-static LLIST_HEAD(storage_list); +-static LLIST_HEAD(phonebook_list); ++static int nFIND = 0; ++static int nREADRG = 0; + + /* this is the handler for receiving passthrough responses */ + static int pt_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh) +@@ -62,46 +59,23 @@ + struct gsmd_phonebook_storage *gpst; + char *payload; + char *fcomma, *lcomma, *ptr = NULL; ++ int *num; + char buf[128]; ++ int i; + + switch (gmh->msg_subtype) { +-#if 0 + case GSMD_PHONEBOOK_FIND: ++ num = (int *) ((char *)gmh + sizeof(*gmh)); ++ printf("Records:%d\n", *num); ++ ++ nFIND = *num; ++ break; + case GSMD_PHONEBOOK_READRG: +- payload = (char *)gmh + sizeof(*gmh); ++ num = (int *) ((char *)gmh + sizeof(*gmh)); ++ printf("Records:%d\n", *num); + +- if (!strncmp(payload, "+CPBR", 5) || +- !strncmp(payload, "+CPBF", 5)) { +- gp = (struct gsmd_phonebook *) malloc(sizeof(struct gsmd_phonebook)); +- ptr = strchr(payload, ' '); +- gp->index = atoi(ptr+1); +- +- fcomma = strchr(payload, '"'); +- lcomma = strchr(fcomma+1, '"'); +- strncpy(gp->numb, fcomma + 1, (lcomma-fcomma-1)); +- gp->numb[(lcomma - fcomma) - 1] = '\0'; +- +- gp->type = atoi(lcomma + 2); +- +- ptr = strrchr(payload, ','); +- fcomma = ptr + 1; +- lcomma = strchr(fcomma + 1, '"'); +- strncpy(gp->text, fcomma + 1, (lcomma - fcomma - 1)); +- gp->text[(lcomma - fcomma) - 1] = '\0'; +- +- llist_add_tail(&gp->list, &phonebook_list); +- +-#if 0 +- llist_for_each_entry(gp, &phonebook_list, list) { +- printf("%d, %s, %d, %s\n", gp->index, gp->numb, gp->type, gp->text); +- } +-#endif +- printf("%d, %s, %d, %s\n", gp->index, gp->numb, gp->type, gp->text); +- } +- else +- printf("%s\n", payload); ++ nREADRG = *num; + break; +-#endif + case GSMD_PHONEBOOK_READ: + gp = (struct gsmd_phonebook *) ((char *)gmh + sizeof(*gmh)); + if (gp->index) +@@ -115,48 +89,18 @@ + gps = (struct gsmd_phonebook_support *) ((char *)gmh + sizeof(*gmh)); + printf("(1-%d), %d, %d\n", gps->index, gps->nlength, gps->tlength); + break; +-#if 0 +- case GSMD_PHONEBOOK_LIST_STORAGE: +- payload = (char *)gmh + sizeof(*gmh); + +- if (!strncmp(payload, "+CPBS", 5)) { +- char* delim = "(,"; +- struct gsmd_phonebook_storage *cur, *cur2; +- +- /* Remove previous record */ +- if (!llist_empty(&storage_list)) { +- llist_for_each_entry_safe(cur, cur2, +- &storage_list, list) { +- llist_del(&cur->list); +- talloc_free(cur); +- } +- } +- +- ptr = strpbrk(payload, delim); +- +- while ( ptr ) { +- gpst = (struct gsmd_phonebook_storage *) malloc(sizeof(struct gsmd_phonebook_storage)); +- strncpy(gpst->storage, ptr+2, 2); +- gpst->storage[2] = '\0'; +- +- ptr = strpbrk(ptr+2, delim); +- +- llist_add_tail(&gpst->list, &storage_list); +- } ++ case GSMD_PHONEBOOK_LIST_STORAGE: ++ gpst = (struct gsmd_phonebook_storage *)((char *)gmh + sizeof(*gmh)); + +- if (llist_empty(&storage_list)) +- return 0; ++ for (i = 0; i < gpst->num; i++) { ++ printf("%s, ", gpst->mem[i].type); ++ } + +- llist_for_each_entry(cur, &storage_list, list) { +- printf("\n%s",cur->storage); +- } ++ printf("\n"); + +- printf("\n"); +- } +- else +- printf("%s\n", payload); + break; +-#endif ++ + case GSMD_PHONEBOOK_WRITE: + case GSMD_PHONEBOOK_DELETE: + case GSMD_PHONEBOOK_SET_STORAGE: +@@ -164,6 +108,26 @@ + payload = (char *)gmh + sizeof(*gmh); + printf("%s\n", payload); + break; ++ case GSMD_PHONEBOOK_RETRIEVE_READRG: ++ gp = (struct gsmd_phonebook *) ((char *)gmh + sizeof(*gmh)); ++ ++ for (i=0; i<nREADRG; i++) { ++ printf("%d,%s,%d,%s\n", gp->index, gp->numb, gp->type, gp->text); ++ gp++; ++ } ++ ++ nREADRG = 0; ++ break; ++ case GSMD_PHONEBOOK_RETRIEVE_FIND: ++ gp = (struct gsmd_phonebook *) ((char *)gmh + sizeof(*gmh)); ++ ++ for (i = 0; i < nFIND; i++) { ++ printf("%d,%s,%d,%s\n", gp->index, gp->numb, gp->type, gp->text); ++ gp++; ++ } ++ ++ nFIND = 0; ++ break; + default: + return -EINVAL; + } +@@ -381,11 +345,13 @@ + "\tpd\tPB Delete (pb=index)\n" + "\tpr\tPB Read (pr=index)\n" + "\tprr\tPB Read Range (prr=index1,index2)\n" +- "\tpf\tPB Find (pff=indtext)\n" ++ "\tpf\tPB Find (pf=indtext)\n" + "\tpw\tPB Write (pw=index,number,text)\n" + "\tps\tPB Support\n" + "\tpm\tPB Memory\n" + "\tpp\tPB Set Memory (pp=storage)\n" ++ "\tpRr\tRetrieve Readrg Records\n" ++ "\tpRf\tRetrieve Find Records\n" + "\tsd\tSMS Delete (sd=index,delflg)\n" + "\tsl\tSMS List (sl=stat)\n" + "\tsr\tSMS Read (sr=index)\n" +@@ -509,48 +475,21 @@ + printf("Delete Phonebook Entry\n"); + ptr = strchr(buf, '='); + lgsm_pb_del_entry(lgsmh, atoi(ptr+1)); +-#if 0 + } else if ( !strncmp(buf, "prr", 3)) { + printf("Read Phonebook Entries\n"); + struct lgsm_phonebook_readrg pb_readrg; +- struct gsmd_phonebook *gp_cur, *gp_cur2; +- +- /* Remove records */ +- if (!llist_empty(&phonebook_list)) { +- llist_for_each_entry_safe(gp_cur, +- gp_cur2, +- &phonebook_list, +- list) { +- llist_del(&gp_cur->list); +- talloc_free(gp_cur); +- } +- } + + ptr = strchr(buf, '='); + pb_readrg.index1 = atoi(ptr+1); + ptr = strchr(buf, ','); + pb_readrg.index2 = atoi(ptr+1); + lgsm_pb_read_entries(lgsmh, &pb_readrg); +-#endif + } else if ( !strncmp(buf, "pr", 2)) { + ptr = strchr(buf, '='); + lgsm_pb_read_entry(lgsmh, atoi(ptr+1)); +-#if 0 + } else if ( !strncmp(buf, "pf", 2)) { + printf("Find Phonebook Entry\n"); + struct lgsm_phonebook_find pb_find; +- struct gsmd_phonebook *gp_cur, *gp_cur2; +- +- /* Remove records */ +- if (!llist_empty(&phonebook_list)) { +- llist_for_each_entry_safe(gp_cur, +- gp_cur2, +- &phonebook_list, +- list) { +- llist_del(&gp_cur->list); +- talloc_free(gp_cur); +- } +- } + + ptr = strchr(buf, '='); + strncpy(pb_find.findtext, +@@ -559,7 +498,6 @@ + pb_find.findtext[strlen(ptr+1)] = '\0'; + + lgsm_pb_find_entry(lgsmh, &pb_find); +-#endif + } else if ( !strncmp(buf, "pw", 2)) { + printf("Write Phonebook Entry\n"); + struct lgsm_phonebook pb; +@@ -591,6 +529,16 @@ + } else if ( !strncmp(buf, "ps", 2)) { + printf("Get Phonebook Support\n"); + lgsm_pb_get_support(lgsmh); ++ } else if( !strncmp(buf, "pRr", 3) ) { ++ printf("Retrieve Readrg Records\n"); ++ ++ if ( nREADRG ) ++ lgsm_pb_retrieve_readrg(lgsmh, nREADRG); ++ } else if( !strncmp(buf, "pRf", 3) ) { ++ printf("Retrieve Find Records\n"); ++ ++ if ( nFIND ) ++ lgsm_pb_retrieve_find(lgsmh, nFIND); + } else if ( !strncmp(buf, "sd", 2)) { + printf("Delete SMS\n"); + struct lgsm_sms_delete sms_del; diff --git a/packages/gsm/files/default b/packages/gsm/files/default index 161c97f5fb..761100f702 100644 --- a/packages/gsm/files/default +++ b/packages/gsm/files/default @@ -1,9 +1,48 @@ # gsmd This shell script configures for the gsmd init script. -# If you must specify special options, uncomment and modify the next line -#GSMD_OPTS="-s 115200 -F" +. /etc/init.d/functions -# If your GSM device needs to be powered up, uncomment and modify the next line -#GSM_POW="/sys/bus/platform/devices/gta01-pm-gsm.0/power_on" +case `cpuinfo_id` in + "GTA01"|"GTA02") + GSMD_OPTS="-s 115200 -F" + GSM_POW="/sys/bus/platform/devices/gta01-pm-gsm.0/power_on" + GSM_RES="/sys/bus/platform/devices/gta01-pm-gsm.0/reset" + GSM_DEV="/dev/ttySAC0" + ;; + "HTC Apache"|"HTC Blueangel"|"HTC Universal") + GSMD_OPTS="-s 115200 -F" + GSM_DEV="/dev/ttyS0" + ;; + "HTC Himalaya") + GSMD_OPTS="-s 115200 -F" + GSM_DEV="/dev/ttyS2" + ;; + "HTC Magician") + GSMD_OPTS="-s 115200 -F" + GSM_DEV="/dev/ttyS1" + ;; + "Palm Treo 650") + GSMD_OPTS="-s 460800 -F -w 1" + GSM_DEV="/dev/ttyS0" + ;; + "Motorola Ezx Platform") + GSMD_OPTS="-s 115200 -F -v ti" + GSM_DEV="/dev/mux0" + ;; + *) + # Unknown board -#GSM_DEV="/dev/ttyS1" + # If you must specify special options, uncomment and modify the next line + #GSMD_OPTS="-s 115200 -F" + + # If your GSM device needs to be powered up, uncomment and modify the next line + #GSM_POW="/sys/bus/platform/devices/gta01-pm-gsm.0/power_on" + + # If your GSM device then needs to be reset, uncomment and modify the next line + #GSM_RES="/sys/bus/platform/devices/gta01-pm-gsm.0/reset" + + # This should be in a common /etc/default/serial, together with + # BT_DEV and IR_DEV for devices that have those on a serial port + #GSM_DEV="/dev/ttyS1" + ;; +esac diff --git a/packages/gsm/files/fic-gta01/default b/packages/gsm/files/fic-gta01/default deleted file mode 100644 index 1511376a6c..0000000000 --- a/packages/gsm/files/fic-gta01/default +++ /dev/null @@ -1,9 +0,0 @@ -# gsmd This shell script configures for the gsmd init script. - -# If you must specify special options, uncomment and modify the next line -GSMD_OPTS="-s 115200 -F" - -# If your GSM device needs to be powered up, uncomment and modify the next line -GSM_POW="/sys/bus/platform/devices/gta01-pm-gsm.0/power_on" - -GSM_DEV="/dev/ttySAC0" diff --git a/packages/gsm/files/fic-gta01/gsmd b/packages/gsm/files/fic-gta01/gsmd new file mode 100644 index 0000000000..d8323e202c --- /dev/null +++ b/packages/gsm/files/fic-gta01/gsmd @@ -0,0 +1,49 @@ +#!/bin/sh +# +# gsmd This shell script starts and stops gsmd. +# +# chkconfig: 345 90 40 +# description: Gsmd manages access to a serial- or USB-connected GSM +# processname: gsmd + +PATH=/bin:/usr/bin:/sbin:/usr/sbin + +[ -f /etc/default/rcS ] && . /etc/default/rcS +[ -f /etc/default/gsmd ] && . /etc/default/gsmd + +case "$1" in + start) + stty -F "$GSM_DEV" -crtscts + [ -n "$GSM_POW" ] && ( echo "0" >$GSM_POW; sleep 1 ) + stty -F "$GSM_DEV" -echo + [ -n "$GSM_POW" ] && ( echo "1" >$GSM_POW; sleep 1 ) + [ -n "$GSM_RES" ] && ( echo "1" >$GSM_RES; sleep 1 ) + [ -n "$GSM_RES" ] && ( echo "0" >$GSM_RES; sleep 2 ) + + echo -n "Starting GSM daemon: " + start-stop-daemon -S -x /usr/sbin/gsmd -- gsmd -p $GSM_DEV $GSMD_OPTS >/tmp/gsm.log 2>&1 & + + if [ $? = 0 ]; then + echo "gsmd." + else + echo "(failed.)" + fi + ;; + stop) + echo -n "Stopping GSM daemon: " + start-stop-daemon -K -x /usr/sbin/gsmd + stty -F "$GSM_DEV" -crtscts + [ -n "$GSM_POW" ] && echo "0" >$GSM_POW + echo "gsmd." + ;; + restart|force-reload) + $0 stop + $0 start + ;; + *) + echo "Usage: /etc/init.d/gsmd {start|stop|restart|force-reload}" + exit 1 + ;; +esac + +exit 0 diff --git a/packages/gsm/files/gsmd b/packages/gsm/files/gsmd index 5c78e8178a..0ac4698899 100644 --- a/packages/gsm/files/gsmd +++ b/packages/gsm/files/gsmd @@ -1,106 +1,49 @@ -#!/bin/sh +##!/bin/sh # -# gsmd This shell script starts and stops gsmd. +# gsmd This shell script starts and stops gsmd. # # chkconfig: 345 90 40 # description: Gsmd manages access to a serial- or USB-connected GSM # processname: gsmd -# Source configuration -. /etc/default/gsmd +PATH=/bin:/usr/bin:/sbin:/usr/sbin -# Source function library. -#. /etc/rc.d/init.d/functions +[ -f /etc/default/rcS ] && . /etc/default/rcS +[ -f /etc/default/gsmd ] && . /etc/default/gsmd -RETVAL=0 -prog="gsmd" - -start() { - # Hack for broken uboot and/or kernel on the neo1973 - dmesg -n1 - - if [ -n "${GSM_POW}" ] - then - if [ -e "${GSM_POW}" ] - then - echo -n "Powering up GSM device..." - echo "1" > ${GSM_POW} - sleep 1 - echo "done" - else - echo "GSM device not found. Aborting startup" - return false - fi - fi - # Start daemons. - echo -n "Starting $prog: " - # We don't use the daemon function here because of a known bug - # in initlog -- it spuriously returns a nonzero status when - # starting daemons that fork themselves. See - # http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=130629 - # for discussion. Fortunately: - # - # 1. gsmd startup can't fail, or at least not in the absence of - # much larger resource-exhaustion problems that would be very obvious. - # - # 2. We don't need all the logging crud that daemon/initlog sets - # up -- gsmd does its own syslog calls. - # - if [ -e "${GSM_DEV}" ] - then - gsmd -p ${GSM_DEV} ${GSMD_OPTS} >/tmp/gsm.log 2>&1 & - echo "success" - else - # User needs to symlink ${GPS_DEV} to the right thing - echo "No ${GSM_DEV} device, aborting gsmd startup." - fi - RETVAL=$? - echo - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/gsmd - return $RETVAL -} - -stop() { - # Stop daemons. - echo -n "Shutting down $prog: " - killall gsmd -# killproc gsmd - RETVAL=$? - echo - if [ $RETVAL -eq 0 ] - then - rm -f /var/lock/subsys/gsmd; - fi - return $RETVAL -} - -# See how we were called. case "$1" in - start) - start - ;; - stop) - stop - ;; - restart|reload) - stop - start - RETVAL=$? - ;; - condrestart) - if [ -f /var/lock/subsys/gsmd ]; then - stop - start - RETVAL=$? - fi - ;; - status) -# status gsmd -# RETVAL=$? - ;; - *) - echo "Usage: $0 {start|stop|restart|condrestart|status}" - exit 1 + start) + [ -n "$GSM_POW" ] && ( echo "0" >$GSM_POW; sleep 1 ) + [ -n "$GSM_POW" ] && ( echo "1" >$GSM_POW; sleep 1 ) + [ -n "$GSM_RES" ] && ( echo "1" >$GSM_RES; sleep 1 ) + [ -n "$GSM_RES" ] && ( echo "0" >$GSM_RES; sleep 2 ) + + echo -n "Starting GSM daemon: " + start-stop-daemon -S -x /usr/sbin/gsmd -- gsmd -p $GSM_DEV $GSMD_OPTS >/tmp/gsm.log 2>&1 & + + if [ $? = 0 ]; then + echo "gsmd." + else + echo "(failed.)" + fi + ;; + stop) + [ -n "$GSM_POW" ] && echo "0" >$GSM_POW + + echo -n "Stopping GSM daemon: " + start-stop-daemon -K -x /usr/sbin/gsmd + echo "gsmd." + ;; + restart|force-reload) + $0 stop + $0 start + exit + ;; + *) + echo "Usage: /etc/init.d/apmd {start|stop|restart|force-reload}" + exit 1 + ;; esac -exit $RETVAL +exit 0 + diff --git a/packages/gsm/files/htcuniversal/.mtn2git_empty b/packages/gsm/files/htcuniversal/.mtn2git_empty deleted file mode 100644 index e69de29bb2..0000000000 --- a/packages/gsm/files/htcuniversal/.mtn2git_empty +++ /dev/null diff --git a/packages/gsm/files/htcuniversal/default b/packages/gsm/files/htcuniversal/default deleted file mode 100644 index b09d433d1e..0000000000 --- a/packages/gsm/files/htcuniversal/default +++ /dev/null @@ -1,10 +0,0 @@ -# gsmd This shell script configures for the gsmd init script. - -GSMD_OPTS="-s 115200 -F -w 1" - -# If your GSM device needs to be powered up, uncomment and modify the next line -#GSM_POW="/sys/bus/platform/devices/gta01-pm-gsm.0/power_on" - -# this should be in a common /etc/default/serial, together -# with BT_DEV, and IR_DEV -GSM_DEV="/dev/ttyS0" diff --git a/packages/gsm/files/lgsm_send_fix_return_value.patch b/packages/gsm/files/lgsm_send_fix_return_value.patch new file mode 100644 index 0000000000..00ba3a4549 --- /dev/null +++ b/packages/gsm/files/lgsm_send_fix_return_value.patch @@ -0,0 +1,11 @@ +--- gsm/src/libgsmd/libgsmd.c.orig 2007-09-25 00:41:56.000000000 -0500 ++++ gsm/src/libgsmd/libgsmd.c 2007-09-25 00:43:44.000000000 -0500 +@@ -210,7 +210,7 @@ + pos += rc; + } + } +- return 0; ++ return (sizeof(*gmh) + gmh->len); + } + + struct gsmd_msg_hdr *lgsm_gmh_fill(int type, int subtype, int payload_len) diff --git a/packages/gsm/files/magician/.mtn2git_empty b/packages/gsm/files/magician/.mtn2git_empty deleted file mode 100644 index e69de29bb2..0000000000 --- a/packages/gsm/files/magician/.mtn2git_empty +++ /dev/null diff --git a/packages/gsm/files/magician/default b/packages/gsm/files/magician/default deleted file mode 100644 index 523d0b9479..0000000000 --- a/packages/gsm/files/magician/default +++ /dev/null @@ -1,10 +0,0 @@ -# gsmd This shell script configures for the gsmd init script. - -GSMD_OPTS="-s 115200 -F" - -# If your GSM device needs to be powered up, uncomment and modify the next line -#GSM_POW="/sys/bus/platform/devices/gta01-pm-gsm.0/power_on" - -# this should be in a common /etc/default/serial, together -# with BT_DEV, and IR_DEV -GSM_DEV="/dev/ttyS1" diff --git a/packages/gsm/libgsmd_svn.bb b/packages/gsm/libgsmd_svn.bb index c715092b8d..9aaad58ee6 100644 --- a/packages/gsm/libgsmd_svn.bb +++ b/packages/gsm/libgsmd_svn.bb @@ -3,17 +3,28 @@ HOMEPAGE = "http://www.openmoko.org" LICENSE = "GPL LGPL" SECTION = "libs/gsm" PROVIDES += "gsmd" -PV = "0.1+svn${SRCDATE}" -PR = "r19" - -SRC_URI_OVERRIDES_PACKAGE_ARCH = "1" +PV = "0.1+svnr${SRCREV}" +PR = "r31" SRC_URI = "svn://svn.openmoko.org/trunk/src/target;module=gsm;proto=http \ + file://024_sms-text-in-bracket.patch;patch=1;minrev=2957 \ + file://025_sms-status-report.patch;patch=1;minrev=2957 \ + file://027_phonebook-find-and-read-range-support.patch;patch=1;minrev=2957 \ + file://028_shell-phonebook-find-and-read-range-support.patch;patch=1;minrev=2957 \ + file://0001-Introduce-ports.patch;patch=1;minrev=2957 \ + file://0002-Flush-all-pending-commands-before-restarting-the-mod.patch;patch=1;minrev=2957 \ + file://0003-Correctly-segment-incoming-usock-data-into-packets.patch;patch=1;minrev=2957 \ + file://0004-Handle-read-and-write-return-values.patch;patch=1;minrev=2957 \ + file://0005-Add-ask-ds-option-forSMS.patch;patch=1;minrev=2957 \ + file://lgsm_send_fix_return_value.patch;patch=1 \ file://gsmd \ file://default" S = "${WORKDIR}/gsm" inherit autotools pkgconfig update-rc.d +# handle update-rc.d RDEPENDS manually, we don't need it on +# anything but gsmd +RDEPENDS_append = "" INITSCRIPT_NAME = "gsmd" INITSCRIPT_PARAMS = "defaults 35" @@ -31,15 +42,25 @@ do_install_append() { PACKAGES =+ "${PN}-tools gsmd gsmd-plugins \ gsmd-plugin-machine-generic gsmd-plugin-machine-tihtc \ - gsmd-plugin-vendor-qc gsmd-plugin-vendor-ti \ - gsmd-plugin-vendor-tihtc" + gsmd-plugin-vendor-bcm \ + gsmd-plugin-vendor-qc \ + gsmd-plugin-vendor-ti \ + gsmd-plugin-vendor-tihtc \ + " + RDEPENDS_${PN} = "gsmd" RDEPENDS_gsmd-plugins = "gsmd-plugin-machine-generic \ gsmd-plugin-machine-tihtc \ + gsmd-plugin-vendor-bcm \ gsmd-plugin-vendor-qc \ gsmd-plugin-vendor-ti \ - gsmd-plugin-vendor-tihtc" + gsmd-plugin-vendor-tihtc \ + " + +RDEPENDS_gsmd = "update-rc.d initscripts" RRECOMMENDS_gsmd = "gsmd-plugins" + +FILES_${PN}-dbg += "${libdir}/gsmd/.debug/*" FILES_${PN}-tools = "${bindir}/*" FILES_gsmd = "${sbindir}/gsmd ${sysconfdir}" FILES_gsmd-plugins = "" |