blob: 96ecca682e68a060d8e6a44629afec91287a0d70 [file] [log] [blame]
Harald Welte2a6d3af2016-02-28 19:29:14 +01001#include "board.h"
2#include "card_emu.h"
Harald Weltebd717682016-02-28 19:30:05 +01003#include "iso7816_fidi.h"
Harald Welte54cb3d02016-02-29 14:12:40 +01004#include "utils.h"
Harald Welteacae4122016-03-02 10:27:58 +01005#include "linuxlist.h"
Harald Welteebb80ed2016-03-02 13:56:59 +01006#include "req_ctx.h"
7#include "cardemu_prot.h"
Harald Weltebd717682016-02-28 19:30:05 +01008
9#define TRACE_ENTRY() TRACE_DEBUG("%s entering\n", __func__)
Harald Welte2a6d3af2016-02-28 19:29:14 +010010
11static const Pin pins_cardsim[] = PINS_CARDSIM;
12
13/* UART pins */
14static const Pin pins_usim1[] = {PINS_USIM1};
15static const Pin pin_usim1_rst = PIN_USIM1_nRST;
16static const Pin pin_usim1_vcc = PIN_USIM1_VCC;
17
18#ifdef CARDEMU_SECOND_UART
19static const Pin pins_usim2[] = {PINS_USIM1};
20static const Pin pin_usim2_rst = PIN_USIM2_nRST;
21static const Pin pin_usim2_vcc = PIN_USIM2_VCC;
22#endif
23
Harald Welte13e82022016-03-02 15:17:53 +010024struct cardem_inst {
25 struct card_handle *ch;
26 struct llist_head usb_out_queue;
27 struct ringbuf rb;
28 struct Usart_info usart_info;
29 int usb_pending_old;
30 uint8_t ep_out;
31 uint8_t ep_in;
32 uint8_t ep_int;
33};
Harald Welte2a6d3af2016-02-28 19:29:14 +010034
Harald Welte13e82022016-03-02 15:17:53 +010035static struct cardem_inst cardem_inst[] = {
Harald Welte2a6d3af2016-02-28 19:29:14 +010036 {
Harald Welte13e82022016-03-02 15:17:53 +010037 .usart_info = {
38 .base = USART1,
39 .id = ID_USART1,
40 .state = USART_RCV
41 },
42 .ep_out = PHONE_DATAOUT,
43 .ep_in = PHONE_DATAIN,
44 .ep_int = PHONE_INT,
Harald Welte2a6d3af2016-02-28 19:29:14 +010045 },
46#ifdef CARDEMU_SECOND_UART
47 {
Harald Welte13e82022016-03-02 15:17:53 +010048 .usart_info = {
49 .base = USART0,
50 .id = ID_USART0,
51 .state = USART_RCV
52 },
53 .ep_out = CARDEM_USIM2_DATAOUT,
54 .ep_in = CARDEM_USIM2_DATAIN,
55 .ep_int = CARDEM_USIM2_INT,
Harald Welte2a6d3af2016-02-28 19:29:14 +010056 },
57#endif
58};
59
60static Usart *get_usart_by_chan(uint8_t uart_chan)
61{
62 switch (uart_chan) {
63 case 0:
64 return USART1;
65#ifdef CARDEMU_SECOND_UART
66 case 1:
67 return USART0;
68#endif
69 }
70 return NULL;
71}
72
73/***********************************************************************
74 * Call-Backs from card_emu.c
75 ***********************************************************************/
76
77/* call-back from card_emu.c to enable/disable transmit and/or receive */
78void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
79{
80 Usart *usart = get_usart_by_chan(uart_chan);
81 switch (rxtx) {
82 case ENABLE_TX:
Harald Welte9dbc46e2016-02-29 10:05:10 +010083 USART_DisableIt(usart, ~US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +010084 USART_SetReceiverEnabled(usart, 0);
Harald Welte8a416b12016-03-01 00:42:04 +010085 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
86 USART_EnableIt(usart, US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +010087 USART_SetTransmitterEnabled(usart, 1);
88 break;
89 case ENABLE_RX:
Harald Welte9dbc46e2016-02-29 10:05:10 +010090 USART_DisableIt(usart, ~US_IER_RXRDY);
Harald Welte8a416b12016-03-01 00:42:04 +010091 USART_SetTransmitterEnabled(usart, 0);
92 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
93 USART_EnableIt(usart, US_IER_RXRDY);
94 USART_SetReceiverEnabled(usart, 1);
Harald Welte2a6d3af2016-02-28 19:29:14 +010095 break;
96 case 0:
97 default:
98 USART_SetTransmitterEnabled(usart, 0);
99 USART_SetReceiverEnabled(usart, 0);
Harald Welte9dbc46e2016-02-29 10:05:10 +0100100 USART_DisableIt(usart, 0xFFFFFFFF);
Harald Welte8a416b12016-03-01 00:42:04 +0100101 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100102 break;
103 }
104}
105
106/* call-back from card_emu.c to transmit a byte */
107int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
108{
Harald Welte13e82022016-03-02 15:17:53 +0100109 Usart *usart = get_usart_by_chan(uart_chan);
110#if 0
Harald Welte2a6d3af2016-02-28 19:29:14 +0100111 Usart_info *ui = &usart_info[uart_chan];
112 ISO7816_SendChar(byte, ui);
Harald Welte13e82022016-03-02 15:17:53 +0100113#else
114 int i = 0;
115 while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
116 if (!(i%1000000)) {
117 printf("s: %x %02X", usart->US_CSR, usart->US_RHR & 0xFF);
118 usart->US_CR = US_CR_RSTTX;
119 usart->US_CR = US_CR_RSTRX;
120 }
121 }
122 usart->US_THR = byte;
123 TRACE_ERROR("Sx%02x\r\n", byte);
124#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +0100125 return 1;
126}
127
128
129/* FIXME: integrate this with actual irq handler */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100130void usart_irq_rx(uint8_t uart)
Harald Welte2a6d3af2016-02-28 19:29:14 +0100131{
Harald Weltec0bd7f02016-02-29 10:13:33 +0100132 Usart *usart = get_usart_by_chan(uart);
Harald Welte13e82022016-03-02 15:17:53 +0100133 struct cardem_inst *ci = &cardem_inst[0];
Harald Weltec0bd7f02016-02-29 10:13:33 +0100134 uint32_t csr;
135 uint8_t byte = 0;
136
Harald Welte2a6d3af2016-02-28 19:29:14 +0100137#ifdef CARDEMU_SECOND_UART
Harald Weltec0bd7f02016-02-29 10:13:33 +0100138 if (uart == 1)
Harald Welte13e82022016-03-02 15:17:53 +0100139 ci = &cardem_inst[1];
Harald Welte2a6d3af2016-02-28 19:29:14 +0100140#endif
Harald Weltec0bd7f02016-02-29 10:13:33 +0100141 csr = usart->US_CSR;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100142
Harald Weltec0bd7f02016-02-29 10:13:33 +0100143 if (csr & US_CSR_RXRDY) {
144 byte = (usart->US_RHR) & 0xFF;
Harald Welte13e82022016-03-02 15:17:53 +0100145 rbuf_write(&ci->rb, byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100146 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100147
Harald Welte12d4bdf2016-03-02 10:31:03 +0100148 if (csr & US_CSR_TXRDY) {
Harald Welte13e82022016-03-02 15:17:53 +0100149 if (card_emu_tx_byte(ci->ch) == 0)
Harald Welte12d4bdf2016-03-02 10:31:03 +0100150 USART_DisableIt(usart, US_IER_TXRDY);
151 }
152
Harald Welte2a6d3af2016-02-28 19:29:14 +0100153 if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
154 US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100155 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
156 TRACE_ERROR("e 0x%x st: 0x%x\n", byte, csr);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100157 }
158}
159
Harald Weltebd717682016-02-28 19:30:05 +0100160/* call-back from card_emu.c to change UART baud rate */
161int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
162{
163 int rc;
Harald Weltebd717682016-02-28 19:30:05 +0100164 Usart *usart = get_usart_by_chan(uart_chan);
165
Harald Welte99f62a62016-02-29 10:08:49 +0100166 usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
167 usart->US_FIDI = fidi & 0x3ff;
168 usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
169 return 0;
Harald Weltebd717682016-02-28 19:30:05 +0100170}
Harald Welte2a6d3af2016-02-28 19:29:14 +0100171
172/***********************************************************************
173 * Core USB / mainloop integration
174 ***********************************************************************/
175
Harald Weltec0bd7f02016-02-29 10:13:33 +0100176static void usim1_rst_irqhandler(const Pin *pPin)
177{
178 int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
Harald Welte13e82022016-03-02 15:17:53 +0100179 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100180}
181
182static void usim1_vcc_irqhandler(const Pin *pPin)
183{
184 int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
Harald Welte13e82022016-03-02 15:17:53 +0100185 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100186 /* FIXME do this for real */
Harald Welte13e82022016-03-02 15:17:53 +0100187 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100188}
189
Harald Welte13e82022016-03-02 15:17:53 +0100190#ifdef CARDEMU_SECOND_UART
191static void usim2_rst_irqhandler(const Pin *pPin)
192{
193 int active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
194 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
195}
196
197static void usim2_vcc_irqhandler(const Pin *pPin)
198{
199 int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
200 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
201 /* FIXME do this for real */
202 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
203}
204#endif
205
Harald Welte2a6d3af2016-02-28 19:29:14 +0100206/* executed once at system boot for each config */
207void mode_cardemu_configure(void)
208{
Harald Weltebd717682016-02-28 19:30:05 +0100209 TRACE_ENTRY();
Harald Welte2a6d3af2016-02-28 19:29:14 +0100210}
211
212/* called if config is activated */
213void mode_cardemu_init(void)
214{
Harald Welte13e82022016-03-02 15:17:53 +0100215 int i;
Harald Weltebd717682016-02-28 19:30:05 +0100216
Harald Welte13e82022016-03-02 15:17:53 +0100217 TRACE_ENTRY();
Harald Weltec0bd7f02016-02-29 10:13:33 +0100218
Harald Welte2a6d3af2016-02-28 19:29:14 +0100219 PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
220
Harald Welte13e82022016-03-02 15:17:53 +0100221 INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
222 rbuf_reset(&cardem_inst[0].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100223 PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
Harald Welte13e82022016-03-02 15:17:53 +0100224 ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100225 NVIC_EnableIRQ(USART1_IRQn);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100226 PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
227 PIO_EnableIt(&pin_usim1_rst);
228 PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
229 PIO_EnableIt(&pin_usim1_vcc);
Harald Welte13e82022016-03-02 15:17:53 +0100230 cardem_inst[0].ch = card_emu_init(0, 2, 0);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100231
232#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100233 INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
234 rbuf_reset(&cardem_inst[1].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100235 PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
Harald Welte13e82022016-03-02 15:17:53 +0100236 ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100237 NVIC_EnableIRQ(USART0_IRQn);
Harald Welte13e82022016-03-02 15:17:53 +0100238 PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
239 PIO_EnableIt(&pin_usim2_rst);
240 PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
241 PIO_EnableIt(&pin_usim2_vcc);
242 cardem_inst[1].ch = card_emu_init(1, 0, 1);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100243#endif
244}
245
246/* called if config is deactivated */
247void mode_cardemu_exit(void)
248{
Harald Weltebd717682016-02-28 19:30:05 +0100249 TRACE_ENTRY();
250
Harald Weltec0bd7f02016-02-29 10:13:33 +0100251 PIO_DisableIt(&pin_usim1_rst);
252 PIO_DisableIt(&pin_usim1_vcc);
253
Harald Welte2a6d3af2016-02-28 19:29:14 +0100254 NVIC_DisableIRQ(USART1_IRQn);
255 USART_SetTransmitterEnabled(USART1, 0);
256 USART_SetReceiverEnabled(USART1, 0);
257
258#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100259 PIO_DisableIt(&pin_usim2_rst);
260 PIO_DisableIt(&pin_usim2_vcc);
261
Harald Welte2a6d3af2016-02-28 19:29:14 +0100262 NVIC_DisableIRQ(USART0_IRQn);
263 USART_SetTransmitterEnabled(USART0, 0);
264 USART_SetReceiverEnabled(USART0, 0);
265#endif
266}
267
Harald Welteacae4122016-03-02 10:27:58 +0100268static int llist_count(struct llist_head *head)
269{
270 struct llist_head *list;
271 int i = 0;
272
273 llist_for_each(list, head)
274 i++;
275
276 return i;
277}
278
Harald Welteebb80ed2016-03-02 13:56:59 +0100279/* handle a single USB command as received from the USB host */
280static void dispatch_usb_command(struct req_ctx *rctx, struct card_handle *ch)
281{
282 struct cardemu_usb_msg_hdr *hdr;
Harald Welte06b27f62016-03-02 14:26:38 +0100283 struct cardemu_usb_msg_set_atr *atr;
Harald Welteebb80ed2016-03-02 13:56:59 +0100284 struct llist_head *queue;
285
286 hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
287 switch (hdr->msg_type) {
288 case CEMU_USB_MSGT_DT_TX_DATA:
289 queue = card_emu_get_uart_tx_queue(ch);
290 req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
291 llist_add_tail(&rctx->list, queue);
292 card_emu_have_new_uart_tx(ch);
293 break;
294 case CEMU_USB_MSGT_DT_SET_ATR:
Harald Welte06b27f62016-03-02 14:26:38 +0100295 atr = (struct cardemu_usb_msg_set_atr *) hdr;
296 card_emu_set_atr(ch, atr->atr, hdr->data_len);
297 llist_del(&rctx->list);
298 req_ctx_put(rctx);
299 break;
Harald Welteebb80ed2016-03-02 13:56:59 +0100300 case CEMU_USB_MSGT_DT_GET_STATS:
301 case CEMU_USB_MSGT_DT_GET_STATUS:
302 default:
303 /* FIXME */
304 break;
305 }
306}
307
308/* iterate over the queue of incoming USB commands and dispatch/execute
309 * them */
310static void process_any_usb_commands(struct llist_head *main_q, struct card_handle *ch)
311{
Harald Welte06b27f62016-03-02 14:26:38 +0100312 struct req_ctx *rctx, *tmp;
Harald Welteebb80ed2016-03-02 13:56:59 +0100313
Harald Welte06b27f62016-03-02 14:26:38 +0100314 llist_for_each_entry_safe(rctx, tmp, main_q, list)
Harald Welteebb80ed2016-03-02 13:56:59 +0100315 dispatch_usb_command(rctx, ch);
316}
317
Harald Welte2a6d3af2016-02-28 19:29:14 +0100318/* main loop function, called repeatedly */
319void mode_cardemu_run(void)
320{
Harald Welteacae4122016-03-02 10:27:58 +0100321 struct llist_head *queue;
Harald Welte13e82022016-03-02 15:17:53 +0100322 unsigned int i;
Harald Welteacae4122016-03-02 10:27:58 +0100323
Harald Welte13e82022016-03-02 15:17:53 +0100324 for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
325 struct cardem_inst *ci = &cardem_inst[i];
326
Harald Welte54cb3d02016-02-29 14:12:40 +0100327 /* drain the ring buffer from UART into card_emu */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100328 while (1) {
329 __disable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100330 if (rbuf_is_empty(&ci->rb)) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100331 __enable_irq();
332 break;
333 }
Harald Welte13e82022016-03-02 15:17:53 +0100334 uint8_t byte = rbuf_read(&ci->rb);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100335 __enable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100336 card_emu_process_rx_byte(ci->ch, byte);
Harald Welteacae4122016-03-02 10:27:58 +0100337 TRACE_ERROR("Rx%02x\r\n", byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100338 }
Harald Welteacae4122016-03-02 10:27:58 +0100339
Harald Welte13e82022016-03-02 15:17:53 +0100340 queue = card_emu_get_usb_tx_queue(ci->ch);
Harald Welteacae4122016-03-02 10:27:58 +0100341 int usb_pending = llist_count(queue);
Harald Welte13e82022016-03-02 15:17:53 +0100342 if (usb_pending != ci->usb_pending_old) {
Harald Welteacae4122016-03-02 10:27:58 +0100343// printf("usb_pending=%d\r\n", usb_pending);
Harald Welte13e82022016-03-02 15:17:53 +0100344 ci->usb_pending_old = usb_pending;
Harald Welteacae4122016-03-02 10:27:58 +0100345 }
Harald Welte13e82022016-03-02 15:17:53 +0100346 usb_refill_to_host(queue, ci->ep_in);
Harald Welteacae4122016-03-02 10:27:58 +0100347
Harald Welteebb80ed2016-03-02 13:56:59 +0100348 /* ensure we can handle incoming USB messages from the
349 * host */
Harald Welte13e82022016-03-02 15:17:53 +0100350 queue = &ci->usb_out_queue;
351 usb_refill_from_host(queue, ci->ep_out);
352 process_any_usb_commands(queue, ci->ch);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100353 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100354
Harald Welte2a6d3af2016-02-28 19:29:14 +0100355}