blob: 7094a8622f9361ab7b53cf7ccec13a468309f1e7 [file] [log] [blame]
Harald Weltea40c8e52019-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>
Harald Welte7b64fc02019-10-09 20:49:35 +02005#include <osmocom/core/timer.h>
Harald Weltea40c8e52019-09-27 19:22:34 +02006
7#include "cuart.h"
8
9static LLIST_HEAD(g_cuart_drivers);
10
11const struct value_string card_uart_event_vals[] = {
12 OSMO_VALUE_STRING(CUART_E_RX_SINGLE),
13 OSMO_VALUE_STRING(CUART_E_RX_COMPLETE),
14 OSMO_VALUE_STRING(CUART_E_RX_TIMEOUT),
15 OSMO_VALUE_STRING(CUART_E_TX_COMPLETE),
16 { 0, NULL }
17};
18
19static struct card_uart_driver *cuart_drv_by_name(const char *driver_name)
20{
21 struct card_uart_driver *drv;
22 llist_for_each_entry(drv, &g_cuart_drivers, list) {
23 if (!strcmp(drv->name, driver_name))
24 return drv;
25 }
26 return NULL;
27}
28
Harald Welte7b64fc02019-10-09 20:49:35 +020029/* obtain the current ETU in us */
30static int get_etu_in_us(struct card_uart *cuart)
31{
Eric Wilddbff4212019-11-27 19:02:31 +010032 OSMO_ASSERT(cuart);
33 OSMO_ASSERT(cuart->driver);
34 OSMO_ASSERT(cuart->driver->ops);
35 OSMO_ASSERT(cuart->driver->ops->ctrl);
36
37 return 1e6 / cuart->driver->ops->ctrl(cuart, CUART_CTL_GET_BAUDRATE, 0);
Harald Welte7b64fc02019-10-09 20:49:35 +020038}
39
40/* software waiting-time timer has expired */
41static void card_uart_wtime_cb(void *data)
42{
43 struct card_uart *cuart = (struct card_uart *) data;
44 card_uart_notification(cuart, CUART_E_RX_TIMEOUT, NULL);
45 /* should we automatically disable the receiver? */
46}
47
48void card_uart_wtime_restart(struct card_uart *cuart)
49{
50 int secs, usecs;
51
Eric Wild2f5cdd12019-11-27 18:40:44 +010052 if(!cuart->current_wtime_byte)
53 return;
54
Eric Wild5fcfc492020-04-03 22:27:18 +020055 int etu_in_us = get_etu_in_us(cuart) + 1;
56 cuart->wtime_etu = cuart->wtime_etu ? cuart->wtime_etu : 1;
57
Eric Wild2f5cdd12019-11-27 18:40:44 +010058 /* timemout is wtime * ETU + expected number of bytes * (12ETU+1 slack)ETU */
Eric Wild5fcfc492020-04-03 22:27:18 +020059 usecs = etu_in_us * cuart->wtime_etu +
60 etu_in_us * cuart->current_wtime_byte * (12+1);
61
62 /* limit lower wait time to reasonable value */
63 usecs = usecs < 300000 ? 300000 : usecs;
64
Harald Welte7b64fc02019-10-09 20:49:35 +020065 if (usecs > 1000000) {
66 secs = usecs / 1000000;
67 usecs = usecs % 1000000;
68 } else
69 secs = 0;
70 osmo_timer_schedule(&cuart->wtime_tmr, secs, usecs);
71}
72
Harald Weltea40c8e52019-09-27 19:22:34 +020073int card_uart_open(struct card_uart *cuart, const char *driver_name, const char *device_name)
74{
75 struct card_uart_driver *drv = cuart_drv_by_name(driver_name);
76 int rc;
77
78 if (!drv)
79 return -ENODEV;
80
Harald Welte7b64fc02019-10-09 20:49:35 +020081 cuart->wtime_etu = 9600; /* ISO 7816-3 Section 8.1 */
Harald Weltea40c8e52019-09-27 19:22:34 +020082 cuart->rx_enabled = true;
83 cuart->rx_threshold = 1;
Harald Welte7b64fc02019-10-09 20:49:35 +020084 osmo_timer_setup(&cuart->wtime_tmr, card_uart_wtime_cb, cuart);
Harald Weltea40c8e52019-09-27 19:22:34 +020085
86 rc = drv->ops->open(cuart, device_name);
87 if (rc < 0)
88 return rc;
89
90 cuart->driver = drv;
91 return 0;
92}
93
94int card_uart_close(struct card_uart *cuart)
95{
96 OSMO_ASSERT(cuart);
97 OSMO_ASSERT(cuart->driver);
98 OSMO_ASSERT(cuart->driver->ops);
99 OSMO_ASSERT(cuart->driver->ops->close);
100 return cuart->driver->ops->close(cuart);
101}
102
Harald Welte9700d392019-10-09 20:17:28 +0200103int card_uart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, int arg)
Harald Weltea40c8e52019-09-27 19:22:34 +0200104{
105 int rc;
106 OSMO_ASSERT(cuart);
107 OSMO_ASSERT(cuart->driver);
108 OSMO_ASSERT(cuart->driver->ops);
109 OSMO_ASSERT(cuart->driver->ops->ctrl);
Harald Welte7b64fc02019-10-09 20:49:35 +0200110
Harald Welte9700d392019-10-09 20:17:28 +0200111 rc = cuart->driver->ops->ctrl(cuart, ctl, arg);
Harald Weltea40c8e52019-09-27 19:22:34 +0200112 if (rc < 0)
113 return rc;
114
115 switch (ctl) {
Harald Welte7b64fc02019-10-09 20:49:35 +0200116 case CUART_CTL_WTIME:
117 cuart->wtime_etu = arg;
118 break;
Harald Weltea40c8e52019-09-27 19:22:34 +0200119 case CUART_CTL_RX:
Harald Welte9700d392019-10-09 20:17:28 +0200120 cuart->rx_enabled = arg ? true : false;
Harald Welte7b64fc02019-10-09 20:49:35 +0200121 if (!cuart->rx_enabled)
122 osmo_timer_del(&cuart->wtime_tmr);
Eric Wild2f5cdd12019-11-27 18:40:44 +0100123// else
124// card_uart_wtime_restart(cuart);
125 break;
126 case CUART_CTL_RX_TIMER_HINT:
127 cuart->current_wtime_byte = arg;
128 if(arg)
129 card_uart_wtime_restart(cuart);
130 else
131 osmo_timer_del(&cuart->wtime_tmr);
Harald Weltea40c8e52019-09-27 19:22:34 +0200132 break;
133 default:
134 break;
135 }
136
137 return rc;
138}
139
Harald Welte6603d952019-10-09 20:50:13 +0200140int card_uart_tx(struct card_uart *cuart, const uint8_t *data, size_t len, bool rx_after_complete)
Harald Weltea40c8e52019-09-27 19:22:34 +0200141{
142 OSMO_ASSERT(cuart);
143 OSMO_ASSERT(cuart->driver);
144 OSMO_ASSERT(cuart->driver->ops);
145 OSMO_ASSERT(cuart->driver->ops->async_tx);
146
147 OSMO_ASSERT(!cuart->tx_busy);
148 cuart->tx_busy = true;
Harald Welte6603d952019-10-09 20:50:13 +0200149 cuart->rx_after_tx_compl = rx_after_complete;
Harald Weltea40c8e52019-09-27 19:22:34 +0200150 /* disable receiver to avoid receiving what we transmit */
151 card_uart_ctrl(cuart, CUART_CTL_RX, false);
152
Harald Welte02dd9112019-10-01 08:55:29 +0200153 return cuart->driver->ops->async_tx(cuart, data, len);
Harald Weltea40c8e52019-09-27 19:22:34 +0200154}
155
156int card_uart_rx(struct card_uart *cuart, uint8_t *data, size_t len)
157{
158 OSMO_ASSERT(cuart);
159 OSMO_ASSERT(cuart->driver);
160 OSMO_ASSERT(cuart->driver->ops);
161 OSMO_ASSERT(cuart->driver->ops->async_rx);
162 return cuart->driver->ops->async_rx(cuart, data, len);
163}
164
165void card_uart_set_rx_threshold(struct card_uart *cuart, size_t rx_threshold)
166{
167 cuart->rx_threshold = rx_threshold;
168}
169
170void card_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data)
171{
172 OSMO_ASSERT(cuart);
173 OSMO_ASSERT(cuart->handle_event);
174
175 switch (evt) {
176 case CUART_E_TX_COMPLETE:
177 cuart->tx_busy = false;
178 /* re-enable receiver if we're done with transmit */
Harald Welte6603d952019-10-09 20:50:13 +0200179 if (cuart->rx_after_tx_compl)
180 card_uart_ctrl(cuart, CUART_CTL_RX, true);
Harald Weltea40c8e52019-09-27 19:22:34 +0200181 break;
Eric Wild2f5cdd12019-11-27 18:40:44 +0100182// case CUART_E_RX_COMPLETE:
183// osmo_timer_del(&cuart->wtime_tmr);
184// break;
185// case CUART_E_RX_SINGLE:
186// card_uart_wtime_restart(cuart);
187// break;
Harald Weltea40c8e52019-09-27 19:22:34 +0200188 default:
189 break;
190 }
191
192 cuart->handle_event(cuart, evt, data);
193}
194
195int card_uart_driver_register(struct card_uart_driver *drv)
196{
197 OSMO_ASSERT(!cuart_drv_by_name(drv->name));
198 OSMO_ASSERT(drv->name);
199 OSMO_ASSERT(drv->ops);
200 llist_add_tail(&drv->list, &g_cuart_drivers);
201 return 0;
202}