#include <stdio.h>
#include <errno.h>
-#include <osmocore/msgb.h>
+#include <osmocom/core/msgb.h>
#ifdef HOST_BUILD
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-#endif
-#include <sercomm.h>
-#define local_irq_save(x)
-#define local_fiq_disable()
-#define local_irq_restore(x)
+
+# define SERCOMM_RX_MSG_SIZE 2048
+# ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+# endif
+# include <sercomm.h>
+
+static inline void sercomm_lock(unsigned long __attribute__((unused)) *flags) {}
+static inline void sercomm_unlock(unsigned long __attribute__((unused)) *flags) {}
#else
-#include <debug.h>
-#include <osmocore/linuxlist.h>
-#include <asm/system.h>
-#include <comm/sercomm.h>
-#include <calypso/uart.h>
+# define SERCOMM_RX_MSG_SIZE 256
+# include <debug.h>
+# include <osmocom/core/linuxlist.h>
+# include <asm/system.h>
+
+static inline void sercomm_lock(unsigned long *flags)
+{
+ local_firq_save(*flags);
+}
+
+static inline void sercomm_unlock(unsigned long *flags)
+{
+ local_irq_restore(*flags);
+}
+
+# include <comm/sercomm.h>
+# include <uart.h>
+
#endif
-#define SERCOMM_RX_MSG_SIZE 256
enum rx_state {
RX_ST_WAIT_START,
struct {
struct llist_head dlci_queues[_SC_DLCI_MAX];
struct msgb *msg;
+ enum rx_state state;
uint8_t *next_char;
} tx;
sercomm.rx.msg = NULL;
sercomm.initialized = 1;
+
+ /* set up the echo dlci */
+ sercomm_register_rx_cb(SC_DLCI_ECHO, &sercomm_sendmsg);
}
int sercomm_initialized(void)
/* This functiion can be called from any context: FIQ, IRQ
* and supervisor context. Proper locking is important! */
- local_irq_save(flags);
- local_fiq_disable();
+ sercomm_lock(&flags);
msgb_enqueue(&sercomm.tx.dlci_queues[dlci], msg);
- local_irq_restore(flags);
+ sercomm_unlock(&flags);
#ifndef HOST_BUILD
/* tell UART that we have something to send */
/* fetch one octet of to-be-transmitted serial data */
int sercomm_drv_pull(uint8_t *ch)
{
- /* 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 */
+ unsigned long flags;
+
+ /* we may be called from interrupt context, but we stiff need to lock
+ * because sercomm could be accessed from a FIQ context ... */
+
+ sercomm_lock(&flags);
+
if (!sercomm.tx.msg) {
unsigned int i;
/* dequeue a new message from the queues */
/* start of a new message, send start flag octet */
*ch = HDLC_FLAG;
sercomm.tx.next_char = sercomm.tx.msg->data;
+ sercomm_unlock(&flags);
return 1;
} else {
/* no more data avilable */
+ sercomm_unlock(&flags);
return 0;
}
}
- /* escaping for the two control octets */
- if (*sercomm.tx.next_char == HDLC_FLAG ||
- *sercomm.tx.next_char == HDLC_ESCAPE) {
- /* send an escape octet */
- *ch = HDLC_ESCAPE;
- /* invert bit 5 of the next octet to be sent */
- *sercomm.tx.next_char ^= (1 << 5);
- } else if (sercomm.tx.next_char == sercomm.tx.msg->tail) {
+ 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) {
/* last character has already been transmitted,
* send end-of-message octet */
*ch = HDLC_FLAG;
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) {
+ /* 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;
} else {
/* standard case, simply send next octet */
*ch = *sercomm.tx.next_char++;
}
+
+ sercomm_unlock(&flags);
return 1;
}
return 0;
}
-/* dispatch an incomnig message once it is completely received */
+/* dispatch an incoming message once it is completely received */
static void dispatch_rx_msg(uint8_t dlci, struct msgb *msg)
{
if (dlci >= ARRAY_SIZE(sercomm.rx.dlci_handler) ||
ch ^= (1 << 5);
ptr = msgb_put(sercomm.rx.msg, 1);
*ptr = ch;
- /* transition back to nromal DATA state */
+ /* transition back to normal DATA state */
sercomm.rx.state = RX_ST_DATA;
break;
}