blob: 82127e17c9d963bbe68f0e73157346e03e7cb51d [file] [log] [blame]
Harald Welte53079bb2016-03-20 14:58:35 +01001//#define TRACE_LEVEL 6
Harald Welte7abdb512016-03-03 17:48:32 +01002
Harald Welte2a6d3af2016-02-28 19:29:14 +01003#include "board.h"
Harald Welte16055642016-03-03 11:02:45 +01004#include "simtrace.h"
5#include "ringbuffer.h"
Harald Welte2a6d3af2016-02-28 19:29:14 +01006#include "card_emu.h"
Harald Weltebd717682016-02-28 19:30:05 +01007#include "iso7816_fidi.h"
Harald Welte54cb3d02016-02-29 14:12:40 +01008#include "utils.h"
Harald Welteacae4122016-03-02 10:27:58 +01009#include "linuxlist.h"
Harald Welte9f240b62016-03-18 10:32:56 +010010#include "llist_irqsafe.h"
Harald Welteebb80ed2016-03-02 13:56:59 +010011#include "req_ctx.h"
12#include "cardemu_prot.h"
Harald Weltebd717682016-02-28 19:30:05 +010013
14#define TRACE_ENTRY() TRACE_DEBUG("%s entering\n", __func__)
Harald Welte2a6d3af2016-02-28 19:29:14 +010015
16static const Pin pins_cardsim[] = PINS_CARDSIM;
17
18/* UART pins */
19static const Pin pins_usim1[] = {PINS_USIM1};
20static const Pin pin_usim1_rst = PIN_USIM1_nRST;
21static const Pin pin_usim1_vcc = PIN_USIM1_VCC;
22
23#ifdef CARDEMU_SECOND_UART
Harald Welte6dcacf32016-03-19 14:01:31 +010024static const Pin pins_usim2[] = {PINS_USIM2};
Harald Welte2a6d3af2016-02-28 19:29:14 +010025static const Pin pin_usim2_rst = PIN_USIM2_nRST;
26static const Pin pin_usim2_vcc = PIN_USIM2_VCC;
27#endif
28
Harald Welte13e82022016-03-02 15:17:53 +010029struct cardem_inst {
30 struct card_handle *ch;
31 struct llist_head usb_out_queue;
32 struct ringbuf rb;
33 struct Usart_info usart_info;
34 int usb_pending_old;
35 uint8_t ep_out;
36 uint8_t ep_in;
37 uint8_t ep_int;
Harald Welte0eaa9922016-03-04 03:03:49 +010038 const Pin pin_insert;
Harald Welte07872b62016-03-20 11:45:36 +010039 uint32_t vcc_uv;
40 uint32_t vcc_uv_last;
Harald Welte13e82022016-03-02 15:17:53 +010041};
Harald Welte2a6d3af2016-02-28 19:29:14 +010042
Harald Welte13e82022016-03-02 15:17:53 +010043static struct cardem_inst cardem_inst[] = {
Harald Welte2a6d3af2016-02-28 19:29:14 +010044 {
Harald Welte13e82022016-03-02 15:17:53 +010045 .usart_info = {
46 .base = USART1,
47 .id = ID_USART1,
48 .state = USART_RCV
49 },
50 .ep_out = PHONE_DATAOUT,
51 .ep_in = PHONE_DATAIN,
52 .ep_int = PHONE_INT,
Harald Welte0eaa9922016-03-04 03:03:49 +010053 .pin_insert = PIN_SET_USIM1_PRES,
Harald Welte2a6d3af2016-02-28 19:29:14 +010054 },
55#ifdef CARDEMU_SECOND_UART
56 {
Harald Welte13e82022016-03-02 15:17:53 +010057 .usart_info = {
58 .base = USART0,
59 .id = ID_USART0,
60 .state = USART_RCV
61 },
62 .ep_out = CARDEM_USIM2_DATAOUT,
63 .ep_in = CARDEM_USIM2_DATAIN,
64 .ep_int = CARDEM_USIM2_INT,
Harald Welte0eaa9922016-03-04 03:03:49 +010065 .pin_insert = PIN_SET_USIM2_PRES,
Harald Welte2a6d3af2016-02-28 19:29:14 +010066 },
67#endif
68};
69
70static Usart *get_usart_by_chan(uint8_t uart_chan)
71{
72 switch (uart_chan) {
73 case 0:
74 return USART1;
75#ifdef CARDEMU_SECOND_UART
76 case 1:
77 return USART0;
78#endif
79 }
80 return NULL;
81}
82
83/***********************************************************************
84 * Call-Backs from card_emu.c
85 ***********************************************************************/
86
Harald Weltec8beefb2016-03-20 14:40:47 +010087static void wait_tx_idle(Usart *usart)
88{
89 int i = 1;
90
91 /* wait until last char has been fully transmitted */
92 while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) {
93 if (!(i%1000000)) {
94 TRACE_ERROR("s: %x \r\n", usart->US_CSR);
95 }
96 i++;
97 }
98}
99
Harald Weltec58bba02016-03-20 14:57:53 +0100100void card_emu_uart_wait_tx_idle(uint8_t uart_chan)
101{
102 Usart *usart = get_usart_by_chan(uart_chan);
103 wait_tx_idle(usart);
104}
105
Harald Welte2a6d3af2016-02-28 19:29:14 +0100106/* call-back from card_emu.c to enable/disable transmit and/or receive */
107void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
108{
109 Usart *usart = get_usart_by_chan(uart_chan);
110 switch (rxtx) {
111 case ENABLE_TX:
Harald Welte9dbc46e2016-02-29 10:05:10 +0100112 USART_DisableIt(usart, ~US_IER_TXRDY);
Harald Weltec8beefb2016-03-20 14:40:47 +0100113 /* as irritating as it is, we actually want to keep the
114 * receiver enabled during transmit */
115 USART_SetReceiverEnabled(usart, 1);
Harald Welte8a416b12016-03-01 00:42:04 +0100116 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
117 USART_EnableIt(usart, US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100118 USART_SetTransmitterEnabled(usart, 1);
119 break;
120 case ENABLE_RX:
Harald Welte9dbc46e2016-02-29 10:05:10 +0100121 USART_DisableIt(usart, ~US_IER_RXRDY);
Harald Weltec8beefb2016-03-20 14:40:47 +0100122 /* as irritating as it is, we actually want to keep the
123 * transmitter enabled during receive */
124 USART_SetTransmitterEnabled(usart, 1);
125 wait_tx_idle(usart);
Harald Welte8a416b12016-03-01 00:42:04 +0100126 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
127 USART_EnableIt(usart, US_IER_RXRDY);
128 USART_SetReceiverEnabled(usart, 1);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100129 break;
130 case 0:
131 default:
132 USART_SetTransmitterEnabled(usart, 0);
133 USART_SetReceiverEnabled(usart, 0);
Harald Welte9dbc46e2016-02-29 10:05:10 +0100134 USART_DisableIt(usart, 0xFFFFFFFF);
Harald Welte8a416b12016-03-01 00:42:04 +0100135 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100136 break;
137 }
138}
139
140/* call-back from card_emu.c to transmit a byte */
141int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
142{
Harald Welte13e82022016-03-02 15:17:53 +0100143 Usart *usart = get_usart_by_chan(uart_chan);
144#if 0
Harald Welte2a6d3af2016-02-28 19:29:14 +0100145 Usart_info *ui = &usart_info[uart_chan];
146 ISO7816_SendChar(byte, ui);
Harald Welte13e82022016-03-02 15:17:53 +0100147#else
Harald Welte53079bb2016-03-20 14:58:35 +0100148 int i = 1;
Harald Welte13e82022016-03-02 15:17:53 +0100149 while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
150 if (!(i%1000000)) {
Harald Welte53079bb2016-03-20 14:58:35 +0100151 TRACE_ERROR("s: %x %02X\r\n",
152 usart->US_CSR, usart->US_RHR & 0xFF);
Harald Welte13e82022016-03-02 15:17:53 +0100153 usart->US_CR = US_CR_RSTTX;
154 usart->US_CR = US_CR_RSTRX;
155 }
Harald Welte53079bb2016-03-20 14:58:35 +0100156 i++;
Harald Welte13e82022016-03-02 15:17:53 +0100157 }
158 usart->US_THR = byte;
Harald Welte53079bb2016-03-20 14:58:35 +0100159 //TRACE_ERROR("Sx%02x\r\n", byte);
Harald Welte13e82022016-03-02 15:17:53 +0100160#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +0100161 return 1;
162}
163
164
165/* FIXME: integrate this with actual irq handler */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100166void usart_irq_rx(uint8_t uart)
Harald Welte2a6d3af2016-02-28 19:29:14 +0100167{
Harald Weltec0bd7f02016-02-29 10:13:33 +0100168 Usart *usart = get_usart_by_chan(uart);
Harald Welte13e82022016-03-02 15:17:53 +0100169 struct cardem_inst *ci = &cardem_inst[0];
Harald Weltec0bd7f02016-02-29 10:13:33 +0100170 uint32_t csr;
171 uint8_t byte = 0;
172
Harald Welte2a6d3af2016-02-28 19:29:14 +0100173#ifdef CARDEMU_SECOND_UART
Harald Weltec0bd7f02016-02-29 10:13:33 +0100174 if (uart == 1)
Harald Welte13e82022016-03-02 15:17:53 +0100175 ci = &cardem_inst[1];
Harald Welte2a6d3af2016-02-28 19:29:14 +0100176#endif
Harald Welteda15ca02016-03-17 21:14:04 +0100177 csr = usart->US_CSR & usart->US_IMR;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100178
Harald Weltec0bd7f02016-02-29 10:13:33 +0100179 if (csr & US_CSR_RXRDY) {
180 byte = (usart->US_RHR) & 0xFF;
Harald Welte13e82022016-03-02 15:17:53 +0100181 rbuf_write(&ci->rb, byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100182 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100183
Harald Welte12d4bdf2016-03-02 10:31:03 +0100184 if (csr & US_CSR_TXRDY) {
Harald Welte13e82022016-03-02 15:17:53 +0100185 if (card_emu_tx_byte(ci->ch) == 0)
Harald Welte12d4bdf2016-03-02 10:31:03 +0100186 USART_DisableIt(usart, US_IER_TXRDY);
187 }
188
Harald Welte2a6d3af2016-02-28 19:29:14 +0100189 if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
190 US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100191 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
192 TRACE_ERROR("e 0x%x st: 0x%x\n", byte, csr);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100193 }
194}
195
Harald Weltebd717682016-02-28 19:30:05 +0100196/* call-back from card_emu.c to change UART baud rate */
197int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
198{
199 int rc;
Harald Weltebd717682016-02-28 19:30:05 +0100200 Usart *usart = get_usart_by_chan(uart_chan);
201
Harald Welte99f62a62016-02-29 10:08:49 +0100202 usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
203 usart->US_FIDI = fidi & 0x3ff;
204 usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
205 return 0;
Harald Weltebd717682016-02-28 19:30:05 +0100206}
Harald Welte2a6d3af2016-02-28 19:29:14 +0100207
208/***********************************************************************
Harald Welte419eb8a2016-03-20 10:04:03 +0100209 * ADC for VCC voltage detection
210 ***********************************************************************/
211
Harald Welte07872b62016-03-20 11:45:36 +0100212#ifdef DETECT_VCC_BY_ADC
213
214static int adc_triggered = 0;
215
Harald Welte419eb8a2016-03-20 10:04:03 +0100216static int card_vcc_adc_init(void)
217{
Harald Welte07872b62016-03-20 11:45:36 +0100218 PMC_EnablePeripheral(ID_ADC);
219
Harald Welte419eb8a2016-03-20 10:04:03 +0100220 ADC->ADC_CR |= ADC_CR_SWRST;
Harald Welte07872b62016-03-20 11:45:36 +0100221 /* Errata Work-Around to clear EOCx flags */
222 {
223 volatile uint32_t foo;
224 int i;
225 for (i = 0; i < 16; i++)
226 foo = ADC->ADC_CDR[i];
227 }
228
229 /* Initialize ADC for AD7 / AD6, fADC=48/24=2MHz */
Harald Welte419eb8a2016-03-20 10:04:03 +0100230 ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_LOWRES_BITS_12 |
231 ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF |
Harald Welte07872b62016-03-20 11:45:36 +0100232 ADC_MR_FREERUN_OFF | ADC_MR_PRESCAL(23) |
233 ADC_MR_STARTUP_SUT8 | ADC_MR_SETTLING(3) |
234 ADC_MR_ANACH_NONE | ADC_MR_TRACKTIM(4) |
Harald Welte419eb8a2016-03-20 10:04:03 +0100235 ADC_MR_TRANSFER(1) | ADC_MR_USEQ_NUM_ORDER;
236 /* enable AD6 + AD7 channels */
Harald Welte07872b62016-03-20 11:45:36 +0100237 ADC->ADC_CHER = ADC_CHER_CH7;
238 ADC->ADC_IER = ADC_IER_EOC7;
239#ifdef CARDEMU_SECOND_UART
240 ADC->ADC_CHER |= ADC_CHER_CH6;
241 ADC->ADC_IER |= ADC_IER_EOC6;
242#endif
243 NVIC_EnableIRQ(ADC_IRQn);
Harald Welte419eb8a2016-03-20 10:04:03 +0100244 ADC->ADC_CR |= ADC_CR_START;
Harald Welte07872b62016-03-20 11:45:36 +0100245
246 return 0;
Harald Welte419eb8a2016-03-20 10:04:03 +0100247}
248
Harald Welte07872b62016-03-20 11:45:36 +0100249#define UV_PER_LSB ((3300 * 1000) / 4096)
250#define VCC_UV_THRESH_1V8 1500000
251#define VCC_UV_THRESH_3V 2800000
252
253static void process_vcc_adc(struct cardem_inst *ci)
Harald Welte419eb8a2016-03-20 10:04:03 +0100254{
Harald Welte07872b62016-03-20 11:45:36 +0100255 if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
256 ci->vcc_uv_last < VCC_UV_THRESH_3V) {
257 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1);
258 /* FIXME do this for real */
259 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1);
260 } else if (ci->vcc_uv < VCC_UV_THRESH_3V &&
261 ci->vcc_uv_last >= VCC_UV_THRESH_3V) {
262 /* FIXME do this for real */
263 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0);
264 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0);
Harald Welte419eb8a2016-03-20 10:04:03 +0100265 }
Harald Welte07872b62016-03-20 11:45:36 +0100266 ci->vcc_uv_last = ci->vcc_uv;
267}
268
269static uint32_t adc2uv(uint16_t adc)
270{
271 uint32_t uv = (uint32_t) adc * UV_PER_LSB;
272}
273
274void ADC_IrqHandler(void)
275{
276#ifdef CARDEMU_SECOND_UART
277 if (ADC->ADC_ISR & ADC_ISR_EOC6) {
278 uint16_t val = ADC->ADC_CDR[6] & 0xFFF;
279 cardem_inst[1].vcc_uv = adc2uv(val);
280 process_vcc_adc(&cardem_inst[1]);
281 ADC->ADC_CR |= ADC_CR_START;
282 }
283#endif
Harald Welte419eb8a2016-03-20 10:04:03 +0100284
285 if (ADC->ADC_ISR & ADC_ISR_EOC7) {
Harald Welte07872b62016-03-20 11:45:36 +0100286 uint16_t val = ADC->ADC_CDR[7] & 0xFFF;
287 cardem_inst[0].vcc_uv = adc2uv(val);
288 process_vcc_adc(&cardem_inst[0]);
289 ADC->ADC_CR |= ADC_CR_START;
Harald Welte419eb8a2016-03-20 10:04:03 +0100290 }
291}
Harald Welte07872b62016-03-20 11:45:36 +0100292#endif /* DETECT_VCC_BY_ADC */
Harald Welte419eb8a2016-03-20 10:04:03 +0100293
294/***********************************************************************
Harald Welte2a6d3af2016-02-28 19:29:14 +0100295 * Core USB / mainloop integration
296 ***********************************************************************/
297
Harald Weltec0bd7f02016-02-29 10:13:33 +0100298static void usim1_rst_irqhandler(const Pin *pPin)
299{
300 int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
Harald Welte13e82022016-03-02 15:17:53 +0100301 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100302}
303
Harald Welte07872b62016-03-20 11:45:36 +0100304#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100305static void usim1_vcc_irqhandler(const Pin *pPin)
306{
307 int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
Harald Welte13e82022016-03-02 15:17:53 +0100308 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100309 /* FIXME do this for real */
Harald Welte13e82022016-03-02 15:17:53 +0100310 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100311}
Harald Welte07872b62016-03-20 11:45:36 +0100312#endif /* !DETECT_VCC_BY_ADC */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100313
Harald Welte13e82022016-03-02 15:17:53 +0100314#ifdef CARDEMU_SECOND_UART
315static void usim2_rst_irqhandler(const Pin *pPin)
316{
317 int active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
318 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
319}
320
Harald Welte07872b62016-03-20 11:45:36 +0100321#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100322static void usim2_vcc_irqhandler(const Pin *pPin)
323{
324 int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
325 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
326 /* FIXME do this for real */
327 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
328}
Harald Welte07872b62016-03-20 11:45:36 +0100329#endif /* !DETECT_VCC_BY_ADC */
330#endif /* CARDEMU_SECOND_UART */
Harald Welte13e82022016-03-02 15:17:53 +0100331
Harald Welte2a6d3af2016-02-28 19:29:14 +0100332/* executed once at system boot for each config */
333void mode_cardemu_configure(void)
334{
Harald Weltebd717682016-02-28 19:30:05 +0100335 TRACE_ENTRY();
Harald Welte2a6d3af2016-02-28 19:29:14 +0100336}
337
338/* called if config is activated */
339void mode_cardemu_init(void)
340{
Harald Welte13e82022016-03-02 15:17:53 +0100341 int i;
Harald Weltebd717682016-02-28 19:30:05 +0100342
Harald Welte13e82022016-03-02 15:17:53 +0100343 TRACE_ENTRY();
Harald Weltec0bd7f02016-02-29 10:13:33 +0100344
Harald Welte2a6d3af2016-02-28 19:29:14 +0100345 PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
Harald Welte07872b62016-03-20 11:45:36 +0100346#ifdef DETECT_VCC_BY_ADC
347 card_vcc_adc_init();
348#endif /* DETECT_VCC_BY_ADC */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100349
Harald Welte13e82022016-03-02 15:17:53 +0100350 INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
351 rbuf_reset(&cardem_inst[0].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100352 PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
Harald Welte13e82022016-03-02 15:17:53 +0100353 ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100354 NVIC_EnableIRQ(USART1_IRQn);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100355 PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
356 PIO_EnableIt(&pin_usim1_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100357#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100358 PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
359 PIO_EnableIt(&pin_usim1_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100360#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100361 cardem_inst[0].ch = card_emu_init(0, 2, 0);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100362
363#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100364 INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
365 rbuf_reset(&cardem_inst[1].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100366 PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
Harald Welte13e82022016-03-02 15:17:53 +0100367 ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100368 NVIC_EnableIRQ(USART0_IRQn);
Harald Welte13e82022016-03-02 15:17:53 +0100369 PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
370 PIO_EnableIt(&pin_usim2_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100371#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100372 PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
373 PIO_EnableIt(&pin_usim2_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100374#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100375 cardem_inst[1].ch = card_emu_init(1, 0, 1);
Harald Welte07872b62016-03-20 11:45:36 +0100376#endif /* CARDEMU_SECOND_UART */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100377}
378
379/* called if config is deactivated */
380void mode_cardemu_exit(void)
381{
Harald Weltebd717682016-02-28 19:30:05 +0100382 TRACE_ENTRY();
383
Harald Welte7abdb512016-03-03 17:48:32 +0100384 /* FIXME: stop tc_fdt */
385 /* FIXME: release all rctx, unlink them from any queue */
386
Harald Weltec0bd7f02016-02-29 10:13:33 +0100387 PIO_DisableIt(&pin_usim1_rst);
388 PIO_DisableIt(&pin_usim1_vcc);
389
Harald Welte2a6d3af2016-02-28 19:29:14 +0100390 NVIC_DisableIRQ(USART1_IRQn);
391 USART_SetTransmitterEnabled(USART1, 0);
392 USART_SetReceiverEnabled(USART1, 0);
393
394#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100395 PIO_DisableIt(&pin_usim2_rst);
396 PIO_DisableIt(&pin_usim2_vcc);
397
Harald Welte2a6d3af2016-02-28 19:29:14 +0100398 NVIC_DisableIRQ(USART0_IRQn);
399 USART_SetTransmitterEnabled(USART0, 0);
400 USART_SetReceiverEnabled(USART0, 0);
401#endif
402}
403
Harald Welteacae4122016-03-02 10:27:58 +0100404static int llist_count(struct llist_head *head)
405{
406 struct llist_head *list;
407 int i = 0;
408
409 llist_for_each(list, head)
410 i++;
411
412 return i;
413}
414
Harald Welteebb80ed2016-03-02 13:56:59 +0100415/* handle a single USB command as received from the USB host */
Harald Welte0eaa9922016-03-04 03:03:49 +0100416static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100417{
418 struct cardemu_usb_msg_hdr *hdr;
Harald Welte06b27f62016-03-02 14:26:38 +0100419 struct cardemu_usb_msg_set_atr *atr;
Harald Welte0eaa9922016-03-04 03:03:49 +0100420 struct cardemu_usb_msg_cardinsert *cardins;
Harald Welteebb80ed2016-03-02 13:56:59 +0100421 struct llist_head *queue;
422
423 hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
424 switch (hdr->msg_type) {
425 case CEMU_USB_MSGT_DT_TX_DATA:
Harald Welte0eaa9922016-03-04 03:03:49 +0100426 queue = card_emu_get_uart_tx_queue(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100427 req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
428 llist_add_tail(&rctx->list, queue);
Harald Welte0eaa9922016-03-04 03:03:49 +0100429 card_emu_have_new_uart_tx(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100430 break;
431 case CEMU_USB_MSGT_DT_SET_ATR:
Harald Welte06b27f62016-03-02 14:26:38 +0100432 atr = (struct cardemu_usb_msg_set_atr *) hdr;
Harald Welted295b922016-03-18 21:01:36 +0100433 card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
Harald Welte06b27f62016-03-02 14:26:38 +0100434 req_ctx_put(rctx);
435 break;
Harald Welte0eaa9922016-03-04 03:03:49 +0100436 case CEMU_USB_MSGT_DT_CARDINSERT:
437 cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
438 if (cardins->card_insert)
439 PIO_Set(&ci->pin_insert);
440 else
441 PIO_Clear(&ci->pin_insert);
Harald Welte5820ea92016-03-16 22:12:00 +0100442 req_ctx_put(rctx);
Harald Welte0eaa9922016-03-04 03:03:49 +0100443 break;
Harald Welteebb80ed2016-03-02 13:56:59 +0100444 case CEMU_USB_MSGT_DT_GET_STATUS:
Harald Welteff160652016-03-19 21:59:06 +0100445 card_emu_report_status(ci->ch);
446 break;
447 case CEMU_USB_MSGT_DT_GET_STATS:
Harald Welteebb80ed2016-03-02 13:56:59 +0100448 default:
449 /* FIXME */
Harald Welte5820ea92016-03-16 22:12:00 +0100450 req_ctx_put(rctx);
Harald Welteebb80ed2016-03-02 13:56:59 +0100451 break;
452 }
453}
454
Harald Welteb26d0032016-03-19 13:33:02 +0100455static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci)
456{
457 struct req_ctx *segm;
458 struct cardemu_usb_msg_hdr *mh;
459 int i = 0;
460
461 /* check if we have multiple concatenated commands in
462 * one message. USB endpoints are streams that don't
463 * preserve the message boundaries */
464 mh = (struct cardemu_usb_msg_hdr *) rctx->data;
Harald Welteb26d0032016-03-19 13:33:02 +0100465 if (mh->msg_len == rctx->tot_len) {
466 /* fast path: only one message in buffer */
467 dispatch_usb_command(rctx, ci);
468 return;
469 }
470
471 /* slow path: iterate over list of messages, allocating one new
472 * reqe_ctx per segment */
473 for (mh = (struct cardemu_usb_msg_hdr *) rctx->data;
474 (uint8_t *)mh < rctx->data + rctx->tot_len;
475 mh = (struct cardemu_usb_msg_hdr * ) ((uint8_t *)mh + mh->msg_len)) {
Harald Welteb26d0032016-03-19 13:33:02 +0100476 segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING);
477 if (!segm) {
478 TRACE_ERROR("ENOMEM during rctx segmentation\r\n");
479 break;
480 }
481 segm->idx = 0;
482 segm->tot_len = mh->msg_len;
483 memcpy(segm->data, mh, segm->tot_len);
484 dispatch_usb_command(segm, ci);
485 i++;
486 }
487
488 /* release the master req_ctx, as all segments have been
489 * processed now */
490 req_ctx_put(rctx);
491}
492
Harald Welteebb80ed2016-03-02 13:56:59 +0100493/* iterate over the queue of incoming USB commands and dispatch/execute
494 * them */
Harald Welte9f240b62016-03-18 10:32:56 +0100495static void process_any_usb_commands(struct llist_head *main_q,
496 struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100497{
Harald Welte9f240b62016-03-18 10:32:56 +0100498 struct llist_head *lh;
499 struct req_ctx *rctx;
500 int i;
Harald Welteebb80ed2016-03-02 13:56:59 +0100501
Harald Welte9f240b62016-03-18 10:32:56 +0100502 /* limit the number of iterations to 10, to ensure we don't get
503 * stuck here without returning to main loop processing */
504 for (i = 0; i < 10; i++) {
505 /* de-queue the list head in an irq-safe way */
506 lh = llist_head_dequeue_irqsafe(main_q);
507 if (!lh)
508 break;
509 rctx = llist_entry(lh, struct req_ctx, list);
Harald Welteb26d0032016-03-19 13:33:02 +0100510 dispatch_received_rctx(rctx, ci);
Harald Welte5820ea92016-03-16 22:12:00 +0100511 }
Harald Welteebb80ed2016-03-02 13:56:59 +0100512}
513
Harald Welte2a6d3af2016-02-28 19:29:14 +0100514/* main loop function, called repeatedly */
515void mode_cardemu_run(void)
516{
Harald Welteacae4122016-03-02 10:27:58 +0100517 struct llist_head *queue;
Harald Welte13e82022016-03-02 15:17:53 +0100518 unsigned int i;
Harald Welteacae4122016-03-02 10:27:58 +0100519
Harald Welte13e82022016-03-02 15:17:53 +0100520 for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
521 struct cardem_inst *ci = &cardem_inst[i];
522
Harald Welte54cb3d02016-02-29 14:12:40 +0100523 /* drain the ring buffer from UART into card_emu */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100524 while (1) {
525 __disable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100526 if (rbuf_is_empty(&ci->rb)) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100527 __enable_irq();
528 break;
529 }
Harald Welte13e82022016-03-02 15:17:53 +0100530 uint8_t byte = rbuf_read(&ci->rb);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100531 __enable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100532 card_emu_process_rx_byte(ci->ch, byte);
Harald Welte53079bb2016-03-20 14:58:35 +0100533 //TRACE_ERROR("Rx%02x\r\n", byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100534 }
Harald Welteacae4122016-03-02 10:27:58 +0100535
Harald Welte13e82022016-03-02 15:17:53 +0100536 queue = card_emu_get_usb_tx_queue(ci->ch);
Harald Welteacae4122016-03-02 10:27:58 +0100537 int usb_pending = llist_count(queue);
Harald Welte13e82022016-03-02 15:17:53 +0100538 if (usb_pending != ci->usb_pending_old) {
Harald Welte53079bb2016-03-20 14:58:35 +0100539 TRACE_DEBUG("usb_pending=%d\r\n", usb_pending);
Harald Welte13e82022016-03-02 15:17:53 +0100540 ci->usb_pending_old = usb_pending;
Harald Welteacae4122016-03-02 10:27:58 +0100541 }
Harald Welte13e82022016-03-02 15:17:53 +0100542 usb_refill_to_host(queue, ci->ep_in);
Harald Welteacae4122016-03-02 10:27:58 +0100543
Harald Welteebb80ed2016-03-02 13:56:59 +0100544 /* ensure we can handle incoming USB messages from the
545 * host */
Harald Welte13e82022016-03-02 15:17:53 +0100546 queue = &ci->usb_out_queue;
547 usb_refill_from_host(queue, ci->ep_out);
Harald Welte0eaa9922016-03-04 03:03:49 +0100548 process_any_usb_commands(queue, ci);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100549 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100550}