blob: 0f0d7dc09630e9efc19986bc66a6f5ca694386b5 [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 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
148 int i = 0;
149 while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
150 if (!(i%1000000)) {
151 printf("s: %x %02X", usart->US_CSR, usart->US_RHR & 0xFF);
152 usart->US_CR = US_CR_RSTTX;
153 usart->US_CR = US_CR_RSTRX;
154 }
155 }
156 usart->US_THR = byte;
157 TRACE_ERROR("Sx%02x\r\n", byte);
158#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +0100159 return 1;
160}
161
162
163/* FIXME: integrate this with actual irq handler */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100164void usart_irq_rx(uint8_t uart)
Harald Welte2a6d3af2016-02-28 19:29:14 +0100165{
Harald Weltec0bd7f02016-02-29 10:13:33 +0100166 Usart *usart = get_usart_by_chan(uart);
Harald Welte13e82022016-03-02 15:17:53 +0100167 struct cardem_inst *ci = &cardem_inst[0];
Harald Weltec0bd7f02016-02-29 10:13:33 +0100168 uint32_t csr;
169 uint8_t byte = 0;
170
Harald Welte2a6d3af2016-02-28 19:29:14 +0100171#ifdef CARDEMU_SECOND_UART
Harald Weltec0bd7f02016-02-29 10:13:33 +0100172 if (uart == 1)
Harald Welte13e82022016-03-02 15:17:53 +0100173 ci = &cardem_inst[1];
Harald Welte2a6d3af2016-02-28 19:29:14 +0100174#endif
Harald Welteda15ca02016-03-17 21:14:04 +0100175 csr = usart->US_CSR & usart->US_IMR;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100176
Harald Weltec0bd7f02016-02-29 10:13:33 +0100177 if (csr & US_CSR_RXRDY) {
178 byte = (usart->US_RHR) & 0xFF;
Harald Welte13e82022016-03-02 15:17:53 +0100179 rbuf_write(&ci->rb, byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100180 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100181
Harald Welte12d4bdf2016-03-02 10:31:03 +0100182 if (csr & US_CSR_TXRDY) {
Harald Welte13e82022016-03-02 15:17:53 +0100183 if (card_emu_tx_byte(ci->ch) == 0)
Harald Welte12d4bdf2016-03-02 10:31:03 +0100184 USART_DisableIt(usart, US_IER_TXRDY);
185 }
186
Harald Welte2a6d3af2016-02-28 19:29:14 +0100187 if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
188 US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100189 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
190 TRACE_ERROR("e 0x%x st: 0x%x\n", byte, csr);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100191 }
192}
193
Harald Weltebd717682016-02-28 19:30:05 +0100194/* call-back from card_emu.c to change UART baud rate */
195int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
196{
197 int rc;
Harald Weltebd717682016-02-28 19:30:05 +0100198 Usart *usart = get_usart_by_chan(uart_chan);
199
Harald Welte99f62a62016-02-29 10:08:49 +0100200 usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
201 usart->US_FIDI = fidi & 0x3ff;
202 usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
203 return 0;
Harald Weltebd717682016-02-28 19:30:05 +0100204}
Harald Welte2a6d3af2016-02-28 19:29:14 +0100205
206/***********************************************************************
Harald Welte419eb8a2016-03-20 10:04:03 +0100207 * ADC for VCC voltage detection
208 ***********************************************************************/
209
Harald Welte07872b62016-03-20 11:45:36 +0100210#ifdef DETECT_VCC_BY_ADC
211
212static int adc_triggered = 0;
213
Harald Welte419eb8a2016-03-20 10:04:03 +0100214static int card_vcc_adc_init(void)
215{
Harald Welte07872b62016-03-20 11:45:36 +0100216 PMC_EnablePeripheral(ID_ADC);
217
Harald Welte419eb8a2016-03-20 10:04:03 +0100218 ADC->ADC_CR |= ADC_CR_SWRST;
Harald Welte07872b62016-03-20 11:45:36 +0100219 /* Errata Work-Around to clear EOCx flags */
220 {
221 volatile uint32_t foo;
222 int i;
223 for (i = 0; i < 16; i++)
224 foo = ADC->ADC_CDR[i];
225 }
226
227 /* Initialize ADC for AD7 / AD6, fADC=48/24=2MHz */
Harald Welte419eb8a2016-03-20 10:04:03 +0100228 ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_LOWRES_BITS_12 |
229 ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF |
Harald Welte07872b62016-03-20 11:45:36 +0100230 ADC_MR_FREERUN_OFF | ADC_MR_PRESCAL(23) |
231 ADC_MR_STARTUP_SUT8 | ADC_MR_SETTLING(3) |
232 ADC_MR_ANACH_NONE | ADC_MR_TRACKTIM(4) |
Harald Welte419eb8a2016-03-20 10:04:03 +0100233 ADC_MR_TRANSFER(1) | ADC_MR_USEQ_NUM_ORDER;
234 /* enable AD6 + AD7 channels */
Harald Welte07872b62016-03-20 11:45:36 +0100235 ADC->ADC_CHER = ADC_CHER_CH7;
236 ADC->ADC_IER = ADC_IER_EOC7;
237#ifdef CARDEMU_SECOND_UART
238 ADC->ADC_CHER |= ADC_CHER_CH6;
239 ADC->ADC_IER |= ADC_IER_EOC6;
240#endif
241 NVIC_EnableIRQ(ADC_IRQn);
Harald Welte419eb8a2016-03-20 10:04:03 +0100242 ADC->ADC_CR |= ADC_CR_START;
Harald Welte07872b62016-03-20 11:45:36 +0100243
244 return 0;
Harald Welte419eb8a2016-03-20 10:04:03 +0100245}
246
Harald Welte07872b62016-03-20 11:45:36 +0100247#define UV_PER_LSB ((3300 * 1000) / 4096)
248#define VCC_UV_THRESH_1V8 1500000
249#define VCC_UV_THRESH_3V 2800000
250
251static void process_vcc_adc(struct cardem_inst *ci)
Harald Welte419eb8a2016-03-20 10:04:03 +0100252{
Harald Welte07872b62016-03-20 11:45:36 +0100253 if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
254 ci->vcc_uv_last < VCC_UV_THRESH_3V) {
255 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1);
256 /* FIXME do this for real */
257 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1);
258 } else if (ci->vcc_uv < VCC_UV_THRESH_3V &&
259 ci->vcc_uv_last >= VCC_UV_THRESH_3V) {
260 /* FIXME do this for real */
261 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0);
262 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0);
Harald Welte419eb8a2016-03-20 10:04:03 +0100263 }
Harald Welte07872b62016-03-20 11:45:36 +0100264 ci->vcc_uv_last = ci->vcc_uv;
265}
266
267static uint32_t adc2uv(uint16_t adc)
268{
269 uint32_t uv = (uint32_t) adc * UV_PER_LSB;
270}
271
272void ADC_IrqHandler(void)
273{
274#ifdef CARDEMU_SECOND_UART
275 if (ADC->ADC_ISR & ADC_ISR_EOC6) {
276 uint16_t val = ADC->ADC_CDR[6] & 0xFFF;
277 cardem_inst[1].vcc_uv = adc2uv(val);
278 process_vcc_adc(&cardem_inst[1]);
279 ADC->ADC_CR |= ADC_CR_START;
280 }
281#endif
Harald Welte419eb8a2016-03-20 10:04:03 +0100282
283 if (ADC->ADC_ISR & ADC_ISR_EOC7) {
Harald Welte07872b62016-03-20 11:45:36 +0100284 uint16_t val = ADC->ADC_CDR[7] & 0xFFF;
285 cardem_inst[0].vcc_uv = adc2uv(val);
286 process_vcc_adc(&cardem_inst[0]);
287 ADC->ADC_CR |= ADC_CR_START;
Harald Welte419eb8a2016-03-20 10:04:03 +0100288 }
289}
Harald Welte07872b62016-03-20 11:45:36 +0100290#endif /* DETECT_VCC_BY_ADC */
Harald Welte419eb8a2016-03-20 10:04:03 +0100291
292/***********************************************************************
Harald Welte2a6d3af2016-02-28 19:29:14 +0100293 * Core USB / mainloop integration
294 ***********************************************************************/
295
Harald Weltec0bd7f02016-02-29 10:13:33 +0100296static void usim1_rst_irqhandler(const Pin *pPin)
297{
298 int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
Harald Welte13e82022016-03-02 15:17:53 +0100299 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100300}
301
Harald Welte07872b62016-03-20 11:45:36 +0100302#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100303static void usim1_vcc_irqhandler(const Pin *pPin)
304{
305 int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
Harald Welte13e82022016-03-02 15:17:53 +0100306 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100307 /* FIXME do this for real */
Harald Welte13e82022016-03-02 15:17:53 +0100308 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100309}
Harald Welte07872b62016-03-20 11:45:36 +0100310#endif /* !DETECT_VCC_BY_ADC */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100311
Harald Welte13e82022016-03-02 15:17:53 +0100312#ifdef CARDEMU_SECOND_UART
313static void usim2_rst_irqhandler(const Pin *pPin)
314{
315 int active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
316 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
317}
318
Harald Welte07872b62016-03-20 11:45:36 +0100319#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100320static void usim2_vcc_irqhandler(const Pin *pPin)
321{
322 int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
323 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
324 /* FIXME do this for real */
325 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
326}
Harald Welte07872b62016-03-20 11:45:36 +0100327#endif /* !DETECT_VCC_BY_ADC */
328#endif /* CARDEMU_SECOND_UART */
Harald Welte13e82022016-03-02 15:17:53 +0100329
Harald Welte2a6d3af2016-02-28 19:29:14 +0100330/* executed once at system boot for each config */
331void mode_cardemu_configure(void)
332{
Harald Weltebd717682016-02-28 19:30:05 +0100333 TRACE_ENTRY();
Harald Welte2a6d3af2016-02-28 19:29:14 +0100334}
335
336/* called if config is activated */
337void mode_cardemu_init(void)
338{
Harald Welte13e82022016-03-02 15:17:53 +0100339 int i;
Harald Weltebd717682016-02-28 19:30:05 +0100340
Harald Welte13e82022016-03-02 15:17:53 +0100341 TRACE_ENTRY();
Harald Weltec0bd7f02016-02-29 10:13:33 +0100342
Harald Welte2a6d3af2016-02-28 19:29:14 +0100343 PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
Harald Welte07872b62016-03-20 11:45:36 +0100344#ifdef DETECT_VCC_BY_ADC
345 card_vcc_adc_init();
346#endif /* DETECT_VCC_BY_ADC */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100347
Harald Welte13e82022016-03-02 15:17:53 +0100348 INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
349 rbuf_reset(&cardem_inst[0].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100350 PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
Harald Welte13e82022016-03-02 15:17:53 +0100351 ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100352 NVIC_EnableIRQ(USART1_IRQn);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100353 PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
354 PIO_EnableIt(&pin_usim1_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100355#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100356 PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
357 PIO_EnableIt(&pin_usim1_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100358#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100359 cardem_inst[0].ch = card_emu_init(0, 2, 0);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100360
361#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100362 INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
363 rbuf_reset(&cardem_inst[1].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100364 PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
Harald Welte13e82022016-03-02 15:17:53 +0100365 ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100366 NVIC_EnableIRQ(USART0_IRQn);
Harald Welte13e82022016-03-02 15:17:53 +0100367 PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
368 PIO_EnableIt(&pin_usim2_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100369#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100370 PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
371 PIO_EnableIt(&pin_usim2_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100372#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100373 cardem_inst[1].ch = card_emu_init(1, 0, 1);
Harald Welte07872b62016-03-20 11:45:36 +0100374#endif /* CARDEMU_SECOND_UART */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100375}
376
377/* called if config is deactivated */
378void mode_cardemu_exit(void)
379{
Harald Weltebd717682016-02-28 19:30:05 +0100380 TRACE_ENTRY();
381
Harald Welte7abdb512016-03-03 17:48:32 +0100382 /* FIXME: stop tc_fdt */
383 /* FIXME: release all rctx, unlink them from any queue */
384
Harald Weltec0bd7f02016-02-29 10:13:33 +0100385 PIO_DisableIt(&pin_usim1_rst);
386 PIO_DisableIt(&pin_usim1_vcc);
387
Harald Welte2a6d3af2016-02-28 19:29:14 +0100388 NVIC_DisableIRQ(USART1_IRQn);
389 USART_SetTransmitterEnabled(USART1, 0);
390 USART_SetReceiverEnabled(USART1, 0);
391
392#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100393 PIO_DisableIt(&pin_usim2_rst);
394 PIO_DisableIt(&pin_usim2_vcc);
395
Harald Welte2a6d3af2016-02-28 19:29:14 +0100396 NVIC_DisableIRQ(USART0_IRQn);
397 USART_SetTransmitterEnabled(USART0, 0);
398 USART_SetReceiverEnabled(USART0, 0);
399#endif
400}
401
Harald Welteacae4122016-03-02 10:27:58 +0100402static int llist_count(struct llist_head *head)
403{
404 struct llist_head *list;
405 int i = 0;
406
407 llist_for_each(list, head)
408 i++;
409
410 return i;
411}
412
Harald Welteebb80ed2016-03-02 13:56:59 +0100413/* handle a single USB command as received from the USB host */
Harald Welte0eaa9922016-03-04 03:03:49 +0100414static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100415{
416 struct cardemu_usb_msg_hdr *hdr;
Harald Welte06b27f62016-03-02 14:26:38 +0100417 struct cardemu_usb_msg_set_atr *atr;
Harald Welte0eaa9922016-03-04 03:03:49 +0100418 struct cardemu_usb_msg_cardinsert *cardins;
Harald Welteebb80ed2016-03-02 13:56:59 +0100419 struct llist_head *queue;
420
421 hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
422 switch (hdr->msg_type) {
423 case CEMU_USB_MSGT_DT_TX_DATA:
Harald Welte0eaa9922016-03-04 03:03:49 +0100424 queue = card_emu_get_uart_tx_queue(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100425 req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
426 llist_add_tail(&rctx->list, queue);
Harald Welte0eaa9922016-03-04 03:03:49 +0100427 card_emu_have_new_uart_tx(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100428 break;
429 case CEMU_USB_MSGT_DT_SET_ATR:
Harald Welte06b27f62016-03-02 14:26:38 +0100430 atr = (struct cardemu_usb_msg_set_atr *) hdr;
Harald Welted295b922016-03-18 21:01:36 +0100431 card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
Harald Welte06b27f62016-03-02 14:26:38 +0100432 req_ctx_put(rctx);
433 break;
Harald Welte0eaa9922016-03-04 03:03:49 +0100434 case CEMU_USB_MSGT_DT_CARDINSERT:
435 cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
436 if (cardins->card_insert)
437 PIO_Set(&ci->pin_insert);
438 else
439 PIO_Clear(&ci->pin_insert);
Harald Welte5820ea92016-03-16 22:12:00 +0100440 req_ctx_put(rctx);
Harald Welte0eaa9922016-03-04 03:03:49 +0100441 break;
Harald Welteebb80ed2016-03-02 13:56:59 +0100442 case CEMU_USB_MSGT_DT_GET_STATUS:
Harald Welteff160652016-03-19 21:59:06 +0100443 card_emu_report_status(ci->ch);
444 break;
445 case CEMU_USB_MSGT_DT_GET_STATS:
Harald Welteebb80ed2016-03-02 13:56:59 +0100446 default:
447 /* FIXME */
Harald Welte5820ea92016-03-16 22:12:00 +0100448 req_ctx_put(rctx);
Harald Welteebb80ed2016-03-02 13:56:59 +0100449 break;
450 }
451}
452
Harald Welteb26d0032016-03-19 13:33:02 +0100453static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci)
454{
455 struct req_ctx *segm;
456 struct cardemu_usb_msg_hdr *mh;
457 int i = 0;
458
459 /* check if we have multiple concatenated commands in
460 * one message. USB endpoints are streams that don't
461 * preserve the message boundaries */
462 mh = (struct cardemu_usb_msg_hdr *) rctx->data;
463 TRACE_DEBUG("rctx->tot_len=%d, mh->msg_len=%d\r\n",
464 rctx->tot_len, mh->msg_len);
465 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)) {
476 TRACE_DEBUG("Segment %d, offs=%d, len=%d\r\n", i,
477 (uint8_t *)mh - rctx->data, mh->msg_len);
478 segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING);
479 if (!segm) {
480 TRACE_ERROR("ENOMEM during rctx segmentation\r\n");
481 break;
482 }
483 segm->idx = 0;
484 segm->tot_len = mh->msg_len;
485 memcpy(segm->data, mh, segm->tot_len);
486 dispatch_usb_command(segm, ci);
487 i++;
488 }
489
490 /* release the master req_ctx, as all segments have been
491 * processed now */
492 req_ctx_put(rctx);
493}
494
Harald Welteebb80ed2016-03-02 13:56:59 +0100495/* iterate over the queue of incoming USB commands and dispatch/execute
496 * them */
Harald Welte9f240b62016-03-18 10:32:56 +0100497static void process_any_usb_commands(struct llist_head *main_q,
498 struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100499{
Harald Welte9f240b62016-03-18 10:32:56 +0100500 struct llist_head *lh;
501 struct req_ctx *rctx;
502 int i;
Harald Welteebb80ed2016-03-02 13:56:59 +0100503
Harald Welte9f240b62016-03-18 10:32:56 +0100504 /* limit the number of iterations to 10, to ensure we don't get
505 * stuck here without returning to main loop processing */
506 for (i = 0; i < 10; i++) {
507 /* de-queue the list head in an irq-safe way */
508 lh = llist_head_dequeue_irqsafe(main_q);
509 if (!lh)
510 break;
511 rctx = llist_entry(lh, struct req_ctx, list);
Harald Welteb26d0032016-03-19 13:33:02 +0100512 dispatch_received_rctx(rctx, ci);
Harald Welte5820ea92016-03-16 22:12:00 +0100513 }
Harald Welteebb80ed2016-03-02 13:56:59 +0100514}
515
Harald Welte2a6d3af2016-02-28 19:29:14 +0100516/* main loop function, called repeatedly */
517void mode_cardemu_run(void)
518{
Harald Welteacae4122016-03-02 10:27:58 +0100519 struct llist_head *queue;
Harald Welte13e82022016-03-02 15:17:53 +0100520 unsigned int i;
Harald Welteacae4122016-03-02 10:27:58 +0100521
Harald Welte13e82022016-03-02 15:17:53 +0100522 for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
523 struct cardem_inst *ci = &cardem_inst[i];
524
Harald Welte54cb3d02016-02-29 14:12:40 +0100525 /* drain the ring buffer from UART into card_emu */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100526 while (1) {
527 __disable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100528 if (rbuf_is_empty(&ci->rb)) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100529 __enable_irq();
530 break;
531 }
Harald Welte13e82022016-03-02 15:17:53 +0100532 uint8_t byte = rbuf_read(&ci->rb);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100533 __enable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100534 card_emu_process_rx_byte(ci->ch, byte);
Harald Welteacae4122016-03-02 10:27:58 +0100535 TRACE_ERROR("Rx%02x\r\n", byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100536 }
Harald Welteacae4122016-03-02 10:27:58 +0100537
Harald Welte13e82022016-03-02 15:17:53 +0100538 queue = card_emu_get_usb_tx_queue(ci->ch);
Harald Welteacae4122016-03-02 10:27:58 +0100539 int usb_pending = llist_count(queue);
Harald Welte13e82022016-03-02 15:17:53 +0100540 if (usb_pending != ci->usb_pending_old) {
Harald Welteacae4122016-03-02 10:27:58 +0100541// printf("usb_pending=%d\r\n", usb_pending);
Harald Welte13e82022016-03-02 15:17:53 +0100542 ci->usb_pending_old = usb_pending;
Harald Welteacae4122016-03-02 10:27:58 +0100543 }
Harald Welte13e82022016-03-02 15:17:53 +0100544 usb_refill_to_host(queue, ci->ep_in);
Harald Welteacae4122016-03-02 10:27:58 +0100545
Harald Welteebb80ed2016-03-02 13:56:59 +0100546 /* ensure we can handle incoming USB messages from the
547 * host */
Harald Welte13e82022016-03-02 15:17:53 +0100548 queue = &ci->usb_out_queue;
549 usb_refill_from_host(queue, ci->ep_out);
Harald Welte0eaa9922016-03-04 03:03:49 +0100550 process_any_usb_commands(queue, ci);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100551 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100552}