Review at  https://gerrit.osmocom.org/2634

sercomm: Enable multiple instances of 'sercomm'

Rather than having one global instance, let's permit multiple instances
of sercomm to co-exist, with all API functions extended by the instance
as first argument.

Change-Id: I0f3b53f464b119d65747bcb0be0af2d631e1cc05
---
M include/osmocom/core/sercomm.h
M src/sercomm.c
2 files changed, 106 insertions(+), 104 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/34/2634/1

diff --git a/include/osmocom/core/sercomm.h b/include/osmocom/core/sercomm.h
index 21f715b..b751bcd 100644
--- a/include/osmocom/core/sercomm.h
+++ b/include/osmocom/core/sercomm.h
@@ -21,37 +21,62 @@
        _SC_DLCI_MAX
 };
 
+struct sercomm_inst;
+typedef void (*dlci_cb_t)(struct sercomm_inst *sercomm, uint8_t dlci, struct 
msgb *msg);
+
+struct sercomm_inst {
+       int initialized;
+       int uart_id;
+
+       /* transmit side */
+       struct {
+               struct llist_head dlci_queues[_SC_DLCI_MAX];
+               struct msgb *msg;
+               int state;
+               uint8_t *next_char;
+       } tx;
+
+       /* receive side */
+       struct {
+               dlci_cb_t dlci_handler[_SC_DLCI_MAX];
+               struct msgb *msg;
+               int state;
+               uint8_t dlci;
+               uint8_t ctrl;
+       } rx;
+};
+
+
 #ifndef HOST_BUILD
 #include <uart.h>
 /* helper functions for target */
-void sercomm_bind_uart(int uart);
-int sercomm_get_uart(void);
-void sercomm_change_speed(enum uart_baudrate bdrt);
+void sercomm_bind_uart(struct sercomm_inst *sercomm, int uart);
+int sercomm_get_uart(struct sercomm_inst *sercomm);
+void sercomm_change_speed(struct sercomm_inst *sercomm, enum uart_baudrate 
bdrt);
 #endif
 
-void sercomm_init(void);
-int sercomm_initialized(void);
+void sercomm_init(struct sercomm_inst *sercomm);
+int sercomm_initialized(struct sercomm_inst *sercomm);
 
 /* User Interface: Tx */
 
 /* user interface for transmitting messages for a given DLCI */
-void sercomm_sendmsg(uint8_t dlci, struct msgb *msg);
+void sercomm_sendmsg(struct sercomm_inst *sercomm, uint8_t dlci, struct msgb 
*msg);
 /* how deep is the Tx queue for a given DLCI */
-unsigned int sercomm_tx_queue_depth(uint8_t dlci);
+unsigned int sercomm_tx_queue_depth(struct sercomm_inst *sercomm, uint8_t 
dlci);
 
 /* User Interface: Rx */
 
 /* receiving messages for a given DLCI */
-typedef void (*dlci_cb_t)(uint8_t dlci, struct msgb *msg);
-int sercomm_register_rx_cb(uint8_t dlci, dlci_cb_t cb);
+int sercomm_register_rx_cb(struct sercomm_inst *sercomm, uint8_t dlci, 
dlci_cb_t cb);
 
 /* Driver Interface */
 
 /* fetch one octet of to-be-transmitted serial data. returns 0 if no more data 
*/
-int sercomm_drv_pull(uint8_t *ch);
+int sercomm_drv_pull(struct sercomm_inst *sercomm, uint8_t *ch);
 /* the driver has received one byte, pass it into sercomm layer.
    returns 1 in case of success, 0 in case of unrecognized char */
-int sercomm_drv_rx_char(uint8_t ch);
+int sercomm_drv_rx_char(struct sercomm_inst *sercomm, uint8_t ch);
 
 static inline struct msgb *sercomm_alloc_msgb(unsigned int len)
 {
diff --git a/src/sercomm.c b/src/sercomm.c
index 810d661..4fd979a 100644
--- a/src/sercomm.c
+++ b/src/sercomm.c
@@ -1,6 +1,6 @@
 /* Serial communications layer, based on HDLC */
 
-/* (C) 2010 by Harald Welte <[email protected]>
+/* (C) 2010,2017 by Harald Welte <[email protected]>
  *
  * All Rights Reserved
  *
@@ -59,7 +59,6 @@
 
 #endif
 
-
 enum rx_state {
        RX_ST_WAIT_START,
        RX_ST_ADDR,
@@ -68,61 +67,39 @@
        RX_ST_ESCAPE,
 };
 
-static struct {
-       int initialized;
-       int uart_id;
-
-       /* transmit side */
-       struct {
-               struct llist_head dlci_queues[_SC_DLCI_MAX];
-               struct msgb *msg;
-               enum rx_state state;
-               uint8_t *next_char;
-       } tx;
-
-       /* receive side */
-       struct {
-               dlci_cb_t dlci_handler[_SC_DLCI_MAX];
-               struct msgb *msg;
-               enum rx_state state;
-               uint8_t dlci;
-               uint8_t ctrl;
-       } rx;
-       
-} sercomm;
 
 #ifndef HOST_BUILD
-void sercomm_bind_uart(int uart)
+void sercomm_bind_uart(struct sercomm_inst *sercomm, int uart)
 {
-       sercomm.uart_id = uart;
+       sercomm->uart_id = uart;
 }
 
-int sercomm_get_uart(void)
+int sercomm_get_uart(struct sercomm_inst *sercomm)
 {
-       return sercomm.uart_id;
+       return sercomm->uart_id;
 }
 #endif
 
-void sercomm_init(void)
+void sercomm_init(struct sercomm_inst *sercomm)
 {
        unsigned int i;
-       for (i = 0; i < ARRAY_SIZE(sercomm.tx.dlci_queues); i++)
-               INIT_LLIST_HEAD(&sercomm.tx.dlci_queues[i]);
+       for (i = 0; i < ARRAY_SIZE(sercomm->tx.dlci_queues); i++)
+               INIT_LLIST_HEAD(&sercomm->tx.dlci_queues[i]);
 
-       sercomm.rx.msg = NULL;
-       sercomm.initialized = 1;
+       sercomm->rx.msg = NULL;
+       sercomm->initialized = 1;
 
        /* set up the echo dlci */
-       sercomm_register_rx_cb(SC_DLCI_ECHO, &sercomm_sendmsg);
+       sercomm_register_rx_cb(sercomm, SC_DLCI_ECHO, &sercomm_sendmsg);
 }
 
-int sercomm_initialized(void)
+int sercomm_initialized(struct sercomm_inst *sercomm)
 {
-       return sercomm.initialized;
+       return sercomm->initialized;
 }
 
 /* user interface for transmitting messages for a given DLCI */
-void sercomm_sendmsg(uint8_t dlci, struct msgb *msg)
+void sercomm_sendmsg(struct sercomm_inst *sercomm, uint8_t dlci, struct msgb 
*msg)
 {
        unsigned long flags;
        uint8_t *hdr;
@@ -135,22 +112,22 @@
        /* This functiion can be called from any context: FIQ, IRQ
         * and supervisor context.  Proper locking is important! */
        sercomm_lock(&flags);
-       msgb_enqueue(&sercomm.tx.dlci_queues[dlci], msg);
+       msgb_enqueue(&sercomm->tx.dlci_queues[dlci], msg);
        sercomm_unlock(&flags);
 
 #ifndef HOST_BUILD
        /* tell UART that we have something to send */
-       uart_irq_enable(sercomm.uart_id, UART_IRQ_TX_EMPTY, 1);
+       uart_irq_enable(sercomm->uart_id, UART_IRQ_TX_EMPTY, 1);
 #endif
 }
 
 /* how deep is the Tx queue for a given DLCI */
-unsigned int sercomm_tx_queue_depth(uint8_t dlci)
+unsigned int sercomm_tx_queue_depth(struct sercomm_inst *sercomm, uint8_t dlci)
 {
        struct llist_head *le;
        unsigned int num = 0;
 
-       llist_for_each(le, &sercomm.tx.dlci_queues[dlci]) {
+       llist_for_each(le, &sercomm->tx.dlci_queues[dlci]) {
                num++;
        }
 
@@ -160,7 +137,7 @@
 #ifndef HOST_BUILD
 /* wait until everything has been transmitted, then grab the lock and
  * change the baud rate as requested */
-void sercomm_change_speed(enum uart_baudrate bdrt)
+void sercomm_change_speed(struct sercomm_inst *sercomm, enum uart_baudrate 
bdrt)
 {
        unsigned int i, count;
        unsigned long flags;
@@ -168,7 +145,7 @@
        while (1) {
                /* count the number of pending messages */
                count = 0;
-               for (i = 0; i < ARRAY_SIZE(sercomm.tx.dlci_queues); i++)
+               for (i = 0; i < ARRAY_SIZE(sercomm->tx.dlci_queues); i++)
                        count += sercomm_tx_queue_depth(i);
                /* if we still have any in the queue, restart */
                if (count == 0)
@@ -179,9 +156,9 @@
                /* no messages in the queue, grab the lock to ensure it
                 * stays that way */
                sercomm_lock(&flags);
-               if (!sercomm.tx.msg && !sercomm.tx.next_char) {
+               if (!sercomm->tx.msg && !sercomm->tx.next_char) {
                        /* change speed */
-                       uart_baudrate(sercomm.uart_id, bdrt);
+                       uart_baudrate(sercomm->uart_id, bdrt);
                        sercomm_unlock(&flags);
                        break;
                }
@@ -191,7 +168,7 @@
 #endif
 
 /* fetch one octet of to-be-transmitted serial data */
-int sercomm_drv_pull(uint8_t *ch)
+int sercomm_drv_pull(struct sercomm_inst *sercomm, uint8_t *ch)
 {
        unsigned long flags;
 
@@ -200,18 +177,18 @@
 
        sercomm_lock(&flags);
 
-       if (!sercomm.tx.msg) {
+       if (!sercomm->tx.msg) {
                unsigned int i;
                /* dequeue a new message from the queues */
-               for (i = 0; i < ARRAY_SIZE(sercomm.tx.dlci_queues); i++) {
-                       sercomm.tx.msg = 
msgb_dequeue(&sercomm.tx.dlci_queues[i]);
-                       if (sercomm.tx.msg)
+               for (i = 0; i < ARRAY_SIZE(sercomm->tx.dlci_queues); i++) {
+                       sercomm->tx.msg = 
msgb_dequeue(&sercomm->tx.dlci_queues[i]);
+                       if (sercomm->tx.msg)
                                break;
                }
-               if (sercomm.tx.msg) {
+               if (sercomm->tx.msg) {
                        /* start of a new message, send start flag octet */
                        *ch = HDLC_FLAG;
-                       sercomm.tx.next_char = sercomm.tx.msg->data;
+                       sercomm->tx.next_char = sercomm->tx.msg->data;
                        sercomm_unlock(&flags);
                        return 1;
                } else {
@@ -221,31 +198,31 @@
                }
        }
 
-       if (sercomm.tx.state == RX_ST_ESCAPE) {
+       if (sercomm->tx.state == RX_ST_ESCAPE) {
                /* we've already transmitted the ESCAPE octet,
                 * we now need to transmit the escaped data */
-               *ch = *sercomm.tx.next_char++;
-               sercomm.tx.state = RX_ST_DATA;
-       } else if (sercomm.tx.next_char >= sercomm.tx.msg->tail) {
+               *ch = *sercomm->tx.next_char++;
+               sercomm->tx.state = RX_ST_DATA;
+       } else if (sercomm->tx.next_char >= sercomm->tx.msg->tail) {
                /* last character has already been transmitted,
                 * send end-of-message octet */
                *ch = HDLC_FLAG;
                /* we've reached the end of the message buffer */
-               msgb_free(sercomm.tx.msg);
-               sercomm.tx.msg = NULL;
-               sercomm.tx.next_char = NULL;
+               msgb_free(sercomm->tx.msg);
+               sercomm->tx.msg = NULL;
+               sercomm->tx.next_char = NULL;
        /* escaping for the two control octets */
-       } else if (*sercomm.tx.next_char == HDLC_FLAG ||
-                  *sercomm.tx.next_char == HDLC_ESCAPE ||
-                  *sercomm.tx.next_char == 0x00) {
+       } else if (*sercomm->tx.next_char == HDLC_FLAG ||
+                  *sercomm->tx.next_char == HDLC_ESCAPE ||
+                  *sercomm->tx.next_char == 0x00) {
                /* send an escape octet */
                *ch = HDLC_ESCAPE;
                /* invert bit 5 of the next octet to be sent */
-               *sercomm.tx.next_char ^= (1 << 5);
-               sercomm.tx.state = RX_ST_ESCAPE;
+               *sercomm->tx.next_char ^= (1 << 5);
+               sercomm->tx.state = RX_ST_ESCAPE;
        } else {
                /* standard case, simply send next octet */
-               *ch = *sercomm.tx.next_char++;
+               *ch = *sercomm->tx.next_char++;
        }
 
        sercomm_unlock(&flags);
@@ -253,89 +230,89 @@
 }
 
 /* register a handler for a given DLCI */
-int sercomm_register_rx_cb(uint8_t dlci, dlci_cb_t cb)
+int sercomm_register_rx_cb(struct sercomm_inst *sercomm, uint8_t dlci, 
dlci_cb_t cb)
 {
-       if (dlci >= ARRAY_SIZE(sercomm.rx.dlci_handler))
+       if (dlci >= ARRAY_SIZE(sercomm->rx.dlci_handler))
                return -EINVAL;
 
-       if (sercomm.rx.dlci_handler[dlci])
+       if (sercomm->rx.dlci_handler[dlci])
                return -EBUSY;
 
-       sercomm.rx.dlci_handler[dlci] = cb;
+       sercomm->rx.dlci_handler[dlci] = cb;
        return 0;
 }
 
 /* dispatch an incoming message once it is completely received */
-static void dispatch_rx_msg(uint8_t dlci, struct msgb *msg)
+static void dispatch_rx_msg(struct sercomm_inst *sercomm, uint8_t dlci, struct 
msgb *msg)
 {
-       if (dlci >= ARRAY_SIZE(sercomm.rx.dlci_handler) ||
-           !sercomm.rx.dlci_handler[dlci]) {
+       if (dlci >= ARRAY_SIZE(sercomm->rx.dlci_handler) ||
+           !sercomm->rx.dlci_handler[dlci]) {
                msgb_free(msg);
                return;
        }
-       sercomm.rx.dlci_handler[dlci](dlci, msg);
+       sercomm->rx.dlci_handler[dlci](sercomm, dlci, msg);
 }
 
 /* the driver has received one byte, pass it into sercomm layer */
-int sercomm_drv_rx_char(uint8_t ch)
+int sercomm_drv_rx_char(struct sercomm_inst *sercomm, uint8_t ch)
 {
        uint8_t *ptr;
 
        /* we are always called from interrupt context in this function,
         * which means that any data structures we use need to be for
         * our exclusive access */
-       if (!sercomm.rx.msg)
-               sercomm.rx.msg = sercomm_alloc_msgb(SERCOMM_RX_MSG_SIZE);
+       if (!sercomm->rx.msg)
+               sercomm->rx.msg = sercomm_alloc_msgb(SERCOMM_RX_MSG_SIZE);
 
-       if (msgb_tailroom(sercomm.rx.msg) == 0) {
+       if (msgb_tailroom(sercomm->rx.msg) == 0) {
                //cons_puts("sercomm_drv_rx_char() overflow!\n");
-               msgb_free(sercomm.rx.msg);
-               sercomm.rx.msg = sercomm_alloc_msgb(SERCOMM_RX_MSG_SIZE);
-               sercomm.rx.state = RX_ST_WAIT_START;
+               msgb_free(sercomm->rx.msg);
+               sercomm->rx.msg = sercomm_alloc_msgb(SERCOMM_RX_MSG_SIZE);
+               sercomm->rx.state = RX_ST_WAIT_START;
                return 0;
        }
 
-       switch (sercomm.rx.state) {
+       switch (sercomm->rx.state) {
        case RX_ST_WAIT_START:
                if (ch != HDLC_FLAG)
                        break;
-               sercomm.rx.state = RX_ST_ADDR;
+               sercomm->rx.state = RX_ST_ADDR;
                break;
        case RX_ST_ADDR:
-               sercomm.rx.dlci = ch;
-               sercomm.rx.state = RX_ST_CTRL;
+               sercomm->rx.dlci = ch;
+               sercomm->rx.state = RX_ST_CTRL;
                break;
        case RX_ST_CTRL:
-               sercomm.rx.ctrl = ch;
-               sercomm.rx.state = RX_ST_DATA;
+               sercomm->rx.ctrl = ch;
+               sercomm->rx.state = RX_ST_DATA;
                break;
        case RX_ST_DATA:
                if (ch == HDLC_ESCAPE) {
                        /* drop the escape octet, but change state */
-                       sercomm.rx.state = RX_ST_ESCAPE;
+                       sercomm->rx.state = RX_ST_ESCAPE;
                        break;
                } else if (ch == HDLC_FLAG) {
                        /* message is finished */
-                       dispatch_rx_msg(sercomm.rx.dlci, sercomm.rx.msg);
+                       dispatch_rx_msg(sercomm, sercomm->rx.dlci, 
sercomm->rx.msg);
                        /* allocate new buffer */
-                       sercomm.rx.msg = NULL;
+                       sercomm->rx.msg = NULL;
                        /* start all over again */
-                       sercomm.rx.state = RX_ST_WAIT_START;
+                       sercomm->rx.state = RX_ST_WAIT_START;
 
                        /* do not add the control char */
                        break;
                }
                /* default case: store the octet */
-               ptr = msgb_put(sercomm.rx.msg, 1);
+               ptr = msgb_put(sercomm->rx.msg, 1);
                *ptr = ch;
                break;
        case RX_ST_ESCAPE:
                /* store bif-5-inverted octet in buffer */
                ch ^= (1 << 5);
-               ptr = msgb_put(sercomm.rx.msg, 1);
+               ptr = msgb_put(sercomm->rx.msg, 1);
                *ptr = ch;
                /* transition back to normal DATA state */
-               sercomm.rx.state = RX_ST_DATA;
+               sercomm->rx.state = RX_ST_DATA;
                break;
        }
 

-- 
To view, visit https://gerrit.osmocom.org/2634
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0f3b53f464b119d65747bcb0be0af2d631e1cc05
Gerrit-PatchSet: 1
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <[email protected]>

Reply via email to