Ticket #90: 0001-Introduce-ports.patch

File 0001-Introduce-ports.patch, 16.7 KB (added by balrogg@…, 12 years ago)

Use struct gsmd_port instead of fd's.

  • include/gsmd/atcmd.h

    From c1dbbbd2bd486dbcf599108b741c615fc5b4c79c Mon Sep 17 00:00:00 2001
    From: Andrzej Zaborowski <balrog@zabor.org>
    Date: Sat, 4 Aug 2007 04:00:01 +0200
    Subject: [PATCH] Introduce ports.
    
    ---
     include/gsmd/atcmd.h |    2 +-
     include/gsmd/gsmd.h  |    7 ++-
     include/gsmd/uart.h  |   28 +++++++
     src/gsmd/Makefile.am |    2 +-
     src/gsmd/atcmd.c     |  173 ++++++++++++++++++++------------------------
     src/gsmd/gsmd.c      |   57 ++-------------
     src/gsmd/uart.c      |  197 ++++++++++++++++++++++++++++++++++++++++++++++++++
     7 files changed, 316 insertions(+), 150 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 b typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp); 
    99 
    1010extern struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id); 
    1111extern int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd); 
    12 extern int atcmd_init(struct gsmd *g, int sockfd); 
     12extern int atcmd_init(struct gsmd *g, struct gsmd_port *port); 
    1313extern void atcmd_drain(int fd); 
    1414 
    1515#endif /* __GSMD__ */ 
  • include/gsmd/gsmd.h

    diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h
    index 337b2ec..d8d293e 100644
    a b  
    1010#include <gsmd/machineplugin.h> 
    1111#include <gsmd/vendorplugin.h> 
    1212#include <gsmd/select.h> 
     13#include <gsmd/uart.h> 
    1314#include <gsmd/state.h> 
    1415 
    1516void *gsmd_tallocs; 
    enum llparse_state { 
    4748#define LLPARSE_BUF_SIZE        1024 
    4849 
    4950struct llparser { 
     51        struct gsmd_port *port; 
    5052        enum llparse_state state; 
    5153        unsigned int len; 
    5254        unsigned int flags; 
    struct gsmd; 
    6567struct gsmd { 
    6668        unsigned int flags; 
    6769        int interpreter_ready; 
    68         struct gsmd_fd gfd_uart; 
     70        struct gsmd_uart uart; 
    6971        struct gsmd_fd gfd_sock; 
    7072        struct llparser llp; 
    7173        struct llist_head users; 
    struct gsmd { 
    7678        struct gsmd_device_state dev_state; 
    7779 
    7880        struct llist_head operators;            /* cached list of operator names */ 
    79         unsigned char *mlbuf;           /* ml_parse buffer */ 
     81        char mlbuf[2048];               /* ml_parse buffer */ 
    8082        unsigned int mlbuf_len; 
    8183        int mlunsolicited; 
     84        int clear_to_send; 
    8285}; 
    8386 
    8487struct gsmd_user { 
  • new file include/gsmd/uart.h

    diff --git a/include/gsmd/uart.h b/include/gsmd/uart.h
    new file mode 100644
    index 0000000..a006fa7
    - +  
     1#ifndef __GSMD_UART_H 
     2#define __GSMD_UART_H 
     3 
     4#ifdef __GSMD__ 
     5 
     6struct gsmd_port { 
     7        int (*write)(struct gsmd_port *port, const char data[], int len); 
     8        int (*set_break)(struct gsmd_port *port, int state); 
     9        /* more parameters here */ 
     10        int (*newdata_cb)(void *opaque, const char data[], int len); 
     11        void *newdata_opaque; 
     12}; 
     13 
     14struct gsmd_uart { 
     15        struct gsmd_port port; 
     16        struct gsmd_fd gfd; 
     17        char txfifo[2048]; 
     18        int tx_start; 
     19        int tx_len; 
     20}; 
     21 
     22extern int set_baudrate(int fd, int baudrate, int hwflow); 
     23extern void uart_drain(int fd); 
     24extern int uart_init(struct gsmd_uart *uart, int sockfd); 
     25 
     26#endif /* __GSMD__ */ 
     27 
     28#endif 
  • src/gsmd/Makefile.am

    diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am
    index 1ff1970..3c71001 100644
    a b sbin_PROGRAMS = gsmd 
    77gsmd_CFLAGS = -D PLUGINDIR=\"$(plugindir)\" 
    88gsmd_SOURCES = gsmd.c atcmd.c select.c machine.c vendor.c unsolicited.c log.c \ 
    99               usock.c talloc.c timer.c operator_cache.c ext_response.c \ 
    10                sms_cb.c sms_pdu.c 
     10               sms_cb.c sms_pdu.c uart.c 
    1111gsmd_LDADD = -ldl 
    1212gsmd_LDFLAGS = -Wl,--export-dynamic 
    1313 
  • src/gsmd/atcmd.c

    diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c
    index 514625b..947aabb 100644
    a b static int llparse_byte(struct llparser *llp, char byte) 
    149149        return ret; 
    150150} 
    151151 
    152 static int llparse_string(struct llparser *llp, char *buf, unsigned int len) 
     152static int llparse_string(struct llparser *llp, const char *buf, 
     153                unsigned int len) 
    153154{ 
    154155        while (len--) { 
    155156                int rc = llparse_byte(llp, *(buf++)); 
    static int llparse_init(struct llparser *llp) 
    177178        return 0; 
    178179} 
    179180 
     181/* See if we can now send more commands to the port */ 
     182static void atcmd_wake_queue(struct gsmd *g) 
     183{ 
     184        int len, rc; 
     185        char *cr; 
     186 
     187        /* write pending commands to UART */ 
     188        while (g->interpreter_ready && g->clear_to_send) { 
     189                struct gsmd_atcmd *pos, *pos2; 
     190                llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) { 
     191                        cr = strchr(pos->cur, '\n'); 
     192                        if (cr) 
     193                                len = cr - pos->cur; 
     194                        else 
     195                                len = pos->buflen; 
     196                        rc = g->llp.port->write(g->llp.port, pos->cur, len); 
     197                        if (rc == 0) { 
     198                                gsmd_log(GSMD_ERROR, 
     199                                                "write returns 0, aborting\n"); 
     200                                break; 
     201                        } 
     202                        if (cr && rc == len) 
     203                                rc ++;  /* Skip the \n */ 
     204                        pos->buflen -= rc; 
     205                        pos->cur += rc; 
     206                        g->llp.port->write(g->llp.port, "\r", 1); 
     207 
     208                        if (!pos->buflen) { 
     209                                /* success: remove from global list of 
     210                                 * to-be-sent atcmds */ 
     211                                llist_del(&pos->list); 
     212                                /* append to global list of executing atcmds */ 
     213                                llist_add_tail(&pos->list, &g->busy_atcmds); 
     214 
     215                                /* we only send one cmd at the moment */ 
     216                                g->clear_to_send = 0; 
     217                                break; 
     218                        } else { 
     219                                /* The write was short or the atcmd has more 
     220                                 * lines to send after a "> ".  */ 
     221                                if (rc < len) 
     222                                        break; 
     223                                g->clear_to_send = 0; 
     224                                break; 
     225                        } 
     226                } 
     227        } 
     228} 
     229 
    180230/* mid-level parser */ 
    181231 
    182232static int parse_final_result(const char *res) 
    static int ml_parse(const char *buf, int len, void *ctx) 
    206256                g->interpreter_ready = 1; 
    207257                gsmd_initsettings(g); 
    208258                gmsd_alive_start(g); 
     259                atcmd_wake_queue(g); 
    209260                return 0; 
    210261        } 
    211262 
    static int ml_parse(const char *buf, int len, void *ctx) 
    306357                                } else { 
    307358                                        DEBUGP("Calling cmd->cb()\n"); 
    308359                                        cmd->resp = g->mlbuf; 
     360                                        g->mlbuf[g->mlbuf_len] = 0; 
    309361                                        rc = cmd->cb(cmd, cmd->ctx, cmd->resp); 
    310362                                        DEBUGP("Clearing mlbuf\n"); 
    311363                                } 
    static int ml_parse(const char *buf, int len, void *ctx) 
    366418        g->mlbuf_len += len; 
    367419 
    368420        if (g->mlunsolicited) { 
     421                g->mlbuf[g->mlbuf_len] = 0; 
    369422                rc = unsolicited_parse(g, g->mlbuf, g->mlbuf_len, 
    370423                                strchr(g->mlbuf, ':') + 1); 
    371424                if (rc == -EAGAIN) { 
    final_cb: 
    412465 
    413466        /* if we're finished with current commands, but still have pending 
    414467         * commands: we want to WRITE again */ 
    415         if (llist_empty(&g->busy_atcmds) && !llist_empty(&g->pending_atcmds)) 
    416                 g->gfd_uart.when |= GSMD_FD_WRITE; 
     468        if (llist_empty(&g->busy_atcmds)) { 
     469                g->clear_to_send = 1; 
     470                if (!llist_empty(&g->pending_atcmds)) 
     471                        atcmd_wake_queue(g); 
     472        } 
    417473 
    418474        return rc; 
    419475} 
    static int atcmd_prompt(void *data) 
    423479{ 
    424480        struct gsmd *g = data; 
    425481 
    426         g->gfd_uart.when |= GSMD_FD_WRITE; 
     482        g->clear_to_send = 1; 
     483        atcmd_wake_queue(g); 
    427484} 
    428485 
    429486/* callback to be called if [virtual] UART has some data for us */ 
    430 static int atcmd_select_cb(int fd, unsigned int what, void *data) 
     487static int atcmd_newdata_cb(void *opaque, const char data[], int len) 
    431488{ 
    432         int len, rc; 
    433         static char rxbuf[1024]; 
    434         struct gsmd *g = data; 
    435         char *cr; 
    436  
    437         if (what & GSMD_FD_READ) { 
    438                 memset(rxbuf, 0, sizeof(rxbuf)); 
    439                 while ((len = read(fd, rxbuf, sizeof(rxbuf)))) { 
    440                         if (len < 0) { 
    441                                 if (errno == EAGAIN) 
    442                                         return 0; 
    443                                 gsmd_log(GSMD_NOTICE, "ERROR reading from fd %u: %d (%s)\n", fd, len, 
    444                                         strerror(errno)); 
    445                                         return len; 
    446                         } 
    447                         rc = llparse_string(&g->llp, rxbuf, len); 
    448                         if (rc < 0) { 
    449                                 gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc); 
    450                                 return rc; 
    451                         } 
    452                 } 
    453         } 
    454  
    455         /* write pending commands to UART */ 
    456         if ((what & GSMD_FD_WRITE) && g->interpreter_ready) { 
    457                 struct gsmd_atcmd *pos, *pos2; 
    458                 llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) { 
    459                         cr = strchr(pos->cur, '\n'); 
    460                         if (cr) 
    461                                 len = cr - pos->cur; 
    462                         else 
    463                                 len = pos->buflen; 
    464                         rc = write(fd, pos->cur, len); 
    465                         if (rc == 0) { 
    466                                 gsmd_log(GSMD_ERROR, "write returns 0, aborting\n"); 
    467                                 break; 
    468                         } else if (rc < 0) { 
    469                                 gsmd_log(GSMD_ERROR, "error during write to fd %d: %d\n", 
    470                                         fd, rc); 
    471                                 return rc; 
    472                         } 
    473                         if (cr && rc == len) 
    474                                 rc ++;  /* Skip the \n */ 
    475                         pos->buflen -= rc; 
    476                         pos->cur += rc; 
    477                         write(fd, "\r", 1); 
    478  
    479                         if (!pos->buflen) { 
    480                                 /* success: remove from global list of 
    481                                  * to-be-sent atcmds */ 
    482                                 llist_del(&pos->list); 
    483                                 /* append to global list of executing atcmds */ 
    484                                 llist_add_tail(&pos->list, &g->busy_atcmds); 
     489        struct gsmd *g = opaque; 
     490        int rc; 
    485491 
    486                                 /* we only send one cmd at the moment */ 
    487                                 break; 
    488                         } else { 
    489                                 /* The write was short or the atcmd has more 
    490                                  * lines to send after a "> ".  */ 
    491                                 if (rc < len) 
    492                                         return 0; 
    493                                 break; 
    494                         } 
    495                 } 
     492        rc = llparse_string(&g->llp, data, len); 
     493        if (rc < 0) 
     494                gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc); 
    496495 
    497                 /* Either pending_atcmds is empty or a command has to wait */ 
    498                 g->gfd_uart.when &= ~GSMD_FD_WRITE; 
    499         } 
    500  
    501         return 0; 
     496        return rc; 
    502497} 
    503498 
    504  
    505499struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, 
    506500                              atcmd_cb_t cb, void *ctx, u_int16_t id) 
    507501{ 
    int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd) 
    534528{ 
    535529        DEBUGP("submitting command `%s'\n", cmd->buf); 
    536530 
    537         if (llist_empty(&g->pending_atcmds)) 
    538                 g->gfd_uart.when |= GSMD_FD_WRITE; 
     531        llist_empty(&g->pending_atcmds); 
    539532        llist_add_tail(&cmd->list, &g->pending_atcmds); 
     533        atcmd_wake_queue(g); 
    540534 
    541535        return 0; 
    542536} 
    543537 
    544 void atcmd_drain(int fd) 
    545 { 
    546         int rc; 
    547         struct termios t; 
    548         rc = tcflush(fd, TCIOFLUSH); 
    549         rc = tcgetattr(fd, &t); 
    550         DEBUGP("c_iflag = 0x%08x, c_oflag = 0x%08x, c_cflag = 0x%08x, c_lflag = 0x%08x\n", 
    551                 t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); 
    552         t.c_iflag = t.c_oflag = 0; 
    553         cfmakeraw(&t); 
    554         rc = tcsetattr(fd, TCSANOW, &t); 
    555 } 
    556  
    557538/* init atcmd parser */ 
    558 int atcmd_init(struct gsmd *g, int sockfd) 
     539int atcmd_init(struct gsmd *g, struct gsmd_port *port) 
    559540{ 
    560541        __atcmd_ctx = talloc_named_const(gsmd_tallocs, 1, "atcmds"); 
    561542 
    562         g->gfd_uart.fd = sockfd; 
    563         g->gfd_uart.when = GSMD_FD_READ; 
    564         g->gfd_uart.data = g; 
    565         g->gfd_uart.cb = &atcmd_select_cb; 
    566  
    567543        INIT_LLIST_HEAD(&g->pending_atcmds); 
    568544        INIT_LLIST_HEAD(&g->busy_atcmds); 
    569545 
    int atcmd_init(struct gsmd *g, int sockfd) 
    571547 
    572548        g->mlbuf_len = 0; 
    573549        g->mlunsolicited = 0; 
     550        g->clear_to_send = 1; 
    574551 
     552        g->llp.port = port; 
    575553        g->llp.cur = g->llp.buf; 
    576554        g->llp.len = sizeof(g->llp.buf); 
    577555        g->llp.cb = &ml_parse; 
    int atcmd_init(struct gsmd *g, int sockfd) 
    579557        g->llp.ctx = g; 
    580558        g->llp.flags = LGSM_ATCMD_F_EXTENDED; 
    581559 
    582         return gsmd_register_fd(&g->gfd_uart); 
     560        port->newdata_opaque = g; 
     561        port->newdata_cb = atcmd_newdata_cb; 
     562 
     563        return 0; 
    583564} 
  • src/gsmd/gsmd.c

    diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c
    index ab809a6..1f71788 100644
    a b  
    2626#include <string.h> 
    2727#include <errno.h> 
    2828#include <fcntl.h> 
    29 #include <termios.h> 
    3029#include <signal.h> 
    3130 
    3231#define _GNU_SOURCE 
    int gsmd_initsettings(struct gsmd *gsmd) 
    248247        return atcmd_submit(gsmd, cmd); 
    249248} 
    250249 
    251 struct bdrt { 
    252         int bps; 
    253         u_int32_t b; 
    254 }; 
    255  
    256 static struct bdrt bdrts[] = { 
    257         { 0, B0 }, 
    258         { 9600, B9600 }, 
    259         { 19200, B19200 }, 
    260         { 38400, B38400 }, 
    261         { 57600, B57600 }, 
    262         { 115200, B115200 }, 
    263 }; 
    264  
    265 static int set_baudrate(int fd, int baudrate, int hwflow) 
    266 { 
    267         int i; 
    268         u_int32_t bd = 0; 
    269         struct termios ti; 
    270  
    271         for (i = 0; i < ARRAY_SIZE(bdrts); i++) { 
    272                 if (bdrts[i].bps == baudrate) 
    273                         bd = bdrts[i].b; 
    274         } 
    275         if (bd == 0) 
    276                 return -EINVAL; 
    277          
    278         i = tcgetattr(fd, &ti); 
    279         if (i < 0) 
    280                 return i; 
    281          
    282         i = cfsetispeed(&ti, B0); 
    283         if (i < 0) 
    284                 return i; 
    285          
    286         i = cfsetospeed(&ti, bd); 
    287         if (i < 0) 
    288                 return i; 
    289          
    290         if (hwflow) 
    291                 ti.c_cflag |= CRTSCTS; 
    292         else 
    293                 ti.c_cflag &= ~CRTSCTS; 
    294  
    295         return tcsetattr(fd, 0, &ti); 
    296 } 
    297  
    298250static int gsmd_initialize(struct gsmd *g) 
    299251{ 
    300252        INIT_LLIST_HEAD(&g->users); 
    int main(int argc, char **argv) 
    457409                exit(1); 
    458410        } 
    459411 
    460         if (atcmd_init(&g, fd) < 0) { 
     412        if (uart_init(&g.uart.port, fd) < 0) { 
    461413                fprintf(stderr, "can't initialize UART device\n"); 
    462414                exit(1); 
    463415        } 
    464         atcmd_drain(fd); 
     416 
     417        if (atcmd_init(&g, &g.uart.port) < 0) { 
     418                fprintf(stderr, "can't initialize AT parser\n"); 
     419                exit(1); 
     420        } 
     421        uart_drain(fd); 
    465422 
    466423        if (usock_init(&g) < 0) { 
    467424                fprintf(stderr, "can't open unix socket\n"); 
  • new file src/gsmd/uart.c

    diff --git a/src/gsmd/uart.c b/src/gsmd/uart.c
    new file mode 100644
    index 0000000..207e63d
    - +  
     1/* Wrapper for the physical UART in a struct gsmd_port abstraction. 
     2 * 
     3 * Copyright (C) 2007 OpenMoko, Inc. 
     4 * Written by Andrzej Zaborowski <andrew@openedhand.com> 
     5 * 
     6 * This program is free software; you can redistribute it and/or 
     7 * modify it under the terms of the GNU General Public License as 
     8 * published by the Free Software Foundation; either version 2 of 
     9 * the License, or (at your option) any later version. 
     10 * 
     11 * This program is distributed in the hope that it will be useful, 
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     14 * GNU General Public License for more details. 
     15 * 
     16 * You should have received a copy of the GNU General Public License 
     17 * along with this program; if not, write to the Free Software 
     18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
     19 * MA 02111-1307 USA 
     20 */ 
     21 
     22#include <string.h> 
     23#include <fcntl.h> 
     24#include <termios.h> 
     25#include <unistd.h> 
     26#include <errno.h> 
     27 
     28#include "gsmd.h" 
     29 
     30#include <gsmd/gsmd.h> 
     31 
     32void uart_drain(int fd) 
     33{ 
     34        int rc; 
     35        struct termios t; 
     36        rc = tcflush(fd, TCIOFLUSH); 
     37        rc = tcgetattr(fd, &t); 
     38        DEBUGP("c_iflag = 0x%08x, c_oflag = 0x%08x, c_cflag = 0x%08x, c_lflag = 0x%08x\n", 
     39                t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); 
     40        t.c_iflag = t.c_oflag = 0; 
     41        cfmakeraw(&t); 
     42        rc = tcsetattr(fd, TCSANOW, &t); 
     43} 
     44 
     45struct bdrt { 
     46        int bps; 
     47        u_int32_t b; 
     48}; 
     49 
     50static struct bdrt bdrts[] = { 
     51        { 0, B0 }, 
     52        { 9600, B9600 }, 
     53        { 19200, B19200 }, 
     54        { 38400, B38400 }, 
     55        { 57600, B57600 }, 
     56        { 115200, B115200 }, 
     57}; 
     58 
     59int set_baudrate(int fd, int baudrate, int hwflow) 
     60{ 
     61        int i; 
     62        u_int32_t bd = 0; 
     63        struct termios ti; 
     64 
     65        for (i = 0; i < ARRAY_SIZE(bdrts); i++) { 
     66                if (bdrts[i].bps == baudrate) 
     67                        bd = bdrts[i].b; 
     68        } 
     69        if (bd == 0) 
     70                return -EINVAL; 
     71         
     72        i = tcgetattr(fd, &ti); 
     73        if (i < 0) 
     74                return i; 
     75         
     76        i = cfsetispeed(&ti, B0); 
     77        if (i < 0) 
     78                return i; 
     79         
     80        i = cfsetospeed(&ti, bd); 
     81        if (i < 0) 
     82                return i; 
     83         
     84        if (hwflow) 
     85                ti.c_cflag |= CRTSCTS; 
     86        else 
     87                ti.c_cflag &= ~CRTSCTS; 
     88 
     89        return tcsetattr(fd, 0, &ti); 
     90} 
     91 
     92static int uart_select_cb(int fd, unsigned int what, void *data) 
     93{ 
     94        struct gsmd_uart *uart = (struct gsmd_uart *) data; 
     95        static char rxbuf[2048]; 
     96        int rc, len; 
     97 
     98        if ((what & GSMD_FD_READ) && uart->port.newdata_cb) { 
     99                while ((len = read(fd, rxbuf, sizeof(rxbuf)))) { 
     100                        if (len < 0) { 
     101                                if (errno == EAGAIN || errno == EINTR) 
     102                                        return 0; 
     103                                gsmd_log(GSMD_NOTICE, "ERROR reading from " 
     104                                                "fd %u: %d (%s)\n", fd, errno, 
     105                                                strerror(errno)); 
     106                                return -errno; 
     107                        } 
     108 
     109                        rc = uart->port.newdata_cb( 
     110                                        uart->port.newdata_opaque, 
     111                                        rxbuf, 
     112                                        len); 
     113                        if (rc < 0) 
     114                                return rc; 
     115                } 
     116        } 
     117 
     118        /* Write pending data to UART.  */ 
     119        if ((what & GSMD_FD_WRITE) && uart->tx_len) { 
     120                while (uart->tx_start + uart->tx_len >= sizeof(uart->txfifo)) { 
     121                        len = sizeof(uart->txfifo) - uart->tx_start; 
     122                        rc = write(fd, &uart->txfifo[uart->tx_start], len); 
     123                        if (rc < 0 && errno != EINTR) { 
     124                                if (errno == EAGAIN) 
     125                                        return 0; 
     126                                gsmd_log(GSMD_NOTICE, "ERROR writing " 
     127                                                "fd %u: %d (%s)\n", fd, errno, 
     128                                                strerror(errno)); 
     129                                return -errno; 
     130                        } 
     131 
     132                        if (rc > 0) { 
     133                                uart->tx_start += rc; 
     134                                uart->tx_len -= rc; 
     135                        } 
     136                } 
     137                uart->tx_start &= sizeof(uart->txfifo) - 1; 
     138 
     139                while (uart->tx_len) { 
     140                        rc = write(fd, &uart->txfifo[uart->tx_start], 
     141                                        uart->tx_len); 
     142                        if (rc < 0 && errno != EINTR) { 
     143                                if (errno == EAGAIN) 
     144                                        return 0; 
     145                                gsmd_log(GSMD_NOTICE, "ERROR writing " 
     146                                                "fd %u: %d (%s)\n", fd, errno, 
     147                                                strerror(errno)); 
     148                                return -errno; 
     149                        } 
     150 
     151                        if (rc > 0) { 
     152                                uart->tx_start += rc; 
     153                                uart->tx_len -= rc; 
     154                        } 
     155                } 
     156 
     157                /* If we reached here, there's no more data for the moment.  */ 
     158                uart->gfd.when &= ~GSMD_FD_WRITE; 
     159        } 
     160 
     161        return 0; 
     162} 
     163 
     164static int uart_write(struct gsmd_port *port, const char data[], int len) 
     165{ 
     166        struct gsmd_uart *uart = (struct gsmd_uart *) port; 
     167        int start = (uart->tx_start + uart->tx_len) & 
     168                (sizeof(uart->txfifo) - 1); 
     169        int space = sizeof(uart->txfifo) - start; 
     170 
     171        if (uart->tx_len + len > sizeof(uart->txfifo)) 
     172                len = sizeof(uart->txfifo) - uart->tx_len; 
     173 
     174        if (len) 
     175                uart->gfd.when |= GSMD_FD_WRITE; 
     176 
     177        if (len > space) { 
     178                memcpy(uart->txfifo + start, data, space); 
     179                memcpy(uart->txfifo, data + space, len - space); 
     180        } else 
     181                memcpy(uart->txfifo + start, data, len); 
     182 
     183        uart->tx_len += len; 
     184        return len; 
     185} 
     186 
     187int uart_init(struct gsmd_uart *uart, int sockfd) 
     188{ 
     189        uart->gfd.fd = sockfd; 
     190        uart->gfd.when = GSMD_FD_READ; 
     191        uart->gfd.data = uart; 
     192        uart->gfd.cb = &uart_select_cb; 
     193 
     194        uart->port.write = uart_write; 
     195 
     196        return gsmd_register_fd(&uart->gfd); 
     197}