[PATCH] libosmocore[master]: sercomm: Enable multiple instances of 'sercomm'

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Mon May 15 15:34:26 UTC 2017


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 <laforge at gnumonks.org>
+/* (C) 2010,2017 by Harald Welte <laforge at gnumonks.org>
  *
  * 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 <laforge at gnumonks.org>



More information about the gerrit-log mailing list