1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
#ifndef _SERCOMM_H
#define _SERCOMM_H
#include <osmocom/core/msgb.h>
/*! \defgroup sercomm Seriall Communications (HDLC)
* @{
*/
/*! \file sercomm.h
* \brief Osmocom Sercomm HDLC (de)multiplex
*/
/*! \brief A low sercomm_dlci means high priority. A high DLCI means low priority */
enum sercomm_dlci {
SC_DLCI_HIGHEST = 0,
SC_DLCI_DEBUG = 4,
SC_DLCI_L1A_L23 = 5,
SC_DLCI_LOADER = 9,
SC_DLCI_CONSOLE = 10,
SC_DLCI_ECHO = 128,
_SC_DLCI_MAX
};
struct osmo_sercomm_inst;
/*! \brief call-back function for per-DLC receive handler
* \param[in] sercomm instance on which msg was received
* \param[in] dlci DLC Identifier of received msg
* \param[in] msg received message that needs to be processed */
typedef void (*dlci_cb_t)(struct osmo_sercomm_inst *sercomm, uint8_t dlci, struct msgb *msg);
/*! \brief one instance of a sercomm multiplex/demultiplex */
struct osmo_sercomm_inst {
/*! \brief Has this instance been initialized? */
int initialized;
/*! \brief UART Identifier */
int uart_id;
/*! \brief transmit side */
struct {
/*! \brief per-DLC queue of pending transmit msgbs */
struct llist_head dlci_queues[_SC_DLCI_MAX];
/*! \brief msgb currently being transmitted */
struct msgb *msg;
/*! \brief transmit state */
int state;
/*! \brief next to-be-transmitted char in msg */
uint8_t *next_char;
} tx;
/*! \brief receive side */
struct {
/*! \brief per-DLC handler call-back functions */
dlci_cb_t dlci_handler[_SC_DLCI_MAX];
/*! \brief msgb allocation size for rx msgs */
unsigned int msg_size;
/*! \brief currently received msgb */
struct msgb *msg;
/*! \brief receive state */
int state;
/*! \brief DLCI of currently received msgb */
uint8_t dlci;
/*! \brief CTRL of currently received msgb */
uint8_t ctrl;
} rx;
};
void osmo_sercomm_init(struct osmo_sercomm_inst *sercomm);
int osmo_sercomm_initialized(struct osmo_sercomm_inst *sercomm);
/* User Interface: Tx */
void osmo_sercomm_sendmsg(struct osmo_sercomm_inst *sercomm, uint8_t dlci, struct msgb *msg);
unsigned int osmo_sercomm_tx_queue_depth(struct osmo_sercomm_inst *sercomm, uint8_t dlci);
/* User Interface: Rx */
int osmo_sercomm_register_rx_cb(struct osmo_sercomm_inst *sercomm, uint8_t dlci, dlci_cb_t cb);
int osmo_sercomm_change_speed(struct osmo_sercomm_inst *sercomm, uint32_t bdrt);
/* Driver Interface */
int osmo_sercomm_drv_pull(struct osmo_sercomm_inst *sercomm, uint8_t *ch);
int osmo_sercomm_drv_rx_char(struct osmo_sercomm_inst *sercomm, uint8_t ch);
extern void sercomm_drv_lock(unsigned long *flags);
extern void sercomm_drv_unlock(unsigned long *flags);
/*! \brief low-level driver routine to request start of transmission
* The Sercomm code calls this function to inform the low-level driver
* that some data is pending for transmission, and the low-level driver
* should (if not active already) start enabling tx_empty interrupts
* and pull drivers out of sercomm using osmo_sercomm_drv_pull() until
* the latter returns 0.
* \param[in] sercomm Osmocom sercomm instance for which to change
*/
extern void sercomm_drv_start_tx(struct osmo_sercomm_inst *sercomm);
/*! \brief low-level driver routine to execute baud-rate change
* \param[in] sercomm Osmocom sercomm instance for which to change
* \param[in] bdrt New Baud-Rate (integer)
* \returns 0 on success; negative in case of error
*/
extern int sercomm_drv_baudrate_chg(struct osmo_sercomm_inst *sercomm, uint32_t bdrt);
/*! \brief Sercomm msgb allocator function */
static inline struct msgb *osmo_sercomm_alloc_msgb(unsigned int len)
{
return msgb_alloc_headroom(len+4, 4, "sercomm_tx");
}
/*! @} */
#endif /* _SERCOMM_H */
|