blob: 098e0d676a14d4d82763e5d8e6269129191b3e82 [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
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 Welte2a6d3af2016-02-28 19:29:14 +0100100/* call-back from card_emu.c to enable/disable transmit and/or receive */
101void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
102{
103 Usart *usart = get_usart_by_chan(uart_chan);
104 switch (rxtx) {
105 case ENABLE_TX:
Harald Welte9dbc46e2016-02-29 10:05:10 +0100106 USART_DisableIt(usart, ~US_IER_TXRDY);
Harald Weltec8beefb2016-03-20 14:40:47 +0100107 /* as irritating as it is, we actually want to keep the
108 * receiver enabled during transmit */
109 USART_SetReceiverEnabled(usart, 1);
Harald Welte8a416b12016-03-01 00:42:04 +0100110 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
111 USART_EnableIt(usart, US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100112 USART_SetTransmitterEnabled(usart, 1);
113 break;
114 case ENABLE_RX:
Harald Welte9dbc46e2016-02-29 10:05:10 +0100115 USART_DisableIt(usart, ~US_IER_RXRDY);
Harald Weltec8beefb2016-03-20 14:40:47 +0100116 /* as irritating as it is, we actually want to keep the
117 * transmitter enabled during receive */
118 USART_SetTransmitterEnabled(usart, 1);
119 wait_tx_idle(usart);
Harald Welte8a416b12016-03-01 00:42:04 +0100120 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
121 USART_EnableIt(usart, US_IER_RXRDY);
122 USART_SetReceiverEnabled(usart, 1);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100123 break;
124 case 0:
125 default:
126 USART_SetTransmitterEnabled(usart, 0);
127 USART_SetReceiverEnabled(usart, 0);
Harald Welte9dbc46e2016-02-29 10:05:10 +0100128 USART_DisableIt(usart, 0xFFFFFFFF);
Harald Welte8a416b12016-03-01 00:42:04 +0100129 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100130 break;
131 }
132}
133
134/* call-back from card_emu.c to transmit a byte */
135int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
136{
Harald Welte13e82022016-03-02 15:17:53 +0100137 Usart *usart = get_usart_by_chan(uart_chan);
138#if 0
Harald Welte2a6d3af2016-02-28 19:29:14 +0100139 Usart_info *ui = &usart_info[uart_chan];
140 ISO7816_SendChar(byte, ui);
Harald Welte13e82022016-03-02 15:17:53 +0100141#else
142 int i = 0;
143 while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
144 if (!(i%1000000)) {
145 printf("s: %x %02X", usart->US_CSR, usart->US_RHR & 0xFF);
146 usart->US_CR = US_CR_RSTTX;
147 usart->US_CR = US_CR_RSTRX;
148 }
149 }
150 usart->US_THR = byte;
151 TRACE_ERROR("Sx%02x\r\n", byte);
152#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +0100153 return 1;
154}
155
156
157/* FIXME: integrate this with actual irq handler */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100158void usart_irq_rx(uint8_t uart)
Harald Welte2a6d3af2016-02-28 19:29:14 +0100159{
Harald Weltec0bd7f02016-02-29 10:13:33 +0100160 Usart *usart = get_usart_by_chan(uart);
Harald Welte13e82022016-03-02 15:17:53 +0100161 struct cardem_inst *ci = &cardem_inst[0];
Harald Weltec0bd7f02016-02-29 10:13:33 +0100162 uint32_t csr;
163 uint8_t byte = 0;
164
Harald Welte2a6d3af2016-02-28 19:29:14 +0100165#ifdef CARDEMU_SECOND_UART
Harald Weltec0bd7f02016-02-29 10:13:33 +0100166 if (uart == 1)
Harald Welte13e82022016-03-02 15:17:53 +0100167 ci = &cardem_inst[1];
Harald Welte2a6d3af2016-02-28 19:29:14 +0100168#endif
Harald Welteda15ca02016-03-17 21:14:04 +0100169 csr = usart->US_CSR & usart->US_IMR;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100170
Harald Weltec0bd7f02016-02-29 10:13:33 +0100171 if (csr & US_CSR_RXRDY) {
172 byte = (usart->US_RHR) & 0xFF;
Harald Welte13e82022016-03-02 15:17:53 +0100173 rbuf_write(&ci->rb, byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100174 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100175
Harald Welte12d4bdf2016-03-02 10:31:03 +0100176 if (csr & US_CSR_TXRDY) {
Harald Welte13e82022016-03-02 15:17:53 +0100177 if (card_emu_tx_byte(ci->ch) == 0)
Harald Welte12d4bdf2016-03-02 10:31:03 +0100178 USART_DisableIt(usart, US_IER_TXRDY);
179 }
180
Harald Welte2a6d3af2016-02-28 19:29:14 +0100181 if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
182 US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100183 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
184 TRACE_ERROR("e 0x%x st: 0x%x\n", byte, csr);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100185 }
186}
187
Harald Weltebd717682016-02-28 19:30:05 +0100188/* call-back from card_emu.c to change UART baud rate */
189int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
190{
191 int rc;
Harald Weltebd717682016-02-28 19:30:05 +0100192 Usart *usart = get_usart_by_chan(uart_chan);
193
Harald Welte99f62a62016-02-29 10:08:49 +0100194 usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
195 usart->US_FIDI = fidi & 0x3ff;
196 usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
197 return 0;
Harald Weltebd717682016-02-28 19:30:05 +0100198}
Harald Welte2a6d3af2016-02-28 19:29:14 +0100199
200/***********************************************************************
Harald Welte419eb8a2016-03-20 10:04:03 +0100201 * ADC for VCC voltage detection
202 ***********************************************************************/
203
Harald Welte07872b62016-03-20 11:45:36 +0100204#ifdef DETECT_VCC_BY_ADC
205
206static int adc_triggered = 0;
207
Harald Welte419eb8a2016-03-20 10:04:03 +0100208static int card_vcc_adc_init(void)
209{
Harald Welte07872b62016-03-20 11:45:36 +0100210 PMC_EnablePeripheral(ID_ADC);
211
Harald Welte419eb8a2016-03-20 10:04:03 +0100212 ADC->ADC_CR |= ADC_CR_SWRST;
Harald Welte07872b62016-03-20 11:45:36 +0100213 /* Errata Work-Around to clear EOCx flags */
214 {
215 volatile uint32_t foo;
216 int i;
217 for (i = 0; i < 16; i++)
218 foo = ADC->ADC_CDR[i];
219 }
220
221 /* Initialize ADC for AD7 / AD6, fADC=48/24=2MHz */
Harald Welte419eb8a2016-03-20 10:04:03 +0100222 ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_LOWRES_BITS_12 |
223 ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF |
Harald Welte07872b62016-03-20 11:45:36 +0100224 ADC_MR_FREERUN_OFF | ADC_MR_PRESCAL(23) |
225 ADC_MR_STARTUP_SUT8 | ADC_MR_SETTLING(3) |
226 ADC_MR_ANACH_NONE | ADC_MR_TRACKTIM(4) |
Harald Welte419eb8a2016-03-20 10:04:03 +0100227 ADC_MR_TRANSFER(1) | ADC_MR_USEQ_NUM_ORDER;
228 /* enable AD6 + AD7 channels */
Harald Welte07872b62016-03-20 11:45:36 +0100229 ADC->ADC_CHER = ADC_CHER_CH7;
230 ADC->ADC_IER = ADC_IER_EOC7;
231#ifdef CARDEMU_SECOND_UART
232 ADC->ADC_CHER |= ADC_CHER_CH6;
233 ADC->ADC_IER |= ADC_IER_EOC6;
234#endif
235 NVIC_EnableIRQ(ADC_IRQn);
Harald Welte419eb8a2016-03-20 10:04:03 +0100236 ADC->ADC_CR |= ADC_CR_START;
Harald Welte07872b62016-03-20 11:45:36 +0100237
238 return 0;
Harald Welte419eb8a2016-03-20 10:04:03 +0100239}
240
Harald Welte07872b62016-03-20 11:45:36 +0100241#define UV_PER_LSB ((3300 * 1000) / 4096)
242#define VCC_UV_THRESH_1V8 1500000
243#define VCC_UV_THRESH_3V 2800000
244
245static void process_vcc_adc(struct cardem_inst *ci)
Harald Welte419eb8a2016-03-20 10:04:03 +0100246{
Harald Welte07872b62016-03-20 11:45:36 +0100247 if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
248 ci->vcc_uv_last < VCC_UV_THRESH_3V) {
249 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1);
250 /* FIXME do this for real */
251 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1);
252 } else if (ci->vcc_uv < VCC_UV_THRESH_3V &&
253 ci->vcc_uv_last >= VCC_UV_THRESH_3V) {
254 /* FIXME do this for real */
255 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0);
256 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0);
Harald Welte419eb8a2016-03-20 10:04:03 +0100257 }
Harald Welte07872b62016-03-20 11:45:36 +0100258 ci->vcc_uv_last = ci->vcc_uv;
259}
260
261static uint32_t adc2uv(uint16_t adc)
262{
263 uint32_t uv = (uint32_t) adc * UV_PER_LSB;
264}
265
266void ADC_IrqHandler(void)
267{
268#ifdef CARDEMU_SECOND_UART
269 if (ADC->ADC_ISR & ADC_ISR_EOC6) {
270 uint16_t val = ADC->ADC_CDR[6] & 0xFFF;
271 cardem_inst[1].vcc_uv = adc2uv(val);
272 process_vcc_adc(&cardem_inst[1]);
273 ADC->ADC_CR |= ADC_CR_START;
274 }
275#endif
Harald Welte419eb8a2016-03-20 10:04:03 +0100276
277 if (ADC->ADC_ISR & ADC_ISR_EOC7) {
Harald Welte07872b62016-03-20 11:45:36 +0100278 uint16_t val = ADC->ADC_CDR[7] & 0xFFF;
279 cardem_inst[0].vcc_uv = adc2uv(val);
280 process_vcc_adc(&cardem_inst[0]);
281 ADC->ADC_CR |= ADC_CR_START;
Harald Welte419eb8a2016-03-20 10:04:03 +0100282 }
283}
Harald Welte07872b62016-03-20 11:45:36 +0100284#endif /* DETECT_VCC_BY_ADC */
Harald Welte419eb8a2016-03-20 10:04:03 +0100285
286/***********************************************************************
Harald Welte2a6d3af2016-02-28 19:29:14 +0100287 * Core USB / mainloop integration
288 ***********************************************************************/
289
Harald Weltec0bd7f02016-02-29 10:13:33 +0100290static void usim1_rst_irqhandler(const Pin *pPin)
291{
292 int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
Harald Welte13e82022016-03-02 15:17:53 +0100293 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100294}
295
Harald Welte07872b62016-03-20 11:45:36 +0100296#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100297static void usim1_vcc_irqhandler(const Pin *pPin)
298{
299 int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
Harald Welte13e82022016-03-02 15:17:53 +0100300 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100301 /* FIXME do this for real */
Harald Welte13e82022016-03-02 15:17:53 +0100302 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100303}
Harald Welte07872b62016-03-20 11:45:36 +0100304#endif /* !DETECT_VCC_BY_ADC */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100305
Harald Welte13e82022016-03-02 15:17:53 +0100306#ifdef CARDEMU_SECOND_UART
307static void usim2_rst_irqhandler(const Pin *pPin)
308{
309 int active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
310 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
311}
312
Harald Welte07872b62016-03-20 11:45:36 +0100313#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100314static void usim2_vcc_irqhandler(const Pin *pPin)
315{
316 int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
317 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
318 /* FIXME do this for real */
319 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
320}
Harald Welte07872b62016-03-20 11:45:36 +0100321#endif /* !DETECT_VCC_BY_ADC */
322#endif /* CARDEMU_SECOND_UART */
Harald Welte13e82022016-03-02 15:17:53 +0100323
Harald Welte2a6d3af2016-02-28 19:29:14 +0100324/* executed once at system boot for each config */
325void mode_cardemu_configure(void)
326{
Harald Weltebd717682016-02-28 19:30:05 +0100327 TRACE_ENTRY();
Harald Welte2a6d3af2016-02-28 19:29:14 +0100328}
329
330/* called if config is activated */
331void mode_cardemu_init(void)
332{
Harald Welte13e82022016-03-02 15:17:53 +0100333 int i;
Harald Weltebd717682016-02-28 19:30:05 +0100334
Harald Welte13e82022016-03-02 15:17:53 +0100335 TRACE_ENTRY();
Harald Weltec0bd7f02016-02-29 10:13:33 +0100336
Harald Welte2a6d3af2016-02-28 19:29:14 +0100337 PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
Harald Welte07872b62016-03-20 11:45:36 +0100338#ifdef DETECT_VCC_BY_ADC
339 card_vcc_adc_init();
340#endif /* DETECT_VCC_BY_ADC */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100341
Harald Welte13e82022016-03-02 15:17:53 +0100342 INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
343 rbuf_reset(&cardem_inst[0].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100344 PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
Harald Welte13e82022016-03-02 15:17:53 +0100345 ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100346 NVIC_EnableIRQ(USART1_IRQn);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100347 PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
348 PIO_EnableIt(&pin_usim1_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100349#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100350 PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
351 PIO_EnableIt(&pin_usim1_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100352#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100353 cardem_inst[0].ch = card_emu_init(0, 2, 0);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100354
355#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100356 INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
357 rbuf_reset(&cardem_inst[1].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100358 PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
Harald Welte13e82022016-03-02 15:17:53 +0100359 ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100360 NVIC_EnableIRQ(USART0_IRQn);
Harald Welte13e82022016-03-02 15:17:53 +0100361 PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
362 PIO_EnableIt(&pin_usim2_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100363#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100364 PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
365 PIO_EnableIt(&pin_usim2_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100366#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100367 cardem_inst[1].ch = card_emu_init(1, 0, 1);
Harald Welte07872b62016-03-20 11:45:36 +0100368#endif /* CARDEMU_SECOND_UART */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100369}
370
371/* called if config is deactivated */
372void mode_cardemu_exit(void)
373{
Harald Weltebd717682016-02-28 19:30:05 +0100374 TRACE_ENTRY();
375
Harald Welte7abdb512016-03-03 17:48:32 +0100376 /* FIXME: stop tc_fdt */
377 /* FIXME: release all rctx, unlink them from any queue */
378
Harald Weltec0bd7f02016-02-29 10:13:33 +0100379 PIO_DisableIt(&pin_usim1_rst);
380 PIO_DisableIt(&pin_usim1_vcc);
381
Harald Welte2a6d3af2016-02-28 19:29:14 +0100382 NVIC_DisableIRQ(USART1_IRQn);
383 USART_SetTransmitterEnabled(USART1, 0);
384 USART_SetReceiverEnabled(USART1, 0);
385
386#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100387 PIO_DisableIt(&pin_usim2_rst);
388 PIO_DisableIt(&pin_usim2_vcc);
389
Harald Welte2a6d3af2016-02-28 19:29:14 +0100390 NVIC_DisableIRQ(USART0_IRQn);
391 USART_SetTransmitterEnabled(USART0, 0);
392 USART_SetReceiverEnabled(USART0, 0);
393#endif
394}
395
Harald Welteacae4122016-03-02 10:27:58 +0100396static int llist_count(struct llist_head *head)
397{
398 struct llist_head *list;
399 int i = 0;
400
401 llist_for_each(list, head)
402 i++;
403
404 return i;
405}
406
Harald Welteebb80ed2016-03-02 13:56:59 +0100407/* handle a single USB command as received from the USB host */
Harald Welte0eaa9922016-03-04 03:03:49 +0100408static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100409{
410 struct cardemu_usb_msg_hdr *hdr;
Harald Welte06b27f62016-03-02 14:26:38 +0100411 struct cardemu_usb_msg_set_atr *atr;
Harald Welte0eaa9922016-03-04 03:03:49 +0100412 struct cardemu_usb_msg_cardinsert *cardins;
Harald Welteebb80ed2016-03-02 13:56:59 +0100413 struct llist_head *queue;
414
415 hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
416 switch (hdr->msg_type) {
417 case CEMU_USB_MSGT_DT_TX_DATA:
Harald Welte0eaa9922016-03-04 03:03:49 +0100418 queue = card_emu_get_uart_tx_queue(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100419 req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
420 llist_add_tail(&rctx->list, queue);
Harald Welte0eaa9922016-03-04 03:03:49 +0100421 card_emu_have_new_uart_tx(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100422 break;
423 case CEMU_USB_MSGT_DT_SET_ATR:
Harald Welte06b27f62016-03-02 14:26:38 +0100424 atr = (struct cardemu_usb_msg_set_atr *) hdr;
Harald Welted295b922016-03-18 21:01:36 +0100425 card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
Harald Welte06b27f62016-03-02 14:26:38 +0100426 req_ctx_put(rctx);
427 break;
Harald Welte0eaa9922016-03-04 03:03:49 +0100428 case CEMU_USB_MSGT_DT_CARDINSERT:
429 cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
430 if (cardins->card_insert)
431 PIO_Set(&ci->pin_insert);
432 else
433 PIO_Clear(&ci->pin_insert);
Harald Welte5820ea92016-03-16 22:12:00 +0100434 req_ctx_put(rctx);
Harald Welte0eaa9922016-03-04 03:03:49 +0100435 break;
Harald Welteebb80ed2016-03-02 13:56:59 +0100436 case CEMU_USB_MSGT_DT_GET_STATUS:
Harald Welteff160652016-03-19 21:59:06 +0100437 card_emu_report_status(ci->ch);
438 break;
439 case CEMU_USB_MSGT_DT_GET_STATS:
Harald Welteebb80ed2016-03-02 13:56:59 +0100440 default:
441 /* FIXME */
Harald Welte5820ea92016-03-16 22:12:00 +0100442 req_ctx_put(rctx);
Harald Welteebb80ed2016-03-02 13:56:59 +0100443 break;
444 }
445}
446
Harald Welteb26d0032016-03-19 13:33:02 +0100447static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci)
448{
449 struct req_ctx *segm;
450 struct cardemu_usb_msg_hdr *mh;
451 int i = 0;
452
453 /* check if we have multiple concatenated commands in
454 * one message. USB endpoints are streams that don't
455 * preserve the message boundaries */
456 mh = (struct cardemu_usb_msg_hdr *) rctx->data;
457 TRACE_DEBUG("rctx->tot_len=%d, mh->msg_len=%d\r\n",
458 rctx->tot_len, mh->msg_len);
459 if (mh->msg_len == rctx->tot_len) {
460 /* fast path: only one message in buffer */
461 dispatch_usb_command(rctx, ci);
462 return;
463 }
464
465 /* slow path: iterate over list of messages, allocating one new
466 * reqe_ctx per segment */
467 for (mh = (struct cardemu_usb_msg_hdr *) rctx->data;
468 (uint8_t *)mh < rctx->data + rctx->tot_len;
469 mh = (struct cardemu_usb_msg_hdr * ) ((uint8_t *)mh + mh->msg_len)) {
470 TRACE_DEBUG("Segment %d, offs=%d, len=%d\r\n", i,
471 (uint8_t *)mh - rctx->data, mh->msg_len);
472 segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING);
473 if (!segm) {
474 TRACE_ERROR("ENOMEM during rctx segmentation\r\n");
475 break;
476 }
477 segm->idx = 0;
478 segm->tot_len = mh->msg_len;
479 memcpy(segm->data, mh, segm->tot_len);
480 dispatch_usb_command(segm, ci);
481 i++;
482 }
483
484 /* release the master req_ctx, as all segments have been
485 * processed now */
486 req_ctx_put(rctx);
487}
488
Harald Welteebb80ed2016-03-02 13:56:59 +0100489/* iterate over the queue of incoming USB commands and dispatch/execute
490 * them */
Harald Welte9f240b62016-03-18 10:32:56 +0100491static void process_any_usb_commands(struct llist_head *main_q,
492 struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100493{
Harald Welte9f240b62016-03-18 10:32:56 +0100494 struct llist_head *lh;
495 struct req_ctx *rctx;
496 int i;
Harald Welteebb80ed2016-03-02 13:56:59 +0100497
Harald Welte9f240b62016-03-18 10:32:56 +0100498 /* limit the number of iterations to 10, to ensure we don't get
499 * stuck here without returning to main loop processing */
500 for (i = 0; i < 10; i++) {
501 /* de-queue the list head in an irq-safe way */
502 lh = llist_head_dequeue_irqsafe(main_q);
503 if (!lh)
504 break;
505 rctx = llist_entry(lh, struct req_ctx, list);
Harald Welteb26d0032016-03-19 13:33:02 +0100506 dispatch_received_rctx(rctx, ci);
Harald Welte5820ea92016-03-16 22:12:00 +0100507 }
Harald Welteebb80ed2016-03-02 13:56:59 +0100508}
509
Harald Welte2a6d3af2016-02-28 19:29:14 +0100510/* main loop function, called repeatedly */
511void mode_cardemu_run(void)
512{
Harald Welteacae4122016-03-02 10:27:58 +0100513 struct llist_head *queue;
Harald Welte13e82022016-03-02 15:17:53 +0100514 unsigned int i;
Harald Welteacae4122016-03-02 10:27:58 +0100515
Harald Welte13e82022016-03-02 15:17:53 +0100516 for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
517 struct cardem_inst *ci = &cardem_inst[i];
518
Harald Welte54cb3d02016-02-29 14:12:40 +0100519 /* drain the ring buffer from UART into card_emu */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100520 while (1) {
521 __disable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100522 if (rbuf_is_empty(&ci->rb)) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100523 __enable_irq();
524 break;
525 }
Harald Welte13e82022016-03-02 15:17:53 +0100526 uint8_t byte = rbuf_read(&ci->rb);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100527 __enable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100528 card_emu_process_rx_byte(ci->ch, byte);
Harald Welteacae4122016-03-02 10:27:58 +0100529 TRACE_ERROR("Rx%02x\r\n", byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100530 }
Harald Welteacae4122016-03-02 10:27:58 +0100531
Harald Welte13e82022016-03-02 15:17:53 +0100532 queue = card_emu_get_usb_tx_queue(ci->ch);
Harald Welteacae4122016-03-02 10:27:58 +0100533 int usb_pending = llist_count(queue);
Harald Welte13e82022016-03-02 15:17:53 +0100534 if (usb_pending != ci->usb_pending_old) {
Harald Welteacae4122016-03-02 10:27:58 +0100535// printf("usb_pending=%d\r\n", usb_pending);
Harald Welte13e82022016-03-02 15:17:53 +0100536 ci->usb_pending_old = usb_pending;
Harald Welteacae4122016-03-02 10:27:58 +0100537 }
Harald Welte13e82022016-03-02 15:17:53 +0100538 usb_refill_to_host(queue, ci->ep_in);
Harald Welteacae4122016-03-02 10:27:58 +0100539
Harald Welteebb80ed2016-03-02 13:56:59 +0100540 /* ensure we can handle incoming USB messages from the
541 * host */
Harald Welte13e82022016-03-02 15:17:53 +0100542 queue = &ci->usb_out_queue;
543 usb_refill_from_host(queue, ci->ep_out);
Harald Welte0eaa9922016-03-04 03:03:49 +0100544 process_any_usb_commands(queue, ci);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100545 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100546}