Add glibc support(default)
Change-Id: I7675edcf14df8707ecd424a962e4cc464a4c6ae4
diff --git a/mbtk/aboot-tiny/jacana/jacana_serialport_posix.c b/mbtk/aboot-tiny/jacana/jacana_serialport_posix.c
new file mode 100755
index 0000000..c5c10bb
--- /dev/null
+++ b/mbtk/aboot-tiny/jacana/jacana_serialport_posix.c
@@ -0,0 +1,526 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <termios.h>
+#include <assert.h>
+#include "aboot-tiny.h"
+#include "jacana_serialport.h"
+#include <time.h>
+#include "jacana_usleep.h"
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+#ifndef SERIAL_RX_BUF_SIZE
+#define SERIAL_RX_BUF_SIZE (1024)
+#endif
+
+typedef enum {
+ SERIALPORT_PARITY_NONE = 1,
+ SERIALPORT_PARITY_MARK = 2,
+ SERIALPORT_PARITY_EVEN = 3,
+ SERIALPORT_PARITY_ODD = 4,
+ SERIALPORT_PARITY_SPACE = 5
+} serialport_parity_t;
+
+typedef enum {
+ SERIALPORT_STOPBITS_ONE = 1,
+ SERIALPORT_STOPBITS_ONE_FIVE = 2,
+ SERIALPORT_STOPBITS_TWO = 3
+} serialport_stop_bits_t;
+
+typedef struct {
+ int baud;
+ int data_bits;
+ bool rtscts;
+ bool xon;
+ bool xoff;
+ bool xany;
+ bool dsrdtr;
+ bool hupcl;
+ serialport_parity_t parity;
+ serialport_stop_bits_t stop_bits;
+} serial_port_connect_opt_t;
+/*---------------------------------------------------------------------------*/
+typedef struct serial_tx_memb {
+ struct serial_tx_memb *next;
+ uint8_t *data;
+ int len;
+ int remain;
+} serial_tx_memb_t;
+/*---------------------------------------------------------------------------*/
+static uint8_t rx_buf[SERIAL_RX_BUF_SIZE];
+static aboot_tiny_uart_rx_callback_t rx_cb;
+static int serial_fd = -1;
+static int fd_error;
+/*---------------------------------------------------------------------------*/
+static serial_tx_memb_t *tx_queue_list;
+static serial_tx_memb_t **tx_queue = &tx_queue_list;
+/*---------------------------------------------------------------------------*/
+static inline void
+queue_init(serial_tx_memb_t **queue)
+{
+ *queue = NULL;
+}
+/*---------------------------------------------------------------------------*/
+static inline bool
+queue_is_empty(serial_tx_memb_t **queue)
+{
+ return *queue == NULL ? true : false;
+}
+/*---------------------------------------------------------------------------*/
+static inline serial_tx_memb_t *
+queue_peek(serial_tx_memb_t **queue)
+{
+ return *queue;
+}
+/*---------------------------------------------------------------------------*/
+static inline serial_tx_memb_t *
+queue_dequeue(serial_tx_memb_t **queue)
+{
+ serial_tx_memb_t *l;
+ l = *queue;
+ if(*queue != NULL) {
+ *queue = ((serial_tx_memb_t *)*queue)->next;
+ }
+
+ return l;
+}
+/*---------------------------------------------------------------------------*/
+static inline void
+queue_enqueue(serial_tx_memb_t **queue, serial_tx_memb_t *element)
+{
+ element->next = NULL;
+
+ if(*queue == NULL) {
+ *queue = element;
+ } else {
+ serial_tx_memb_t *l;
+ for(l = *queue; l->next != NULL; l = l->next) {
+ }
+ l->next = element;
+ }
+}
+/*---------------------------------------------------------------------------*/
+static int
+set_fd(fd_set *rset, fd_set *wset)
+{
+ if(serial_fd > 0 && !fd_error) {
+ FD_SET(serial_fd, rset);
+ if(!queue_is_empty(tx_queue)) {
+ FD_SET(serial_fd, wset);
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+static void
+serial_do_tx(void)
+{
+ serial_tx_memb_t *p;
+ int cnt, offset;
+
+ p = queue_peek(tx_queue);
+ if(p) {
+ offset = p->len - p->remain;
+ cnt = write(serial_fd, p->data + offset, p->remain);
+
+#if 0
+ unsigned int ii,j;
+ ii = p->remain;
+ if(ii > 128)
+ {
+ ii = 128;
+ }
+
+ char buff[512];
+ memset(buff, 0, sizeof(buff));
+ for(j=0;j<ii;j++)
+ {
+ sprintf(&buff[j], "%c", *(p->data + offset+j));
+ }
+
+ aboot_tiny_log_printf("Tlen=%d,data=%s", p->remain, buff);
+#endif
+
+ if(cnt > 0) {
+ p->remain -= cnt;
+ if(p->remain == 0) {
+ queue_dequeue(tx_queue);
+ aboot_tiny_mem_free(p->data);
+ aboot_tiny_mem_free(p);
+ }
+ } else if(cnt < 0) {
+ aboot_tiny_log_printf("write error: error code %d\n", errno);
+ fd_error = errno;
+ }
+ }
+}
+/*---------------------------------------------------------------------------*/
+static void
+handle_fd(fd_set *rset, fd_set *wset)
+{
+ int cnt;
+ if(serial_fd >= 0 && !fd_error) {
+ if(FD_ISSET(serial_fd, wset)) {
+ serial_do_tx();
+ if(queue_is_empty(tx_queue)) {
+ FD_CLR(serial_fd, wset);
+ }
+ }
+
+ if(FD_ISSET(serial_fd, rset)) {
+ cnt = read(serial_fd, rx_buf, sizeof(rx_buf));
+#if 0
+ unsigned int ii,j;
+ ii = cnt;
+ if(ii > 64)
+ {
+ ii = 64;
+ }
+
+ char buf[256];
+ memset(buf, 0, sizeof(buf));
+ for(j=0;j<ii;j++)
+ {
+ sprintf(&buf[j], "%c,", rx_buf[j]);
+ }
+
+ aboot_tiny_log_printf("Rlen=%d,data=%s", cnt, buf);
+#endif
+ if((cnt > 0) && rx_cb) {
+ rx_cb(rx_buf, cnt);
+ } else if(cnt < 0) {
+ aboot_tiny_log_printf("read error: error code %d\n", errno);
+ fd_error = errno;
+ }
+ }
+ }
+}
+/*---------------------------------------------------------------------------*/
+static const struct select_callback serial_select_callback = {
+ set_fd,
+ handle_fd,
+};
+/*---------------------------------------------------------------------------*/
+static int
+to_baud_const(int baud)
+{
+ switch(baud) {
+ case 0: return B0;
+ case 50: return B50;
+ case 75: return B75;
+ case 110: return B110;
+ case 134: return B134;
+ case 150: return B150;
+ case 200: return B200;
+ case 300: return B300;
+ case 600: return B600;
+ case 1200: return B1200;
+ case 1800: return B1800;
+ case 2400: return B2400;
+ case 4800: return B4800;
+ case 9600: return B9600;
+ case 19200: return B19200;
+ case 38400: return B38400;
+ case 57600: return B57600;
+ case 115200: return B115200;
+ case 230400: return B230400;
+#if defined(__linux__)
+ case 460800: return B460800;
+ case 500000: return B500000;
+ case 576000: return B576000;
+ case 921600: return B921600;
+ case 1000000: return B1000000;
+ case 1152000: return B1152000;
+ case 1500000: return B1500000;
+ case 2000000: return B2000000;
+ case 2500000: return B2500000;
+ case 3000000: return B3000000;
+ case 3500000: return B3500000;
+ case 4000000: return B4000000;
+#endif
+ }
+ return -1;
+}
+/*---------------------------------------------------------------------------*/
+static int
+to_data_bits_const(int data_bits)
+{
+ switch(data_bits) {
+ case 8: default: return CS8;
+ case 7: return CS7;
+ case 6: return CS6;
+ case 5: return CS5;
+ }
+ return -1;
+}
+/*---------------------------------------------------------------------------*/
+static int
+set_baudrate(int fd, serial_port_connect_opt_t *opt)
+{
+ /* lookup the standard baudrates from the table */
+ int baud_rate = to_baud_const(opt->baud);
+
+ /* get port options */
+ struct termios options;
+
+ if(-1 == tcgetattr(fd, &options)) {
+ aboot_tiny_log_printf("Error: %s setting custom baud rate of %d", strerror(errno), opt->baud);
+ return -1;
+ }
+
+ if(-1 == baud_rate) {
+ aboot_tiny_log_printf("Error baud rate of %d is not supported on your platform", opt->baud);
+ return -1;
+ }
+
+ /* If we have a good baud rate set it and lets go */
+ cfsetospeed(&options, baud_rate);
+ cfsetispeed(&options, baud_rate);
+ /* throw away all the buffered data */
+ tcflush(fd, TCIOFLUSH);
+ /* make the changes now */
+ tcsetattr(fd, TCSANOW, &options);
+
+ return 1;
+}
+
+/*---------------------------------------------------------------------------*/
+static int
+set_default_baudrate(int fd)
+{
+ /* Default BaudRate => 115200. Just for AP UART. */
+ int baud_rate = to_baud_const(115200);
+
+ /* get port options */
+ struct termios options;
+
+ if(-1 == tcgetattr(fd, &options))
+ return -1;
+
+
+ if(-1 == baud_rate)
+ return -1;
+
+ /* If we have a good baud rate set it and lets go */
+ cfsetospeed(&options, baud_rate);
+ cfsetispeed(&options, baud_rate);
+ /* throw away all the buffered data */
+ tcflush(fd, TCIOFLUSH);
+ /* make the changes now */
+ tcsetattr(fd, TCSANOW, &options);
+
+ return 1;
+}
+
+
+/*---------------------------------------------------------------------------*/
+static int
+setup(int fd, serial_port_connect_opt_t *opt)
+{
+ int data_bits = to_data_bits_const(opt->data_bits);
+ if(data_bits == -1) {
+ aboot_tiny_log_printf("Invalid data bits %d\n", opt->data_bits);
+ return -1;
+ }
+ if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ aboot_tiny_log_printf("Set FD_CLOEXEC failed\n");
+ return -1;
+ }
+
+ /* Get port configuration for modification */
+ struct termios options;
+ tcgetattr(fd, &options);
+
+ /* IGNPAR: ignore bytes with parity errors */
+ options.c_iflag = IGNPAR;
+ /* ICRNL: map CR to NL (otherwise a CR input on the other computer will not terminate input) */
+ /* Future potential option */
+ /* options.c_iflag = ICRNL; */
+ /* otherwise make device raw (no other input processing) */
+
+ /* Specify data bits */
+ options.c_cflag &= ~CSIZE;
+ options.c_cflag |= data_bits;
+
+ options.c_cflag &= ~(CRTSCTS);
+
+ if(opt->rtscts) {
+ options.c_cflag |= CRTSCTS;
+ }
+
+ options.c_iflag &= ~(IXON | IXOFF | IXANY);
+
+ if(opt->xon) {
+ options.c_iflag |= IXON;
+ }
+
+ if(opt->xoff) {
+ options.c_iflag |= IXOFF;
+ }
+
+ if(opt->xany) {
+ options.c_iflag |= IXANY;
+ }
+
+ switch(opt->parity) {
+ case SERIALPORT_PARITY_NONE:
+ options.c_cflag &= ~PARENB;
+ break;
+ case SERIALPORT_PARITY_ODD:
+ options.c_cflag |= PARENB;
+ options.c_cflag |= PARODD;
+ break;
+ case SERIALPORT_PARITY_EVEN:
+ options.c_cflag |= PARENB;
+ options.c_cflag &= ~PARODD;
+ break;
+ default:
+ aboot_tiny_log_printf("Invalid parity setting %d", opt->parity);
+ return -1;
+ }
+
+ switch(opt->stop_bits) {
+ case SERIALPORT_STOPBITS_ONE:
+ options.c_cflag &= ~CSTOPB;
+ break;
+ case SERIALPORT_STOPBITS_TWO:
+ options.c_cflag |= CSTOPB;
+ break;
+ default:
+ aboot_tiny_log_printf("Invalid stop bits setting %d", opt->stop_bits);
+ return -1;
+ }
+
+
+ options.c_cflag |= CLOCAL; /* ignore status lines */
+ options.c_cflag |= CREAD; /* enable receiver */
+ options.c_oflag = 0;
+ /* ICANON makes partial lines not readable. It should be optional. */
+ /* It works with ICRNL. */
+ options.c_lflag = 0; /* ICANON; */
+ options.c_cc[VMIN] = 0;
+ options.c_cc[VTIME] = 0;
+
+ tcsetattr(fd, TCSANOW, &options);
+
+
+ if(set_baudrate(fd, opt) == -1) {
+ return -1;
+ }
+
+ return 1;
+}
+/*---------------------------------------------------------------------------*/
+static int
+serial_port_open(const char *dev, serial_port_connect_opt_t *opt)
+{
+ assert(serial_fd == -1); /* previously port has not been closed */
+ serial_fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC | O_SYNC);
+ if(serial_fd < 0) {
+ return -1;
+ }
+ if(setup(serial_fd, opt) < 0) {
+ return -1;
+ }
+ rx_cb = NULL;
+ fd_error = 0;
+ aboot_tiny_log_printf("serial fd=%d rate=%d", serial_fd, opt->baud);
+ aboot_tiny_select_set_callback(serial_fd, &serial_select_callback);
+ queue_init(tx_queue);
+
+ return 0;
+}
+static void
+serial_port_close(void)
+{
+ serial_tx_memb_t *p;
+
+ if(serial_fd >= 0) {
+ aboot_tiny_select_set_callback(serial_fd, NULL);
+ rx_cb = NULL;
+ /* BaudRate = 115200bps. */
+ set_default_baudrate(serial_fd);
+ close(serial_fd);
+ serial_fd = -1;
+ while(1) {
+ p = queue_dequeue(tx_queue);
+ if(!p) {
+ break;
+ }
+ aboot_tiny_mem_free(p->data);
+ aboot_tiny_mem_free(p);
+ }
+ }
+}
+/*---------------------------------------------------------------------------*/
+int
+jacana_serialport_write(const uint8_t *buf, size_t len)
+{
+ serial_tx_memb_t *p;
+
+ if(serial_fd < 0 || fd_error) {
+ return len;
+ }
+
+ p = aboot_tiny_mem_alloc(sizeof(serial_tx_memb_t));
+ if(!p) {
+ aboot_tiny_log_printf("out of memory\n");
+ return -1;
+ }
+
+ p->data = aboot_tiny_mem_alloc(len);
+ if(!p->data) {
+ aboot_tiny_mem_free((void *)p);
+ aboot_tiny_log_printf("out of memory\n");
+ return -1;
+ }
+ memcpy(p->data, (void *)buf, len);
+ p->len = p->remain = len;
+ queue_enqueue(tx_queue, p);
+
+ return len;
+}
+/*---------------------------------------------------------------------------*/
+int
+jacana_serialport_init(const char *dev, int baud,
+ aboot_tiny_uart_rx_callback_t cb)
+{
+ serial_port_connect_opt_t connect_op;
+ connect_op.baud = baud;
+ connect_op.data_bits = 8;
+ connect_op.rtscts = false;
+ connect_op.xon = false;
+ connect_op.xoff = false;
+ connect_op.xany = false;
+ connect_op.dsrdtr = false;
+ connect_op.hupcl = false;
+ connect_op.parity = SERIALPORT_PARITY_NONE;
+ connect_op.stop_bits = SERIALPORT_STOPBITS_ONE;
+
+ if(!serial_port_open(dev, &connect_op)) {
+ rx_cb = cb;
+ return 0;
+ } else {
+ aboot_tiny_log_printf("open device \"%s\" failed\n", dev);
+ return -1;
+ }
+}
+/*---------------------------------------------------------------------------*/
+void
+jacana_serialport_exit(void)
+{
+ serial_port_close();
+}
+/*---------------------------------------------------------------------------*/