blob: c0127017833780a2f4fb538c191659473d26b984 [file] [log] [blame]
Harald Welte7abdb512016-03-03 17:48:32 +01001#define TRACE_LEVEL 6
2
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
87/* call-back from card_emu.c to enable/disable transmit and/or receive */
88void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
89{
90 Usart *usart = get_usart_by_chan(uart_chan);
91 switch (rxtx) {
92 case ENABLE_TX:
Harald Welte9dbc46e2016-02-29 10:05:10 +010093 USART_DisableIt(usart, ~US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +010094 USART_SetReceiverEnabled(usart, 0);
Harald Welte8a416b12016-03-01 00:42:04 +010095 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
96 USART_EnableIt(usart, US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +010097 USART_SetTransmitterEnabled(usart, 1);
98 break;
99 case ENABLE_RX:
Harald Welte9dbc46e2016-02-29 10:05:10 +0100100 USART_DisableIt(usart, ~US_IER_RXRDY);
Harald Welte8a416b12016-03-01 00:42:04 +0100101 USART_SetTransmitterEnabled(usart, 0);
102 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
103 USART_EnableIt(usart, US_IER_RXRDY);
104 USART_SetReceiverEnabled(usart, 1);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100105 break;
106 case 0:
107 default:
108 USART_SetTransmitterEnabled(usart, 0);
109 USART_SetReceiverEnabled(usart, 0);
Harald Welte9dbc46e2016-02-29 10:05:10 +0100110 USART_DisableIt(usart, 0xFFFFFFFF);
Harald Welte8a416b12016-03-01 00:42:04 +0100111 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100112 break;
113 }
114}
115
116/* call-back from card_emu.c to transmit a byte */
117int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
118{
Harald Welte13e82022016-03-02 15:17:53 +0100119 Usart *usart = get_usart_by_chan(uart_chan);
120#if 0
Harald Welte2a6d3af2016-02-28 19:29:14 +0100121 Usart_info *ui = &usart_info[uart_chan];
122 ISO7816_SendChar(byte, ui);
Harald Welte13e82022016-03-02 15:17:53 +0100123#else
124 int i = 0;
125 while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
126 if (!(i%1000000)) {
127 printf("s: %x %02X", usart->US_CSR, usart->US_RHR & 0xFF);
128 usart->US_CR = US_CR_RSTTX;
129 usart->US_CR = US_CR_RSTRX;
130 }
131 }
132 usart->US_THR = byte;
133 TRACE_ERROR("Sx%02x\r\n", byte);
134#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +0100135 return 1;
136}
137
138
139/* FIXME: integrate this with actual irq handler */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100140void usart_irq_rx(uint8_t uart)
Harald Welte2a6d3af2016-02-28 19:29:14 +0100141{
Harald Weltec0bd7f02016-02-29 10:13:33 +0100142 Usart *usart = get_usart_by_chan(uart);
Harald Welte13e82022016-03-02 15:17:53 +0100143 struct cardem_inst *ci = &cardem_inst[0];
Harald Weltec0bd7f02016-02-29 10:13:33 +0100144 uint32_t csr;
145 uint8_t byte = 0;
146
Harald Welte2a6d3af2016-02-28 19:29:14 +0100147#ifdef CARDEMU_SECOND_UART
Harald Weltec0bd7f02016-02-29 10:13:33 +0100148 if (uart == 1)
Harald Welte13e82022016-03-02 15:17:53 +0100149 ci = &cardem_inst[1];
Harald Welte2a6d3af2016-02-28 19:29:14 +0100150#endif
Harald Welteda15ca02016-03-17 21:14:04 +0100151 csr = usart->US_CSR & usart->US_IMR;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100152
Harald Weltec0bd7f02016-02-29 10:13:33 +0100153 if (csr & US_CSR_RXRDY) {
154 byte = (usart->US_RHR) & 0xFF;
Harald Welte13e82022016-03-02 15:17:53 +0100155 rbuf_write(&ci->rb, byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100156 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100157
Harald Welte12d4bdf2016-03-02 10:31:03 +0100158 if (csr & US_CSR_TXRDY) {
Harald Welte13e82022016-03-02 15:17:53 +0100159 if (card_emu_tx_byte(ci->ch) == 0)
Harald Welte12d4bdf2016-03-02 10:31:03 +0100160 USART_DisableIt(usart, US_IER_TXRDY);
161 }
162
Harald Welte2a6d3af2016-02-28 19:29:14 +0100163 if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
164 US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100165 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
166 TRACE_ERROR("e 0x%x st: 0x%x\n", byte, csr);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100167 }
168}
169
Harald Weltebd717682016-02-28 19:30:05 +0100170/* call-back from card_emu.c to change UART baud rate */
171int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
172{
173 int rc;
Harald Weltebd717682016-02-28 19:30:05 +0100174 Usart *usart = get_usart_by_chan(uart_chan);
175
Harald Welte99f62a62016-02-29 10:08:49 +0100176 usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
177 usart->US_FIDI = fidi & 0x3ff;
178 usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
179 return 0;
Harald Weltebd717682016-02-28 19:30:05 +0100180}
Harald Welte2a6d3af2016-02-28 19:29:14 +0100181
182/***********************************************************************
Harald Welte419eb8a2016-03-20 10:04:03 +0100183 * ADC for VCC voltage detection
184 ***********************************************************************/
185
Harald Welte07872b62016-03-20 11:45:36 +0100186#ifdef DETECT_VCC_BY_ADC
187
188static int adc_triggered = 0;
189
Harald Welte419eb8a2016-03-20 10:04:03 +0100190static int card_vcc_adc_init(void)
191{
Harald Welte07872b62016-03-20 11:45:36 +0100192 PMC_EnablePeripheral(ID_ADC);
193
Harald Welte419eb8a2016-03-20 10:04:03 +0100194 ADC->ADC_CR |= ADC_CR_SWRST;
Harald Welte07872b62016-03-20 11:45:36 +0100195 /* Errata Work-Around to clear EOCx flags */
196 {
197 volatile uint32_t foo;
198 int i;
199 for (i = 0; i < 16; i++)
200 foo = ADC->ADC_CDR[i];
201 }
202
203 /* Initialize ADC for AD7 / AD6, fADC=48/24=2MHz */
Harald Welte419eb8a2016-03-20 10:04:03 +0100204 ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_LOWRES_BITS_12 |
205 ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF |
Harald Welte07872b62016-03-20 11:45:36 +0100206 ADC_MR_FREERUN_OFF | ADC_MR_PRESCAL(23) |
207 ADC_MR_STARTUP_SUT8 | ADC_MR_SETTLING(3) |
208 ADC_MR_ANACH_NONE | ADC_MR_TRACKTIM(4) |
Harald Welte419eb8a2016-03-20 10:04:03 +0100209 ADC_MR_TRANSFER(1) | ADC_MR_USEQ_NUM_ORDER;
210 /* enable AD6 + AD7 channels */
Harald Welte07872b62016-03-20 11:45:36 +0100211 ADC->ADC_CHER = ADC_CHER_CH7;
212 ADC->ADC_IER = ADC_IER_EOC7;
213#ifdef CARDEMU_SECOND_UART
214 ADC->ADC_CHER |= ADC_CHER_CH6;
215 ADC->ADC_IER |= ADC_IER_EOC6;
216#endif
217 NVIC_EnableIRQ(ADC_IRQn);
Harald Welte419eb8a2016-03-20 10:04:03 +0100218 ADC->ADC_CR |= ADC_CR_START;
Harald Welte07872b62016-03-20 11:45:36 +0100219
220 return 0;
Harald Welte419eb8a2016-03-20 10:04:03 +0100221}
222
Harald Welte07872b62016-03-20 11:45:36 +0100223#define UV_PER_LSB ((3300 * 1000) / 4096)
224#define VCC_UV_THRESH_1V8 1500000
225#define VCC_UV_THRESH_3V 2800000
226
227static void process_vcc_adc(struct cardem_inst *ci)
Harald Welte419eb8a2016-03-20 10:04:03 +0100228{
Harald Welte07872b62016-03-20 11:45:36 +0100229 if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
230 ci->vcc_uv_last < VCC_UV_THRESH_3V) {
231 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1);
232 /* FIXME do this for real */
233 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1);
234 } else if (ci->vcc_uv < VCC_UV_THRESH_3V &&
235 ci->vcc_uv_last >= VCC_UV_THRESH_3V) {
236 /* FIXME do this for real */
237 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0);
238 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0);
Harald Welte419eb8a2016-03-20 10:04:03 +0100239 }
Harald Welte07872b62016-03-20 11:45:36 +0100240 ci->vcc_uv_last = ci->vcc_uv;
241}
242
243static uint32_t adc2uv(uint16_t adc)
244{
245 uint32_t uv = (uint32_t) adc * UV_PER_LSB;
246}
247
248void ADC_IrqHandler(void)
249{
250#ifdef CARDEMU_SECOND_UART
251 if (ADC->ADC_ISR & ADC_ISR_EOC6) {
252 uint16_t val = ADC->ADC_CDR[6] & 0xFFF;
253 cardem_inst[1].vcc_uv = adc2uv(val);
254 process_vcc_adc(&cardem_inst[1]);
255 ADC->ADC_CR |= ADC_CR_START;
256 }
257#endif
Harald Welte419eb8a2016-03-20 10:04:03 +0100258
259 if (ADC->ADC_ISR & ADC_ISR_EOC7) {
Harald Welte07872b62016-03-20 11:45:36 +0100260 uint16_t val = ADC->ADC_CDR[7] & 0xFFF;
261 cardem_inst[0].vcc_uv = adc2uv(val);
262 process_vcc_adc(&cardem_inst[0]);
263 ADC->ADC_CR |= ADC_CR_START;
Harald Welte419eb8a2016-03-20 10:04:03 +0100264 }
265}
Harald Welte07872b62016-03-20 11:45:36 +0100266#endif /* DETECT_VCC_BY_ADC */
Harald Welte419eb8a2016-03-20 10:04:03 +0100267
268/***********************************************************************
Harald Welte2a6d3af2016-02-28 19:29:14 +0100269 * Core USB / mainloop integration
270 ***********************************************************************/
271
Harald Weltec0bd7f02016-02-29 10:13:33 +0100272static void usim1_rst_irqhandler(const Pin *pPin)
273{
274 int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
Harald Welte13e82022016-03-02 15:17:53 +0100275 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100276}
277
Harald Welte07872b62016-03-20 11:45:36 +0100278#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100279static void usim1_vcc_irqhandler(const Pin *pPin)
280{
281 int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
Harald Welte13e82022016-03-02 15:17:53 +0100282 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100283 /* FIXME do this for real */
Harald Welte13e82022016-03-02 15:17:53 +0100284 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100285}
Harald Welte07872b62016-03-20 11:45:36 +0100286#endif /* !DETECT_VCC_BY_ADC */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100287
Harald Welte13e82022016-03-02 15:17:53 +0100288#ifdef CARDEMU_SECOND_UART
289static void usim2_rst_irqhandler(const Pin *pPin)
290{
291 int active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
292 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
293}
294
Harald Welte07872b62016-03-20 11:45:36 +0100295#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100296static void usim2_vcc_irqhandler(const Pin *pPin)
297{
298 int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
299 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
300 /* FIXME do this for real */
301 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
302}
Harald Welte07872b62016-03-20 11:45:36 +0100303#endif /* !DETECT_VCC_BY_ADC */
304#endif /* CARDEMU_SECOND_UART */
Harald Welte13e82022016-03-02 15:17:53 +0100305
Harald Welte2a6d3af2016-02-28 19:29:14 +0100306/* executed once at system boot for each config */
307void mode_cardemu_configure(void)
308{
Harald Weltebd717682016-02-28 19:30:05 +0100309 TRACE_ENTRY();
Harald Welte2a6d3af2016-02-28 19:29:14 +0100310}
311
312/* called if config is activated */
313void mode_cardemu_init(void)
314{
Harald Welte13e82022016-03-02 15:17:53 +0100315 int i;
Harald Weltebd717682016-02-28 19:30:05 +0100316
Harald Welte13e82022016-03-02 15:17:53 +0100317 TRACE_ENTRY();
Harald Weltec0bd7f02016-02-29 10:13:33 +0100318
Harald Welte2a6d3af2016-02-28 19:29:14 +0100319 PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
Harald Welte07872b62016-03-20 11:45:36 +0100320#ifdef DETECT_VCC_BY_ADC
321 card_vcc_adc_init();
322#endif /* DETECT_VCC_BY_ADC */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100323
Harald Welte13e82022016-03-02 15:17:53 +0100324 INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
325 rbuf_reset(&cardem_inst[0].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100326 PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
Harald Welte13e82022016-03-02 15:17:53 +0100327 ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100328 NVIC_EnableIRQ(USART1_IRQn);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100329 PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
330 PIO_EnableIt(&pin_usim1_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100331#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100332 PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
333 PIO_EnableIt(&pin_usim1_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100334#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100335 cardem_inst[0].ch = card_emu_init(0, 2, 0);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100336
337#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100338 INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
339 rbuf_reset(&cardem_inst[1].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100340 PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
Harald Welte13e82022016-03-02 15:17:53 +0100341 ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100342 NVIC_EnableIRQ(USART0_IRQn);
Harald Welte13e82022016-03-02 15:17:53 +0100343 PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
344 PIO_EnableIt(&pin_usim2_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100345#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100346 PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
347 PIO_EnableIt(&pin_usim2_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100348#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100349 cardem_inst[1].ch = card_emu_init(1, 0, 1);
Harald Welte07872b62016-03-20 11:45:36 +0100350#endif /* CARDEMU_SECOND_UART */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100351}
352
353/* called if config is deactivated */
354void mode_cardemu_exit(void)
355{
Harald Weltebd717682016-02-28 19:30:05 +0100356 TRACE_ENTRY();
357
Harald Welte7abdb512016-03-03 17:48:32 +0100358 /* FIXME: stop tc_fdt */
359 /* FIXME: release all rctx, unlink them from any queue */
360
Harald Weltec0bd7f02016-02-29 10:13:33 +0100361 PIO_DisableIt(&pin_usim1_rst);
362 PIO_DisableIt(&pin_usim1_vcc);
363
Harald Welte2a6d3af2016-02-28 19:29:14 +0100364 NVIC_DisableIRQ(USART1_IRQn);
365 USART_SetTransmitterEnabled(USART1, 0);
366 USART_SetReceiverEnabled(USART1, 0);
367
368#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100369 PIO_DisableIt(&pin_usim2_rst);
370 PIO_DisableIt(&pin_usim2_vcc);
371
Harald Welte2a6d3af2016-02-28 19:29:14 +0100372 NVIC_DisableIRQ(USART0_IRQn);
373 USART_SetTransmitterEnabled(USART0, 0);
374 USART_SetReceiverEnabled(USART0, 0);
375#endif
376}
377
Harald Welteacae4122016-03-02 10:27:58 +0100378static int llist_count(struct llist_head *head)
379{
380 struct llist_head *list;
381 int i = 0;
382
383 llist_for_each(list, head)
384 i++;
385
386 return i;
387}
388
Harald Welteebb80ed2016-03-02 13:56:59 +0100389/* handle a single USB command as received from the USB host */
Harald Welte0eaa9922016-03-04 03:03:49 +0100390static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100391{
392 struct cardemu_usb_msg_hdr *hdr;
Harald Welte06b27f62016-03-02 14:26:38 +0100393 struct cardemu_usb_msg_set_atr *atr;
Harald Welte0eaa9922016-03-04 03:03:49 +0100394 struct cardemu_usb_msg_cardinsert *cardins;
Harald Welteebb80ed2016-03-02 13:56:59 +0100395 struct llist_head *queue;
396
397 hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
398 switch (hdr->msg_type) {
399 case CEMU_USB_MSGT_DT_TX_DATA:
Harald Welte0eaa9922016-03-04 03:03:49 +0100400 queue = card_emu_get_uart_tx_queue(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100401 req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
402 llist_add_tail(&rctx->list, queue);
Harald Welte0eaa9922016-03-04 03:03:49 +0100403 card_emu_have_new_uart_tx(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100404 break;
405 case CEMU_USB_MSGT_DT_SET_ATR:
Harald Welte06b27f62016-03-02 14:26:38 +0100406 atr = (struct cardemu_usb_msg_set_atr *) hdr;
Harald Welted295b922016-03-18 21:01:36 +0100407 card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
Harald Welte06b27f62016-03-02 14:26:38 +0100408 req_ctx_put(rctx);
409 break;
Harald Welte0eaa9922016-03-04 03:03:49 +0100410 case CEMU_USB_MSGT_DT_CARDINSERT:
411 cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
412 if (cardins->card_insert)
413 PIO_Set(&ci->pin_insert);
414 else
415 PIO_Clear(&ci->pin_insert);
Harald Welte5820ea92016-03-16 22:12:00 +0100416 req_ctx_put(rctx);
Harald Welte0eaa9922016-03-04 03:03:49 +0100417 break;
Harald Welteebb80ed2016-03-02 13:56:59 +0100418 case CEMU_USB_MSGT_DT_GET_STATUS:
Harald Welteff160652016-03-19 21:59:06 +0100419 card_emu_report_status(ci->ch);
420 break;
421 case CEMU_USB_MSGT_DT_GET_STATS:
Harald Welteebb80ed2016-03-02 13:56:59 +0100422 default:
423 /* FIXME */
Harald Welte5820ea92016-03-16 22:12:00 +0100424 req_ctx_put(rctx);
Harald Welteebb80ed2016-03-02 13:56:59 +0100425 break;
426 }
427}
428
Harald Welteb26d0032016-03-19 13:33:02 +0100429static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci)
430{
431 struct req_ctx *segm;
432 struct cardemu_usb_msg_hdr *mh;
433 int i = 0;
434
435 /* check if we have multiple concatenated commands in
436 * one message. USB endpoints are streams that don't
437 * preserve the message boundaries */
438 mh = (struct cardemu_usb_msg_hdr *) rctx->data;
439 TRACE_DEBUG("rctx->tot_len=%d, mh->msg_len=%d\r\n",
440 rctx->tot_len, mh->msg_len);
441 if (mh->msg_len == rctx->tot_len) {
442 /* fast path: only one message in buffer */
443 dispatch_usb_command(rctx, ci);
444 return;
445 }
446
447 /* slow path: iterate over list of messages, allocating one new
448 * reqe_ctx per segment */
449 for (mh = (struct cardemu_usb_msg_hdr *) rctx->data;
450 (uint8_t *)mh < rctx->data + rctx->tot_len;
451 mh = (struct cardemu_usb_msg_hdr * ) ((uint8_t *)mh + mh->msg_len)) {
452 TRACE_DEBUG("Segment %d, offs=%d, len=%d\r\n", i,
453 (uint8_t *)mh - rctx->data, mh->msg_len);
454 segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING);
455 if (!segm) {
456 TRACE_ERROR("ENOMEM during rctx segmentation\r\n");
457 break;
458 }
459 segm->idx = 0;
460 segm->tot_len = mh->msg_len;
461 memcpy(segm->data, mh, segm->tot_len);
462 dispatch_usb_command(segm, ci);
463 i++;
464 }
465
466 /* release the master req_ctx, as all segments have been
467 * processed now */
468 req_ctx_put(rctx);
469}
470
Harald Welteebb80ed2016-03-02 13:56:59 +0100471/* iterate over the queue of incoming USB commands and dispatch/execute
472 * them */
Harald Welte9f240b62016-03-18 10:32:56 +0100473static void process_any_usb_commands(struct llist_head *main_q,
474 struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100475{
Harald Welte9f240b62016-03-18 10:32:56 +0100476 struct llist_head *lh;
477 struct req_ctx *rctx;
478 int i;
Harald Welteebb80ed2016-03-02 13:56:59 +0100479
Harald Welte9f240b62016-03-18 10:32:56 +0100480 /* limit the number of iterations to 10, to ensure we don't get
481 * stuck here without returning to main loop processing */
482 for (i = 0; i < 10; i++) {
483 /* de-queue the list head in an irq-safe way */
484 lh = llist_head_dequeue_irqsafe(main_q);
485 if (!lh)
486 break;
487 rctx = llist_entry(lh, struct req_ctx, list);
Harald Welteb26d0032016-03-19 13:33:02 +0100488 dispatch_received_rctx(rctx, ci);
Harald Welte5820ea92016-03-16 22:12:00 +0100489 }
Harald Welteebb80ed2016-03-02 13:56:59 +0100490}
491
Harald Welte2a6d3af2016-02-28 19:29:14 +0100492/* main loop function, called repeatedly */
493void mode_cardemu_run(void)
494{
Harald Welteacae4122016-03-02 10:27:58 +0100495 struct llist_head *queue;
Harald Welte13e82022016-03-02 15:17:53 +0100496 unsigned int i;
Harald Welteacae4122016-03-02 10:27:58 +0100497
Harald Welte13e82022016-03-02 15:17:53 +0100498 for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
499 struct cardem_inst *ci = &cardem_inst[i];
500
Harald Welte54cb3d02016-02-29 14:12:40 +0100501 /* drain the ring buffer from UART into card_emu */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100502 while (1) {
503 __disable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100504 if (rbuf_is_empty(&ci->rb)) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100505 __enable_irq();
506 break;
507 }
Harald Welte13e82022016-03-02 15:17:53 +0100508 uint8_t byte = rbuf_read(&ci->rb);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100509 __enable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100510 card_emu_process_rx_byte(ci->ch, byte);
Harald Welteacae4122016-03-02 10:27:58 +0100511 TRACE_ERROR("Rx%02x\r\n", byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100512 }
Harald Welteacae4122016-03-02 10:27:58 +0100513
Harald Welte13e82022016-03-02 15:17:53 +0100514 queue = card_emu_get_usb_tx_queue(ci->ch);
Harald Welteacae4122016-03-02 10:27:58 +0100515 int usb_pending = llist_count(queue);
Harald Welte13e82022016-03-02 15:17:53 +0100516 if (usb_pending != ci->usb_pending_old) {
Harald Welteacae4122016-03-02 10:27:58 +0100517// printf("usb_pending=%d\r\n", usb_pending);
Harald Welte13e82022016-03-02 15:17:53 +0100518 ci->usb_pending_old = usb_pending;
Harald Welteacae4122016-03-02 10:27:58 +0100519 }
Harald Welte13e82022016-03-02 15:17:53 +0100520 usb_refill_to_host(queue, ci->ep_in);
Harald Welteacae4122016-03-02 10:27:58 +0100521
Harald Welteebb80ed2016-03-02 13:56:59 +0100522 /* ensure we can handle incoming USB messages from the
523 * host */
Harald Welte13e82022016-03-02 15:17:53 +0100524 queue = &ci->usb_out_queue;
525 usb_refill_from_host(queue, ci->ep_out);
Harald Welte0eaa9922016-03-04 03:03:49 +0100526 process_any_usb_commands(queue, ci);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100527 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100528}