summaryrefslogtreecommitdiffstats
path: root/meta/recipes-connectivity/gsm/files/0001-Introduce-ports.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-connectivity/gsm/files/0001-Introduce-ports.patch')
-rw-r--r--meta/recipes-connectivity/gsm/files/0001-Introduce-ports.patch712
1 files changed, 0 insertions, 712 deletions
diff --git a/meta/recipes-connectivity/gsm/files/0001-Introduce-ports.patch b/meta/recipes-connectivity/gsm/files/0001-Introduce-ports.patch
deleted file mode 100644
index 2a954d6d8b..0000000000
--- a/meta/recipes-connectivity/gsm/files/0001-Introduce-ports.patch
+++ /dev/null
@@ -1,712 +0,0 @@
1Upstream-Status: Inappropriate [not used]
2
3From 516d67c679101d1503dbd4c0613bcd6ff1b604e4 Mon Sep 17 00:00:00 2001
4From: Andrzej Zaborowski <balrog@zabor.org>
5Date: Wed, 19 Sep 2007 14:03:28 +0200
6Subject: [PATCH] Introduce ports.
7
8---
9 include/gsmd/atcmd.h | 2 +-
10 include/gsmd/gsmd.h | 7 +-
11 include/gsmd/uart.h | 28 ++++++
12 include/gsmd/vendorplugin.h | 4 +-
13 src/gsmd/Makefile.am | 2 +-
14 src/gsmd/atcmd.c | 177 +++++++++++++++++---------------------
15 src/gsmd/gsmd.c | 64 ++------------
16 src/gsmd/uart.c | 202 +++++++++++++++++++++++++++++++++++++++++++
17 8 files changed, 328 insertions(+), 158 deletions(-)
18 create mode 100644 include/gsmd/uart.h
19 create mode 100644 src/gsmd/uart.c
20
21diff --git a/include/gsmd/atcmd.h b/include/gsmd/atcmd.h
22index 0d6c62a..a1af6a0 100644
23--- a/include/gsmd/atcmd.h
24+++ b/include/gsmd/atcmd.h
25@@ -9,7 +9,7 @@ typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp);
26
27 extern struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id);
28 extern int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd);
29-extern int atcmd_init(struct gsmd *g, int sockfd);
30+extern int atcmd_init(struct gsmd *g, struct gsmd_port *port);
31 extern void atcmd_drain(int fd);
32
33 #endif /* __GSMD__ */
34diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h
35index ed334f1..4afdf66 100644
36--- a/include/gsmd/gsmd.h
37+++ b/include/gsmd/gsmd.h
38@@ -10,6 +10,7 @@
39 #include <gsmd/machineplugin.h>
40 #include <gsmd/vendorplugin.h>
41 #include <gsmd/select.h>
42+#include <gsmd/uart.h>
43 #include <gsmd/state.h>
44
45 void *gsmd_tallocs;
46@@ -52,6 +53,7 @@ enum llparse_state {
47 #define MLPARSE_BUF_SIZE 65535
48
49 struct llparser {
50+ struct gsmd_port *port;
51 enum llparse_state state;
52 unsigned int len;
53 unsigned int flags;
54@@ -70,7 +72,7 @@ struct gsmd;
55 struct gsmd {
56 unsigned int flags;
57 int interpreter_ready;
58- struct gsmd_fd gfd_uart;
59+ struct gsmd_uart uart;
60 struct gsmd_fd gfd_sock;
61 struct llparser llp;
62 struct llist_head users;
63@@ -81,9 +83,10 @@ struct gsmd {
64 struct gsmd_device_state dev_state;
65
66 struct llist_head operators; /* cached list of operator names */
67- unsigned char *mlbuf; /* ml_parse buffer */
68+ char *mlbuf; /* ml_parse buffer */
69 unsigned int mlbuf_len;
70 int mlunsolicited;
71+ int clear_to_send;
72 };
73
74 struct gsmd_user {
75diff --git a/include/gsmd/uart.h b/include/gsmd/uart.h
76new file mode 100644
77index 0000000..a006fa7
78--- /dev/null
79+++ b/include/gsmd/uart.h
80@@ -0,0 +1,28 @@
81+#ifndef __GSMD_UART_H
82+#define __GSMD_UART_H
83+
84+#ifdef __GSMD__
85+
86+struct gsmd_port {
87+ int (*write)(struct gsmd_port *port, const char data[], int len);
88+ int (*set_break)(struct gsmd_port *port, int state);
89+ /* more parameters here */
90+ int (*newdata_cb)(void *opaque, const char data[], int len);
91+ void *newdata_opaque;
92+};
93+
94+struct gsmd_uart {
95+ struct gsmd_port port;
96+ struct gsmd_fd gfd;
97+ char txfifo[2048];
98+ int tx_start;
99+ int tx_len;
100+};
101+
102+extern int set_baudrate(int fd, int baudrate, int hwflow);
103+extern void uart_drain(int fd);
104+extern int uart_init(struct gsmd_uart *uart, int sockfd);
105+
106+#endif /* __GSMD__ */
107+
108+#endif
109diff --git a/include/gsmd/vendorplugin.h b/include/gsmd/vendorplugin.h
110index 1911fef..1c82790 100644
111--- a/include/gsmd/vendorplugin.h
112+++ b/include/gsmd/vendorplugin.h
113@@ -11,8 +11,8 @@ struct gsmd_unsolicit;
114
115 struct gsmd_vendor_plugin {
116 struct llist_head list;
117- unsigned char *name;
118- unsigned char *ext_chars;
119+ char *name;
120+ char *ext_chars;
121 unsigned int num_unsolicit;
122 const struct gsmd_unsolicit *unsolicit;
123 int (*detect)(struct gsmd *g);
124diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am
125index 9ac45ee..110b757 100644
126--- a/src/gsmd/Makefile.am
127+++ b/src/gsmd/Makefile.am
128@@ -13,7 +13,7 @@ sbin_PROGRAMS = gsmd
129 gsmd_CFLAGS = -D PLUGINDIR=\"$(plugindir)\"
130 gsmd_SOURCES = gsmd.c atcmd.c select.c machine.c vendor.c unsolicited.c log.c \
131 usock.c talloc.c timer.c operator_cache.c ext_response.c \
132- sms_cb.c sms_pdu.c
133+ sms_cb.c sms_pdu.c uart.c
134 gsmd_LDADD = -ldl
135 gsmd_LDFLAGS = -Wl,--export-dynamic
136
137diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c
138index 2ef6a10..27dfa41 100644
139--- a/src/gsmd/atcmd.c
140+++ b/src/gsmd/atcmd.c
141@@ -159,7 +159,8 @@ static int llparse_byte(struct llparser *llp, char byte)
142 return ret;
143 }
144
145-static int llparse_string(struct llparser *llp, char *buf, unsigned int len)
146+static int llparse_string(struct llparser *llp, const char *buf,
147+ unsigned int len)
148 {
149 while (len--) {
150 int rc = llparse_byte(llp, *(buf++));
151@@ -187,6 +188,55 @@ static int llparse_init(struct llparser *llp)
152 return 0;
153 }
154
155+/* See if we can now send more commands to the port */
156+static void atcmd_wake_queue(struct gsmd *g)
157+{
158+ int len, rc;
159+ char *cr;
160+
161+ /* write pending commands to UART */
162+ while (g->interpreter_ready && g->clear_to_send) {
163+ struct gsmd_atcmd *pos, *pos2;
164+ llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) {
165+ cr = strchr(pos->cur, '\n');
166+ if (cr)
167+ len = cr - pos->cur;
168+ else
169+ len = pos->buflen;
170+ rc = g->llp.port->write(g->llp.port, pos->cur, len);
171+ if (rc == 0) {
172+ gsmd_log(GSMD_ERROR,
173+ "write returns 0, aborting\n");
174+ break;
175+ }
176+ if (cr && rc == len)
177+ rc ++; /* Skip the \n */
178+ pos->buflen -= rc;
179+ pos->cur += rc;
180+ g->llp.port->write(g->llp.port, "\r", 1);
181+
182+ if (!pos->buflen) {
183+ /* success: remove from global list of
184+ * to-be-sent atcmds */
185+ llist_del(&pos->list);
186+ /* append to global list of executing atcmds */
187+ llist_add_tail(&pos->list, &g->busy_atcmds);
188+
189+ /* we only send one cmd at the moment */
190+ g->clear_to_send = 0;
191+ break;
192+ } else {
193+ /* The write was short or the atcmd has more
194+ * lines to send after a "> ". */
195+ if (rc < len)
196+ break;
197+ g->clear_to_send = 0;
198+ break;
199+ }
200+ }
201+ }
202+}
203+
204 /* mid-level parser */
205
206 static int parse_final_result(const char *res)
207@@ -216,6 +266,7 @@ static int ml_parse(const char *buf, int len, void *ctx)
208 g->interpreter_ready = 1;
209 gsmd_initsettings(g);
210 gmsd_alive_start(g);
211+ atcmd_wake_queue(g);
212 return 0;
213 }
214
215@@ -316,6 +367,7 @@ static int ml_parse(const char *buf, int len, void *ctx)
216 } else {
217 DEBUGP("Calling cmd->cb()\n");
218 cmd->resp = g->mlbuf;
219+ g->mlbuf[g->mlbuf_len] = 0;
220 rc = cmd->cb(cmd, cmd->ctx, cmd->resp);
221 DEBUGP("Clearing mlbuf\n");
222 }
223@@ -370,12 +422,15 @@ static int ml_parse(const char *buf, int len, void *ctx)
224 if (g->mlbuf_len)
225 g->mlbuf[g->mlbuf_len ++] = '\n';
226 DEBUGP("Appending buf to mlbuf\n");
227- if (len > MLPARSE_BUF_SIZE - g->mlbuf_len)
228+ if (len > MLPARSE_BUF_SIZE - g->mlbuf_len) {
229 len = MLPARSE_BUF_SIZE - g->mlbuf_len;
230+ gsmd_log(GSMD_NOTICE, "g->mlbuf overrun\n");
231+ }
232 memcpy(g->mlbuf + g->mlbuf_len, buf, len);
233 g->mlbuf_len += len;
234
235 if (g->mlunsolicited) {
236+ g->mlbuf[g->mlbuf_len] = 0;
237 rc = unsolicited_parse(g, g->mlbuf, g->mlbuf_len,
238 strchr(g->mlbuf, ':') + 1);
239 if (rc == -EAGAIN) {
240@@ -422,8 +477,11 @@ final_cb:
241
242 /* if we're finished with current commands, but still have pending
243 * commands: we want to WRITE again */
244- if (llist_empty(&g->busy_atcmds) && !llist_empty(&g->pending_atcmds))
245- g->gfd_uart.when |= GSMD_FD_WRITE;
246+ if (llist_empty(&g->busy_atcmds)) {
247+ g->clear_to_send = 1;
248+ if (!llist_empty(&g->pending_atcmds))
249+ atcmd_wake_queue(g);
250+ }
251
252 return rc;
253 }
254@@ -433,85 +491,23 @@ static int atcmd_prompt(void *data)
255 {
256 struct gsmd *g = data;
257
258- g->gfd_uart.when |= GSMD_FD_WRITE;
259+ g->clear_to_send = 1;
260+ atcmd_wake_queue(g);
261 }
262
263 /* callback to be called if [virtual] UART has some data for us */
264-static int atcmd_select_cb(int fd, unsigned int what, void *data)
265+static int atcmd_newdata_cb(void *opaque, const char data[], int len)
266 {
267- int len, rc;
268- static char rxbuf[1024];
269- struct gsmd *g = data;
270- char *cr;
271-
272- if (what & GSMD_FD_READ) {
273- memset(rxbuf, 0, sizeof(rxbuf));
274- while ((len = read(fd, rxbuf, sizeof(rxbuf)))) {
275- if (len < 0) {
276- if (errno == EAGAIN)
277- return 0;
278- gsmd_log(GSMD_NOTICE, "ERROR reading from fd %u: %d (%s)\n", fd, len,
279- strerror(errno));
280- return len;
281- }
282- rc = llparse_string(&g->llp, rxbuf, len);
283- if (rc < 0) {
284- gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc);
285- return rc;
286- }
287- }
288- }
289-
290- /* write pending commands to UART */
291- if ((what & GSMD_FD_WRITE) && g->interpreter_ready) {
292- struct gsmd_atcmd *pos, *pos2;
293- llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) {
294- cr = strchr(pos->cur, '\n');
295- if (cr)
296- len = cr - pos->cur;
297- else
298- len = pos->buflen - 1; /* assuming zero-terminated strings */
299- rc = write(fd, pos->cur, len);
300- if (rc == 0) {
301- gsmd_log(GSMD_ERROR, "write returns 0, aborting\n");
302- break;
303- } else if (rc < 0) {
304- gsmd_log(GSMD_ERROR, "error during write to fd %d: %d\n",
305- fd, rc);
306- return rc;
307- }
308- if (!cr || rc == len)
309- rc ++; /* Skip the \n or \0 */
310- pos->buflen -= rc;
311- pos->cur += rc;
312- write(fd, "\r", 1);
313-
314- if (!pos->buflen) {
315- /* success: remove from global list of
316- * to-be-sent atcmds */
317- llist_del(&pos->list);
318- /* append to global list of executing atcmds */
319- llist_add_tail(&pos->list, &g->busy_atcmds);
320-
321- /* we only send one cmd at the moment */
322- break;
323- } else {
324- /* The write was short or the atcmd has more
325- * lines to send after a "> ". */
326- if (rc < len)
327- return 0;
328- break;
329- }
330- }
331+ struct gsmd *g = opaque;
332+ int rc;
333
334- /* Either pending_atcmds is empty or a command has to wait */
335- g->gfd_uart.when &= ~GSMD_FD_WRITE;
336- }
337+ rc = llparse_string(&g->llp, data, len);
338+ if (rc < 0)
339+ gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc);
340
341- return 0;
342+ return rc;
343 }
344
345-
346 struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen,
347 atcmd_cb_t cb, void *ctx, u_int16_t id)
348 {
349@@ -544,36 +540,18 @@ int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd)
350 {
351 DEBUGP("submitting command `%s'\n", cmd->buf);
352
353- if (llist_empty(&g->pending_atcmds))
354- g->gfd_uart.when |= GSMD_FD_WRITE;
355+ llist_empty(&g->pending_atcmds);
356 llist_add_tail(&cmd->list, &g->pending_atcmds);
357+ atcmd_wake_queue(g);
358
359 return 0;
360 }
361
362-void atcmd_drain(int fd)
363-{
364- int rc;
365- struct termios t;
366- rc = tcflush(fd, TCIOFLUSH);
367- rc = tcgetattr(fd, &t);
368- DEBUGP("c_iflag = 0x%08x, c_oflag = 0x%08x, c_cflag = 0x%08x, c_lflag = 0x%08x\n",
369- t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
370- t.c_iflag = t.c_oflag = 0;
371- cfmakeraw(&t);
372- rc = tcsetattr(fd, TCSANOW, &t);
373-}
374-
375 /* init atcmd parser */
376-int atcmd_init(struct gsmd *g, int sockfd)
377+int atcmd_init(struct gsmd *g, struct gsmd_port *port)
378 {
379 __atcmd_ctx = talloc_named_const(gsmd_tallocs, 1, "atcmds");
380
381- g->gfd_uart.fd = sockfd;
382- g->gfd_uart.when = GSMD_FD_READ;
383- g->gfd_uart.data = g;
384- g->gfd_uart.cb = &atcmd_select_cb;
385-
386 INIT_LLIST_HEAD(&g->pending_atcmds);
387 INIT_LLIST_HEAD(&g->busy_atcmds);
388
389@@ -581,7 +559,9 @@ int atcmd_init(struct gsmd *g, int sockfd)
390
391 g->mlbuf_len = 0;
392 g->mlunsolicited = 0;
393+ g->clear_to_send = 1;
394
395+ g->llp.port = port;
396 g->llp.cur = g->llp.buf;
397 g->llp.len = sizeof(g->llp.buf);
398 g->llp.cb = &ml_parse;
399@@ -589,5 +569,8 @@ int atcmd_init(struct gsmd *g, int sockfd)
400 g->llp.ctx = g;
401 g->llp.flags = LGSM_ATCMD_F_EXTENDED;
402
403- return gsmd_register_fd(&g->gfd_uart);
404+ port->newdata_opaque = g;
405+ port->newdata_cb = atcmd_newdata_cb;
406+
407+ return 0;
408 }
409diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c
410index 51b4f2c..846bd17 100644
411--- a/src/gsmd/gsmd.c
412+++ b/src/gsmd/gsmd.c
413@@ -26,7 +26,6 @@
414 #include <string.h>
415 #include <errno.h>
416 #include <fcntl.h>
417-#include <termios.h>
418 #include <signal.h>
419
420 #define _GNU_SOURCE
421@@ -247,56 +246,6 @@ int gsmd_initsettings(struct gsmd *gsmd)
422 return atcmd_submit(gsmd, cmd);
423 }
424
425-struct bdrt {
426- int bps;
427- u_int32_t b;
428-};
429-
430-static struct bdrt bdrts[] = {
431- { 0, B0 },
432- { 9600, B9600 },
433- { 19200, B19200 },
434- { 38400, B38400 },
435- { 57600, B57600 },
436- { 115200, B115200 },
437- { 230400, B230400 },
438- { 460800, B460800 },
439- { 921600, B921600 },
440-};
441-
442-static int set_baudrate(int fd, int baudrate, int hwflow)
443-{
444- int i;
445- u_int32_t bd = 0;
446- struct termios ti;
447-
448- for (i = 0; i < ARRAY_SIZE(bdrts); i++) {
449- if (bdrts[i].bps == baudrate)
450- bd = bdrts[i].b;
451- }
452- if (bd == 0)
453- return -EINVAL;
454-
455- i = tcgetattr(fd, &ti);
456- if (i < 0)
457- return i;
458-
459- i = cfsetispeed(&ti, B0);
460- if (i < 0)
461- return i;
462-
463- i = cfsetospeed(&ti, bd);
464- if (i < 0)
465- return i;
466-
467- if (hwflow)
468- ti.c_cflag |= CRTSCTS;
469- else
470- ti.c_cflag &= ~CRTSCTS;
471-
472- return tcsetattr(fd, 0, &ti);
473-}
474-
475 static int gsmd_initialize(struct gsmd *g)
476 {
477 INIT_LLIST_HEAD(&g->users);
478@@ -478,14 +427,19 @@ int main(int argc, char **argv)
479 if (wait >= 0)
480 g.interpreter_ready = !wait;
481
482- if (atcmd_init(&g, fd) < 0) {
483+ if (uart_init(&g.uart, fd) < 0) {
484 fprintf(stderr, "can't initialize UART device\n");
485 exit(1);
486 }
487
488- write(fd, "\r", 1);
489- sleep(1);
490- atcmd_drain(fd);
491+ if (atcmd_init(&g, &g.uart.port) < 0) {
492+ fprintf(stderr, "can't initialize AT parser\n");
493+ exit(1);
494+ }
495+ write(fd, "\r", 1);
496+ sleep(1);
497+
498+ uart_drain(fd);
499
500 if (usock_init(&g) < 0) {
501 fprintf(stderr, "can't open unix socket\n");
502diff --git a/src/gsmd/uart.c b/src/gsmd/uart.c
503new file mode 100644
504index 0000000..22a4a5c
505--- /dev/null
506+++ b/src/gsmd/uart.c
507@@ -0,0 +1,202 @@
508+/* Wrapper for the physical UART in a struct gsmd_port abstraction.
509+ *
510+ * Copyright (C) 2007 OpenMoko, Inc.
511+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
512+ *
513+ * This program is free software; you can redistribute it and/or
514+ * modify it under the terms of the GNU General Public License as
515+ * published by the Free Software Foundation; either version 2 of
516+ * the License, or (at your option) any later version.
517+ *
518+ * This program is distributed in the hope that it will be useful,
519+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
520+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
521+ * GNU General Public License for more details.
522+ *
523+ * You should have received a copy of the GNU General Public License
524+ * along with this program; if not, write to the Free Software
525+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
526+ * MA 02111-1307 USA
527+ */
528+
529+#include <string.h>
530+#include <fcntl.h>
531+#include <termios.h>
532+#include <unistd.h>
533+#include <errno.h>
534+
535+#include "gsmd.h"
536+
537+#include <gsmd/gsmd.h>
538+
539+void uart_drain(int fd)
540+{
541+ int rc;
542+ struct termios t;
543+ rc = tcflush(fd, TCIOFLUSH);
544+ rc = tcgetattr(fd, &t);
545+ DEBUGP(
546+ "c_iflag = 0x%08x, c_oflag = 0x%08x, "
547+ "c_cflag = 0x%08x, c_lflag = 0x%08x\n",
548+ t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
549+ t.c_iflag = t.c_oflag = 0;
550+ cfmakeraw(&t);
551+ rc = tcsetattr(fd, TCSANOW, &t);
552+}
553+
554+struct bdrt {
555+ int bps;
556+ u_int32_t b;
557+};
558+
559+static struct bdrt bdrts[] = {
560+ { 0, B0 },
561+ { 9600, B9600 },
562+ { 19200, B19200 },
563+ { 38400, B38400 },
564+ { 57600, B57600 },
565+ { 115200, B115200 },
566+ { 230400, B230400 },
567+ { 460800, B460800 },
568+ { 921600, B921600 },
569+};
570+
571+int set_baudrate(int fd, int baudrate, int hwflow)
572+{
573+ int i;
574+ u_int32_t bd = 0;
575+ struct termios ti;
576+
577+ for (i = 0; i < ARRAY_SIZE(bdrts); i++) {
578+ if (bdrts[i].bps == baudrate)
579+ bd = bdrts[i].b;
580+ }
581+ if (bd == 0)
582+ return -EINVAL;
583+
584+ i = tcgetattr(fd, &ti);
585+ if (i < 0)
586+ return i;
587+
588+ i = cfsetispeed(&ti, B0);
589+ if (i < 0)
590+ return i;
591+
592+ i = cfsetospeed(&ti, bd);
593+ if (i < 0)
594+ return i;
595+
596+ if (hwflow)
597+ ti.c_cflag |= CRTSCTS;
598+ else
599+ ti.c_cflag &= ~CRTSCTS;
600+
601+ return tcsetattr(fd, 0, &ti);
602+}
603+
604+static int uart_select_cb(int fd, unsigned int what, void *data)
605+{
606+ struct gsmd_uart *uart = (struct gsmd_uart *) data;
607+ static char rxbuf[2048];
608+ int rc, len;
609+
610+ if ((what & GSMD_FD_READ) && uart->port.newdata_cb) {
611+ while ((len = read(fd, rxbuf, sizeof(rxbuf)))) {
612+ if (len < 0) {
613+ if (errno == EAGAIN || errno == EINTR)
614+ return 0;
615+ gsmd_log(GSMD_NOTICE, "ERROR reading from "
616+ "fd %u: %d (%s)\n", fd, errno,
617+ strerror(errno));
618+ return -errno;
619+ }
620+
621+ rc = uart->port.newdata_cb(
622+ uart->port.newdata_opaque,
623+ rxbuf,
624+ len);
625+ if (rc < 0)
626+ return rc;
627+ }
628+ }
629+
630+ /* Write pending data to UART. */
631+ if ((what & GSMD_FD_WRITE) && uart->tx_len) {
632+ while (uart->tx_start + uart->tx_len >= sizeof(uart->txfifo)) {
633+ len = sizeof(uart->txfifo) - uart->tx_start;
634+ rc = write(fd, &uart->txfifo[uart->tx_start], len);
635+ if (rc < 0 && errno != EINTR) {
636+ if (errno == EAGAIN)
637+ return 0;
638+ gsmd_log(GSMD_NOTICE, "ERROR writing "
639+ "fd %u: %d (%s)\n", fd, errno,
640+ strerror(errno));
641+ return -errno;
642+ }
643+
644+ if (rc > 0) {
645+ uart->tx_start += rc;
646+ uart->tx_len -= rc;
647+ }
648+ }
649+ uart->tx_start &= sizeof(uart->txfifo) - 1;
650+
651+ while (uart->tx_len) {
652+ rc = write(fd, &uart->txfifo[uart->tx_start],
653+ uart->tx_len);
654+ if (rc < 0 && errno != EINTR) {
655+ if (errno == EAGAIN)
656+ return 0;
657+ gsmd_log(GSMD_NOTICE, "ERROR writing "
658+ "fd %u: %d (%s)\n", fd, errno,
659+ strerror(errno));
660+ return -errno;
661+ }
662+
663+ if (rc > 0) {
664+ uart->tx_start += rc;
665+ uart->tx_len -= rc;
666+ }
667+ }
668+
669+ /* If we reached here, there's no more data for the moment. */
670+ uart->gfd.when &= ~GSMD_FD_WRITE;
671+ }
672+
673+ return 0;
674+}
675+
676+static int uart_write(struct gsmd_port *port, const char data[], int len)
677+{
678+ struct gsmd_uart *uart = (struct gsmd_uart *) port;
679+ int start = (uart->tx_start + uart->tx_len) &
680+ (sizeof(uart->txfifo) - 1);
681+ int space = sizeof(uart->txfifo) - start;
682+
683+ if (uart->tx_len + len > sizeof(uart->txfifo))
684+ len = sizeof(uart->txfifo) - uart->tx_len;
685+
686+ if (len)
687+ uart->gfd.when |= GSMD_FD_WRITE;
688+
689+ if (len > space) {
690+ memcpy(uart->txfifo + start, data, space);
691+ memcpy(uart->txfifo, data + space, len - space);
692+ } else
693+ memcpy(uart->txfifo + start, data, len);
694+
695+ uart->tx_len += len;
696+ return len;
697+}
698+
699+int uart_init(struct gsmd_uart *uart, int sockfd)
700+{
701+ uart->gfd.fd = sockfd;
702+ uart->gfd.when = GSMD_FD_READ;
703+ uart->gfd.data = uart;
704+ uart->gfd.cb = &uart_select_cb;
705+
706+ uart->port.write = uart_write;
707+
708+ return gsmd_register_fd(&uart->gfd);
709+}
710--
7111.5.2.1
712