blob: b4925be040021eb1399b61151612738366b30064 [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
Harald Weltefd9c0412016-03-20 18:15:57 +010014#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\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 {
Harald Weltedde112e2016-03-20 16:42:11 +010030 uint32_t num;
Harald Welte13e82022016-03-02 15:17:53 +010031 struct card_handle *ch;
32 struct llist_head usb_out_queue;
33 struct ringbuf rb;
34 struct Usart_info usart_info;
35 int usb_pending_old;
36 uint8_t ep_out;
37 uint8_t ep_in;
38 uint8_t ep_int;
Harald Welte0eaa9922016-03-04 03:03:49 +010039 const Pin pin_insert;
Harald Welte07872b62016-03-20 11:45:36 +010040 uint32_t vcc_uv;
41 uint32_t vcc_uv_last;
Harald Welte13e82022016-03-02 15:17:53 +010042};
Harald Welte2a6d3af2016-02-28 19:29:14 +010043
Harald Welte13e82022016-03-02 15:17:53 +010044static struct cardem_inst cardem_inst[] = {
Harald Welte2a6d3af2016-02-28 19:29:14 +010045 {
Harald Weltedde112e2016-03-20 16:42:11 +010046 .num = 0,
Harald Welte13e82022016-03-02 15:17:53 +010047 .usart_info = {
48 .base = USART1,
49 .id = ID_USART1,
50 .state = USART_RCV
51 },
52 .ep_out = PHONE_DATAOUT,
53 .ep_in = PHONE_DATAIN,
54 .ep_int = PHONE_INT,
Harald Welte0eaa9922016-03-04 03:03:49 +010055 .pin_insert = PIN_SET_USIM1_PRES,
Harald Welte2a6d3af2016-02-28 19:29:14 +010056 },
57#ifdef CARDEMU_SECOND_UART
58 {
Harald Weltedde112e2016-03-20 16:42:11 +010059 .num = 1,
Harald Welte13e82022016-03-02 15:17:53 +010060 .usart_info = {
61 .base = USART0,
62 .id = ID_USART0,
63 .state = USART_RCV
64 },
65 .ep_out = CARDEM_USIM2_DATAOUT,
66 .ep_in = CARDEM_USIM2_DATAIN,
67 .ep_int = CARDEM_USIM2_INT,
Harald Welte0eaa9922016-03-04 03:03:49 +010068 .pin_insert = PIN_SET_USIM2_PRES,
Harald Welte2a6d3af2016-02-28 19:29:14 +010069 },
70#endif
71};
72
73static Usart *get_usart_by_chan(uint8_t uart_chan)
74{
75 switch (uart_chan) {
76 case 0:
77 return USART1;
78#ifdef CARDEMU_SECOND_UART
79 case 1:
80 return USART0;
81#endif
82 }
83 return NULL;
84}
85
86/***********************************************************************
87 * Call-Backs from card_emu.c
88 ***********************************************************************/
89
Harald Weltec8beefb2016-03-20 14:40:47 +010090static void wait_tx_idle(Usart *usart)
91{
92 int i = 1;
93
94 /* wait until last char has been fully transmitted */
95 while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) {
96 if (!(i%1000000)) {
97 TRACE_ERROR("s: %x \r\n", usart->US_CSR);
98 }
99 i++;
100 }
101}
102
Harald Weltec58bba02016-03-20 14:57:53 +0100103void card_emu_uart_wait_tx_idle(uint8_t uart_chan)
104{
105 Usart *usart = get_usart_by_chan(uart_chan);
106 wait_tx_idle(usart);
107}
108
Harald Welte2a6d3af2016-02-28 19:29:14 +0100109/* call-back from card_emu.c to enable/disable transmit and/or receive */
110void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
111{
112 Usart *usart = get_usart_by_chan(uart_chan);
113 switch (rxtx) {
114 case ENABLE_TX:
Harald Welte9dbc46e2016-02-29 10:05:10 +0100115 USART_DisableIt(usart, ~US_IER_TXRDY);
Harald Weltec8beefb2016-03-20 14:40:47 +0100116 /* as irritating as it is, we actually want to keep the
117 * receiver enabled during transmit */
118 USART_SetReceiverEnabled(usart, 1);
Harald Welte8a416b12016-03-01 00:42:04 +0100119 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
120 USART_EnableIt(usart, US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100121 USART_SetTransmitterEnabled(usart, 1);
122 break;
123 case ENABLE_RX:
Harald Welte9dbc46e2016-02-29 10:05:10 +0100124 USART_DisableIt(usart, ~US_IER_RXRDY);
Harald Weltec8beefb2016-03-20 14:40:47 +0100125 /* as irritating as it is, we actually want to keep the
126 * transmitter enabled during receive */
127 USART_SetTransmitterEnabled(usart, 1);
128 wait_tx_idle(usart);
Harald Welte8a416b12016-03-01 00:42:04 +0100129 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
130 USART_EnableIt(usart, US_IER_RXRDY);
131 USART_SetReceiverEnabled(usart, 1);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100132 break;
133 case 0:
134 default:
135 USART_SetTransmitterEnabled(usart, 0);
136 USART_SetReceiverEnabled(usart, 0);
Harald Welte9dbc46e2016-02-29 10:05:10 +0100137 USART_DisableIt(usart, 0xFFFFFFFF);
Harald Welte8a416b12016-03-01 00:42:04 +0100138 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100139 break;
140 }
141}
142
143/* call-back from card_emu.c to transmit a byte */
144int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
145{
Harald Welte13e82022016-03-02 15:17:53 +0100146 Usart *usart = get_usart_by_chan(uart_chan);
147#if 0
Harald Welte2a6d3af2016-02-28 19:29:14 +0100148 Usart_info *ui = &usart_info[uart_chan];
149 ISO7816_SendChar(byte, ui);
Harald Welte13e82022016-03-02 15:17:53 +0100150#else
Harald Welte53079bb2016-03-20 14:58:35 +0100151 int i = 1;
Harald Welte13e82022016-03-02 15:17:53 +0100152 while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
153 if (!(i%1000000)) {
Harald Weltedde112e2016-03-20 16:42:11 +0100154 TRACE_ERROR("%u: s: %x %02X\r\n",
155 uart_chan, usart->US_CSR,
156 usart->US_RHR & 0xFF);
Harald Welte13e82022016-03-02 15:17:53 +0100157 usart->US_CR = US_CR_RSTTX;
158 usart->US_CR = US_CR_RSTRX;
159 }
Harald Welte53079bb2016-03-20 14:58:35 +0100160 i++;
Harald Welte13e82022016-03-02 15:17:53 +0100161 }
162 usart->US_THR = byte;
Harald Welte53079bb2016-03-20 14:58:35 +0100163 //TRACE_ERROR("Sx%02x\r\n", byte);
Harald Welte13e82022016-03-02 15:17:53 +0100164#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +0100165 return 1;
166}
167
168
169/* FIXME: integrate this with actual irq handler */
Harald Welte3bafe432016-03-20 16:43:12 +0100170static void usart_irq_rx(uint8_t inst_num)
Harald Welte2a6d3af2016-02-28 19:29:14 +0100171{
Harald Welte3bafe432016-03-20 16:43:12 +0100172 Usart *usart = get_usart_by_chan(inst_num);
173 struct cardem_inst *ci = &cardem_inst[inst_num];
Harald Weltec0bd7f02016-02-29 10:13:33 +0100174 uint32_t csr;
175 uint8_t byte = 0;
176
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;
Harald Weltedde112e2016-03-20 16:42:11 +0100192 TRACE_ERROR("%u e 0x%x st: 0x%x\n", ci->num, byte, csr);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100193 }
194}
195
Harald Welte3bafe432016-03-20 16:43:12 +0100196void mode_cardemu_usart0_irq(void)
197{
198 /* USART0 == Instance 1 == USIM 2 */
199 usart_irq_rx(1);
200}
201
202void mode_cardemu_usart1_irq(void)
203{
204 /* USART1 == Instance 0 == USIM 1 */
205 usart_irq_rx(0);
206}
207
Harald Weltebd717682016-02-28 19:30:05 +0100208/* call-back from card_emu.c to change UART baud rate */
209int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
210{
211 int rc;
Harald Weltebd717682016-02-28 19:30:05 +0100212 Usart *usart = get_usart_by_chan(uart_chan);
213
Harald Welte99f62a62016-02-29 10:08:49 +0100214 usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
215 usart->US_FIDI = fidi & 0x3ff;
216 usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
217 return 0;
Harald Weltebd717682016-02-28 19:30:05 +0100218}
Harald Welte2a6d3af2016-02-28 19:29:14 +0100219
220/***********************************************************************
Harald Welte419eb8a2016-03-20 10:04:03 +0100221 * ADC for VCC voltage detection
222 ***********************************************************************/
223
Harald Welte07872b62016-03-20 11:45:36 +0100224#ifdef DETECT_VCC_BY_ADC
225
226static int adc_triggered = 0;
Harald Welte28772eb2016-03-20 15:44:52 +0100227static int adc_sam3s_reva_errata = 0;
Harald Welte07872b62016-03-20 11:45:36 +0100228
Harald Welte419eb8a2016-03-20 10:04:03 +0100229static int card_vcc_adc_init(void)
230{
Harald Welte622b6be2016-03-20 16:43:59 +0100231 uint32_t chip_arch = CHIPID->CHIPID_CIDR & CHIPID_CIDR_ARCH_Msk;
232 uint32_t chip_ver = CHIPID->CHIPID_CIDR & CHIPID_CIDR_VERSION_Msk;
Harald Welte28772eb2016-03-20 15:44:52 +0100233
Harald Welte07872b62016-03-20 11:45:36 +0100234 PMC_EnablePeripheral(ID_ADC);
235
Harald Welte419eb8a2016-03-20 10:04:03 +0100236 ADC->ADC_CR |= ADC_CR_SWRST;
Harald Welte28772eb2016-03-20 15:44:52 +0100237 if (chip_ver == 0 &&
238 (chip_arch == CHIPID_CIDR_ARCH_SAM3SxA ||
239 chip_arch == CHIPID_CIDR_ARCH_SAM3SxB ||
240 chip_arch == CHIPID_CIDR_ARCH_SAM3SxC)) {
241 TRACE_INFO("Enabling Rev.A ADC Errata work-around\r\n");
242 adc_sam3s_reva_errata = 1;
243 }
244
245 if (adc_sam3s_reva_errata) {
246 /* Errata Work-Around to clear EOCx flags */
Harald Welte07872b62016-03-20 11:45:36 +0100247 volatile uint32_t foo;
248 int i;
249 for (i = 0; i < 16; i++)
250 foo = ADC->ADC_CDR[i];
251 }
252
253 /* Initialize ADC for AD7 / AD6, fADC=48/24=2MHz */
Harald Welte419eb8a2016-03-20 10:04:03 +0100254 ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_LOWRES_BITS_12 |
255 ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF |
Harald Welte07872b62016-03-20 11:45:36 +0100256 ADC_MR_FREERUN_OFF | ADC_MR_PRESCAL(23) |
257 ADC_MR_STARTUP_SUT8 | ADC_MR_SETTLING(3) |
258 ADC_MR_ANACH_NONE | ADC_MR_TRACKTIM(4) |
Harald Welte419eb8a2016-03-20 10:04:03 +0100259 ADC_MR_TRANSFER(1) | ADC_MR_USEQ_NUM_ORDER;
260 /* enable AD6 + AD7 channels */
Harald Welte07872b62016-03-20 11:45:36 +0100261 ADC->ADC_CHER = ADC_CHER_CH7;
262 ADC->ADC_IER = ADC_IER_EOC7;
263#ifdef CARDEMU_SECOND_UART
264 ADC->ADC_CHER |= ADC_CHER_CH6;
265 ADC->ADC_IER |= ADC_IER_EOC6;
266#endif
267 NVIC_EnableIRQ(ADC_IRQn);
Harald Welte419eb8a2016-03-20 10:04:03 +0100268 ADC->ADC_CR |= ADC_CR_START;
Harald Welte07872b62016-03-20 11:45:36 +0100269
270 return 0;
Harald Welte419eb8a2016-03-20 10:04:03 +0100271}
272
Harald Welte07872b62016-03-20 11:45:36 +0100273#define UV_PER_LSB ((3300 * 1000) / 4096)
274#define VCC_UV_THRESH_1V8 1500000
275#define VCC_UV_THRESH_3V 2800000
276
277static void process_vcc_adc(struct cardem_inst *ci)
Harald Welte419eb8a2016-03-20 10:04:03 +0100278{
Harald Welte07872b62016-03-20 11:45:36 +0100279 if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
280 ci->vcc_uv_last < VCC_UV_THRESH_3V) {
281 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1);
282 /* FIXME do this for real */
283 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1);
284 } else if (ci->vcc_uv < VCC_UV_THRESH_3V &&
285 ci->vcc_uv_last >= VCC_UV_THRESH_3V) {
286 /* FIXME do this for real */
287 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0);
288 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0);
Harald Welte419eb8a2016-03-20 10:04:03 +0100289 }
Harald Welte07872b62016-03-20 11:45:36 +0100290 ci->vcc_uv_last = ci->vcc_uv;
291}
292
293static uint32_t adc2uv(uint16_t adc)
294{
295 uint32_t uv = (uint32_t) adc * UV_PER_LSB;
Harald Welte622b6be2016-03-20 16:43:59 +0100296 return uv;
Harald Welte07872b62016-03-20 11:45:36 +0100297}
298
299void ADC_IrqHandler(void)
300{
301#ifdef CARDEMU_SECOND_UART
302 if (ADC->ADC_ISR & ADC_ISR_EOC6) {
303 uint16_t val = ADC->ADC_CDR[6] & 0xFFF;
304 cardem_inst[1].vcc_uv = adc2uv(val);
305 process_vcc_adc(&cardem_inst[1]);
Harald Welte28772eb2016-03-20 15:44:52 +0100306 if (adc_sam3s_reva_errata) {
307 /* Errata: START doesn't start a conversion
308 * sequence, but only a single conversion */
309 ADC->ADC_CR |= ADC_CR_START;
310 }
Harald Welte07872b62016-03-20 11:45:36 +0100311 }
312#endif
Harald Welte419eb8a2016-03-20 10:04:03 +0100313
314 if (ADC->ADC_ISR & ADC_ISR_EOC7) {
Harald Welte07872b62016-03-20 11:45:36 +0100315 uint16_t val = ADC->ADC_CDR[7] & 0xFFF;
316 cardem_inst[0].vcc_uv = adc2uv(val);
317 process_vcc_adc(&cardem_inst[0]);
318 ADC->ADC_CR |= ADC_CR_START;
Harald Welte419eb8a2016-03-20 10:04:03 +0100319 }
320}
Harald Welte07872b62016-03-20 11:45:36 +0100321#endif /* DETECT_VCC_BY_ADC */
Harald Welte419eb8a2016-03-20 10:04:03 +0100322
323/***********************************************************************
Harald Welte2a6d3af2016-02-28 19:29:14 +0100324 * Core USB / mainloop integration
325 ***********************************************************************/
326
Harald Weltec0bd7f02016-02-29 10:13:33 +0100327static void usim1_rst_irqhandler(const Pin *pPin)
328{
329 int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
Harald Welte13e82022016-03-02 15:17:53 +0100330 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100331}
332
Harald Welte07872b62016-03-20 11:45:36 +0100333#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100334static void usim1_vcc_irqhandler(const Pin *pPin)
335{
336 int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
Harald Welte13e82022016-03-02 15:17:53 +0100337 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100338 /* FIXME do this for real */
Harald Welte13e82022016-03-02 15:17:53 +0100339 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100340}
Harald Welte07872b62016-03-20 11:45:36 +0100341#endif /* !DETECT_VCC_BY_ADC */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100342
Harald Welte13e82022016-03-02 15:17:53 +0100343#ifdef CARDEMU_SECOND_UART
344static void usim2_rst_irqhandler(const Pin *pPin)
345{
346 int active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
347 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
348}
349
Harald Welte07872b62016-03-20 11:45:36 +0100350#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100351static void usim2_vcc_irqhandler(const Pin *pPin)
352{
353 int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
354 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
355 /* FIXME do this for real */
356 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
357}
Harald Welte07872b62016-03-20 11:45:36 +0100358#endif /* !DETECT_VCC_BY_ADC */
359#endif /* CARDEMU_SECOND_UART */
Harald Welte13e82022016-03-02 15:17:53 +0100360
Harald Welte2a6d3af2016-02-28 19:29:14 +0100361/* executed once at system boot for each config */
362void mode_cardemu_configure(void)
363{
Harald Weltebd717682016-02-28 19:30:05 +0100364 TRACE_ENTRY();
Harald Welte2a6d3af2016-02-28 19:29:14 +0100365}
366
367/* called if config is activated */
368void mode_cardemu_init(void)
369{
Harald Welte13e82022016-03-02 15:17:53 +0100370 int i;
Harald Weltebd717682016-02-28 19:30:05 +0100371
Harald Welte13e82022016-03-02 15:17:53 +0100372 TRACE_ENTRY();
Harald Weltec0bd7f02016-02-29 10:13:33 +0100373
Harald Welte2a6d3af2016-02-28 19:29:14 +0100374 PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
Harald Welte07872b62016-03-20 11:45:36 +0100375#ifdef DETECT_VCC_BY_ADC
376 card_vcc_adc_init();
377#endif /* DETECT_VCC_BY_ADC */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100378
Harald Welte13e82022016-03-02 15:17:53 +0100379 INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
380 rbuf_reset(&cardem_inst[0].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100381 PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
Harald Welte13e82022016-03-02 15:17:53 +0100382 ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100383 NVIC_EnableIRQ(USART1_IRQn);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100384 PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
385 PIO_EnableIt(&pin_usim1_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100386#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100387 PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
388 PIO_EnableIt(&pin_usim1_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100389#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100390 cardem_inst[0].ch = card_emu_init(0, 2, 0);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100391
392#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100393 INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
394 rbuf_reset(&cardem_inst[1].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100395 PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
Harald Welte13e82022016-03-02 15:17:53 +0100396 ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100397 NVIC_EnableIRQ(USART0_IRQn);
Harald Welte13e82022016-03-02 15:17:53 +0100398 PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
399 PIO_EnableIt(&pin_usim2_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100400#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100401 PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
402 PIO_EnableIt(&pin_usim2_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100403#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100404 cardem_inst[1].ch = card_emu_init(1, 0, 1);
Harald Welte07872b62016-03-20 11:45:36 +0100405#endif /* CARDEMU_SECOND_UART */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100406}
407
408/* called if config is deactivated */
409void mode_cardemu_exit(void)
410{
Harald Weltebd717682016-02-28 19:30:05 +0100411 TRACE_ENTRY();
412
Harald Welte7abdb512016-03-03 17:48:32 +0100413 /* FIXME: stop tc_fdt */
414 /* FIXME: release all rctx, unlink them from any queue */
415
Harald Weltec0bd7f02016-02-29 10:13:33 +0100416 PIO_DisableIt(&pin_usim1_rst);
417 PIO_DisableIt(&pin_usim1_vcc);
418
Harald Welte2a6d3af2016-02-28 19:29:14 +0100419 NVIC_DisableIRQ(USART1_IRQn);
420 USART_SetTransmitterEnabled(USART1, 0);
421 USART_SetReceiverEnabled(USART1, 0);
422
423#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100424 PIO_DisableIt(&pin_usim2_rst);
425 PIO_DisableIt(&pin_usim2_vcc);
426
Harald Welte2a6d3af2016-02-28 19:29:14 +0100427 NVIC_DisableIRQ(USART0_IRQn);
428 USART_SetTransmitterEnabled(USART0, 0);
429 USART_SetReceiverEnabled(USART0, 0);
430#endif
431}
432
Harald Welteacae4122016-03-02 10:27:58 +0100433static int llist_count(struct llist_head *head)
434{
435 struct llist_head *list;
436 int i = 0;
437
438 llist_for_each(list, head)
439 i++;
440
441 return i;
442}
443
Harald Welteebb80ed2016-03-02 13:56:59 +0100444/* handle a single USB command as received from the USB host */
Harald Welte0eaa9922016-03-04 03:03:49 +0100445static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100446{
447 struct cardemu_usb_msg_hdr *hdr;
Harald Welte06b27f62016-03-02 14:26:38 +0100448 struct cardemu_usb_msg_set_atr *atr;
Harald Welte0eaa9922016-03-04 03:03:49 +0100449 struct cardemu_usb_msg_cardinsert *cardins;
Harald Welteebb80ed2016-03-02 13:56:59 +0100450 struct llist_head *queue;
451
452 hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
453 switch (hdr->msg_type) {
454 case CEMU_USB_MSGT_DT_TX_DATA:
Harald Welte0eaa9922016-03-04 03:03:49 +0100455 queue = card_emu_get_uart_tx_queue(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100456 req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
457 llist_add_tail(&rctx->list, queue);
Harald Welte0eaa9922016-03-04 03:03:49 +0100458 card_emu_have_new_uart_tx(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100459 break;
460 case CEMU_USB_MSGT_DT_SET_ATR:
Harald Welte06b27f62016-03-02 14:26:38 +0100461 atr = (struct cardemu_usb_msg_set_atr *) hdr;
Harald Welted295b922016-03-18 21:01:36 +0100462 card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
Harald Welte06b27f62016-03-02 14:26:38 +0100463 req_ctx_put(rctx);
464 break;
Harald Welte0eaa9922016-03-04 03:03:49 +0100465 case CEMU_USB_MSGT_DT_CARDINSERT:
466 cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
Harald Weltedde112e2016-03-20 16:42:11 +0100467 TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
468 cardins->card_insert ? "INSERTED" : "REMOVED");
Harald Welte0eaa9922016-03-04 03:03:49 +0100469 if (cardins->card_insert)
470 PIO_Set(&ci->pin_insert);
471 else
472 PIO_Clear(&ci->pin_insert);
Harald Welte5820ea92016-03-16 22:12:00 +0100473 req_ctx_put(rctx);
Harald Welte0eaa9922016-03-04 03:03:49 +0100474 break;
Harald Welteebb80ed2016-03-02 13:56:59 +0100475 case CEMU_USB_MSGT_DT_GET_STATUS:
Harald Welteff160652016-03-19 21:59:06 +0100476 card_emu_report_status(ci->ch);
477 break;
478 case CEMU_USB_MSGT_DT_GET_STATS:
Harald Welteebb80ed2016-03-02 13:56:59 +0100479 default:
480 /* FIXME */
Harald Welte5820ea92016-03-16 22:12:00 +0100481 req_ctx_put(rctx);
Harald Welteebb80ed2016-03-02 13:56:59 +0100482 break;
483 }
484}
485
Harald Welteb26d0032016-03-19 13:33:02 +0100486static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci)
487{
488 struct req_ctx *segm;
489 struct cardemu_usb_msg_hdr *mh;
490 int i = 0;
491
492 /* check if we have multiple concatenated commands in
493 * one message. USB endpoints are streams that don't
494 * preserve the message boundaries */
495 mh = (struct cardemu_usb_msg_hdr *) rctx->data;
Harald Welteb26d0032016-03-19 13:33:02 +0100496 if (mh->msg_len == rctx->tot_len) {
497 /* fast path: only one message in buffer */
498 dispatch_usb_command(rctx, ci);
499 return;
500 }
501
502 /* slow path: iterate over list of messages, allocating one new
503 * reqe_ctx per segment */
504 for (mh = (struct cardemu_usb_msg_hdr *) rctx->data;
505 (uint8_t *)mh < rctx->data + rctx->tot_len;
506 mh = (struct cardemu_usb_msg_hdr * ) ((uint8_t *)mh + mh->msg_len)) {
Harald Welteb26d0032016-03-19 13:33:02 +0100507 segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING);
508 if (!segm) {
Harald Weltedde112e2016-03-20 16:42:11 +0100509 TRACE_ERROR("%u: ENOMEM during rctx segmentation\r\n",
510 ci->num);
Harald Welteb26d0032016-03-19 13:33:02 +0100511 break;
512 }
513 segm->idx = 0;
514 segm->tot_len = mh->msg_len;
515 memcpy(segm->data, mh, segm->tot_len);
516 dispatch_usb_command(segm, ci);
517 i++;
518 }
519
520 /* release the master req_ctx, as all segments have been
521 * processed now */
522 req_ctx_put(rctx);
523}
524
Harald Welteebb80ed2016-03-02 13:56:59 +0100525/* iterate over the queue of incoming USB commands and dispatch/execute
526 * them */
Harald Welte9f240b62016-03-18 10:32:56 +0100527static void process_any_usb_commands(struct llist_head *main_q,
528 struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100529{
Harald Welte9f240b62016-03-18 10:32:56 +0100530 struct llist_head *lh;
531 struct req_ctx *rctx;
532 int i;
Harald Welteebb80ed2016-03-02 13:56:59 +0100533
Harald Welte9f240b62016-03-18 10:32:56 +0100534 /* limit the number of iterations to 10, to ensure we don't get
535 * stuck here without returning to main loop processing */
536 for (i = 0; i < 10; i++) {
537 /* de-queue the list head in an irq-safe way */
538 lh = llist_head_dequeue_irqsafe(main_q);
539 if (!lh)
540 break;
541 rctx = llist_entry(lh, struct req_ctx, list);
Harald Welteb26d0032016-03-19 13:33:02 +0100542 dispatch_received_rctx(rctx, ci);
Harald Welte5820ea92016-03-16 22:12:00 +0100543 }
Harald Welteebb80ed2016-03-02 13:56:59 +0100544}
545
Harald Welte2a6d3af2016-02-28 19:29:14 +0100546/* main loop function, called repeatedly */
547void mode_cardemu_run(void)
548{
Harald Welteacae4122016-03-02 10:27:58 +0100549 struct llist_head *queue;
Harald Welte13e82022016-03-02 15:17:53 +0100550 unsigned int i;
Harald Welteacae4122016-03-02 10:27:58 +0100551
Harald Welte13e82022016-03-02 15:17:53 +0100552 for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
553 struct cardem_inst *ci = &cardem_inst[i];
554
Harald Welte54cb3d02016-02-29 14:12:40 +0100555 /* drain the ring buffer from UART into card_emu */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100556 while (1) {
557 __disable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100558 if (rbuf_is_empty(&ci->rb)) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100559 __enable_irq();
560 break;
561 }
Harald Welte13e82022016-03-02 15:17:53 +0100562 uint8_t byte = rbuf_read(&ci->rb);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100563 __enable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100564 card_emu_process_rx_byte(ci->ch, byte);
Harald Weltedde112e2016-03-20 16:42:11 +0100565 //TRACE_ERROR("%uRx%02x\r\n", i, byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100566 }
Harald Welteacae4122016-03-02 10:27:58 +0100567
Harald Welte13e82022016-03-02 15:17:53 +0100568 queue = card_emu_get_usb_tx_queue(ci->ch);
Harald Welteacae4122016-03-02 10:27:58 +0100569 int usb_pending = llist_count(queue);
Harald Welte13e82022016-03-02 15:17:53 +0100570 if (usb_pending != ci->usb_pending_old) {
Harald Weltedde112e2016-03-20 16:42:11 +0100571 TRACE_DEBUG("%u usb_pending=%d\r\n",
572 i, usb_pending);
Harald Welte13e82022016-03-02 15:17:53 +0100573 ci->usb_pending_old = usb_pending;
Harald Welteacae4122016-03-02 10:27:58 +0100574 }
Harald Welte13e82022016-03-02 15:17:53 +0100575 usb_refill_to_host(queue, ci->ep_in);
Harald Welteacae4122016-03-02 10:27:58 +0100576
Harald Welteebb80ed2016-03-02 13:56:59 +0100577 /* ensure we can handle incoming USB messages from the
578 * host */
Harald Welte13e82022016-03-02 15:17:53 +0100579 queue = &ci->usb_out_queue;
580 usb_refill_from_host(queue, ci->ep_out);
Harald Welte0eaa9922016-03-04 03:03:49 +0100581 process_any_usb_commands(queue, ci);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100582 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100583}