blob: 895717ad107e29553ec7c241a787a1963e036093 [file] [log] [blame]
Harald Welte95960602019-09-27 19:22:34 +02001#include <errno.h>
2#include <string.h>
3#include <osmocom/core/linuxlist.h>
4#include <osmocom/core/utils.h>
5
6#include "cuart.h"
7
8static LLIST_HEAD(g_cuart_drivers);
9
10const struct value_string card_uart_event_vals[] = {
11 OSMO_VALUE_STRING(CUART_E_RX_SINGLE),
12 OSMO_VALUE_STRING(CUART_E_RX_COMPLETE),
13 OSMO_VALUE_STRING(CUART_E_RX_TIMEOUT),
14 OSMO_VALUE_STRING(CUART_E_TX_COMPLETE),
15 { 0, NULL }
16};
17
18static struct card_uart_driver *cuart_drv_by_name(const char *driver_name)
19{
20 struct card_uart_driver *drv;
21 llist_for_each_entry(drv, &g_cuart_drivers, list) {
22 if (!strcmp(drv->name, driver_name))
23 return drv;
24 }
25 return NULL;
26}
27
28int card_uart_open(struct card_uart *cuart, const char *driver_name, const char *device_name)
29{
30 struct card_uart_driver *drv = cuart_drv_by_name(driver_name);
31 int rc;
32
33 if (!drv)
34 return -ENODEV;
35
36 cuart->rx_enabled = true;
37 cuart->rx_threshold = 1;
38
39 rc = drv->ops->open(cuart, device_name);
40 if (rc < 0)
41 return rc;
42
43 cuart->driver = drv;
44 return 0;
45}
46
47int card_uart_close(struct card_uart *cuart)
48{
49 OSMO_ASSERT(cuart);
50 OSMO_ASSERT(cuart->driver);
51 OSMO_ASSERT(cuart->driver->ops);
52 OSMO_ASSERT(cuart->driver->ops->close);
53 return cuart->driver->ops->close(cuart);
54}
55
56int card_uart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, bool enable)
57{
58 int rc;
59 OSMO_ASSERT(cuart);
60 OSMO_ASSERT(cuart->driver);
61 OSMO_ASSERT(cuart->driver->ops);
62 OSMO_ASSERT(cuart->driver->ops->ctrl);
63 rc = cuart->driver->ops->ctrl(cuart, ctl, enable);
64 if (rc < 0)
65 return rc;
66
67 switch (ctl) {
68 case CUART_CTL_RX:
69 cuart->rx_enabled = enable;
70 break;
71 default:
72 break;
73 }
74
75 return rc;
76}
77
Harald Weltea34ba462019-10-01 08:55:29 +020078int card_uart_tx(struct card_uart *cuart, const uint8_t *data, size_t len)
Harald Welte95960602019-09-27 19:22:34 +020079{
80 OSMO_ASSERT(cuart);
81 OSMO_ASSERT(cuart->driver);
82 OSMO_ASSERT(cuart->driver->ops);
83 OSMO_ASSERT(cuart->driver->ops->async_tx);
84
85 OSMO_ASSERT(!cuart->tx_busy);
86 cuart->tx_busy = true;
87 /* disable receiver to avoid receiving what we transmit */
88 card_uart_ctrl(cuart, CUART_CTL_RX, false);
89
Harald Weltea34ba462019-10-01 08:55:29 +020090 return cuart->driver->ops->async_tx(cuart, data, len);
Harald Welte95960602019-09-27 19:22:34 +020091}
92
93int card_uart_rx(struct card_uart *cuart, uint8_t *data, size_t len)
94{
95 OSMO_ASSERT(cuart);
96 OSMO_ASSERT(cuart->driver);
97 OSMO_ASSERT(cuart->driver->ops);
98 OSMO_ASSERT(cuart->driver->ops->async_rx);
99 return cuart->driver->ops->async_rx(cuart, data, len);
100}
101
102void card_uart_set_rx_threshold(struct card_uart *cuart, size_t rx_threshold)
103{
104 cuart->rx_threshold = rx_threshold;
105}
106
107void card_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data)
108{
109 OSMO_ASSERT(cuart);
110 OSMO_ASSERT(cuart->handle_event);
111
112 switch (evt) {
113 case CUART_E_TX_COMPLETE:
114 cuart->tx_busy = false;
115 /* re-enable receiver if we're done with transmit */
Harald Welte95960602019-09-27 19:22:34 +0200116 card_uart_ctrl(cuart, CUART_CTL_RX, true);
117 break;
118 default:
119 break;
120 }
121
122 cuart->handle_event(cuart, evt, data);
123}
124
125int card_uart_driver_register(struct card_uart_driver *drv)
126{
127 OSMO_ASSERT(!cuart_drv_by_name(drv->name));
128 OSMO_ASSERT(drv->name);
129 OSMO_ASSERT(drv->ops);
130 llist_add_tail(&drv->list, &g_cuart_drivers);
131 return 0;
132}