blob: 00742d68e276d35fbb8185752f48512409c86497 [file] [log] [blame]
Harald Welte53079bb2016-03-20 14:58:35 +01001//#define TRACE_LEVEL 6
Harald Welte7abdb512016-03-03 17:48:32 +01002
Harald Welte2a6d3af2016-02-28 19:29:14 +01003#include "board.h"
Harald Welte16055642016-03-03 11:02:45 +01004#include "simtrace.h"
5#include "ringbuffer.h"
Harald Welte2a6d3af2016-02-28 19:29:14 +01006#include "card_emu.h"
Harald Weltebd717682016-02-28 19:30:05 +01007#include "iso7816_fidi.h"
Harald Welte54cb3d02016-02-29 14:12:40 +01008#include "utils.h"
Harald Welteacae4122016-03-02 10:27:58 +01009#include "linuxlist.h"
Harald Welte9f240b62016-03-18 10:32:56 +010010#include "llist_irqsafe.h"
Harald Welteebb80ed2016-03-02 13:56:59 +010011#include "req_ctx.h"
12#include "cardemu_prot.h"
Harald Weltebd717682016-02-28 19:30:05 +010013
14#define TRACE_ENTRY() TRACE_DEBUG("%s entering\n", __func__)
Harald Welte2a6d3af2016-02-28 19:29:14 +010015
16static const Pin pins_cardsim[] = PINS_CARDSIM;
17
18/* UART pins */
19static const Pin pins_usim1[] = {PINS_USIM1};
20static const Pin pin_usim1_rst = PIN_USIM1_nRST;
21static const Pin pin_usim1_vcc = PIN_USIM1_VCC;
22
23#ifdef CARDEMU_SECOND_UART
Harald Welte6dcacf32016-03-19 14:01:31 +010024static const Pin pins_usim2[] = {PINS_USIM2};
Harald Welte2a6d3af2016-02-28 19:29:14 +010025static const Pin pin_usim2_rst = PIN_USIM2_nRST;
26static const Pin pin_usim2_vcc = PIN_USIM2_VCC;
27#endif
28
Harald Welte13e82022016-03-02 15:17:53 +010029struct cardem_inst {
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 Welte28772eb2016-03-20 15:44:52 +0100231 uint32_t chip_arch = CHIPID->CIDR & CHIPID_CIDR_ARCH_Msk;
232 uint32_t chip_ver = CHIPID->CIDR & CHIPID_CIDR_VERSION_Msk;
233
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;
296}
297
298void ADC_IrqHandler(void)
299{
300#ifdef CARDEMU_SECOND_UART
301 if (ADC->ADC_ISR & ADC_ISR_EOC6) {
302 uint16_t val = ADC->ADC_CDR[6] & 0xFFF;
303 cardem_inst[1].vcc_uv = adc2uv(val);
304 process_vcc_adc(&cardem_inst[1]);
Harald Welte28772eb2016-03-20 15:44:52 +0100305 if (adc_sam3s_reva_errata) {
306 /* Errata: START doesn't start a conversion
307 * sequence, but only a single conversion */
308 ADC->ADC_CR |= ADC_CR_START;
309 }
Harald Welte07872b62016-03-20 11:45:36 +0100310 }
311#endif
Harald Welte419eb8a2016-03-20 10:04:03 +0100312
313 if (ADC->ADC_ISR & ADC_ISR_EOC7) {
Harald Welte07872b62016-03-20 11:45:36 +0100314 uint16_t val = ADC->ADC_CDR[7] & 0xFFF;
315 cardem_inst[0].vcc_uv = adc2uv(val);
316 process_vcc_adc(&cardem_inst[0]);
317 ADC->ADC_CR |= ADC_CR_START;
Harald Welte419eb8a2016-03-20 10:04:03 +0100318 }
319}
Harald Welte07872b62016-03-20 11:45:36 +0100320#endif /* DETECT_VCC_BY_ADC */
Harald Welte419eb8a2016-03-20 10:04:03 +0100321
322/***********************************************************************
Harald Welte2a6d3af2016-02-28 19:29:14 +0100323 * Core USB / mainloop integration
324 ***********************************************************************/
325
Harald Weltec0bd7f02016-02-29 10:13:33 +0100326static void usim1_rst_irqhandler(const Pin *pPin)
327{
328 int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
Harald Welte13e82022016-03-02 15:17:53 +0100329 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100330}
331
Harald Welte07872b62016-03-20 11:45:36 +0100332#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100333static void usim1_vcc_irqhandler(const Pin *pPin)
334{
335 int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
Harald Welte13e82022016-03-02 15:17:53 +0100336 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100337 /* FIXME do this for real */
Harald Welte13e82022016-03-02 15:17:53 +0100338 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100339}
Harald Welte07872b62016-03-20 11:45:36 +0100340#endif /* !DETECT_VCC_BY_ADC */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100341
Harald Welte13e82022016-03-02 15:17:53 +0100342#ifdef CARDEMU_SECOND_UART
343static void usim2_rst_irqhandler(const Pin *pPin)
344{
345 int active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
346 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
347}
348
Harald Welte07872b62016-03-20 11:45:36 +0100349#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100350static void usim2_vcc_irqhandler(const Pin *pPin)
351{
352 int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
353 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
354 /* FIXME do this for real */
355 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
356}
Harald Welte07872b62016-03-20 11:45:36 +0100357#endif /* !DETECT_VCC_BY_ADC */
358#endif /* CARDEMU_SECOND_UART */
Harald Welte13e82022016-03-02 15:17:53 +0100359
Harald Welte2a6d3af2016-02-28 19:29:14 +0100360/* executed once at system boot for each config */
361void mode_cardemu_configure(void)
362{
Harald Weltebd717682016-02-28 19:30:05 +0100363 TRACE_ENTRY();
Harald Welte2a6d3af2016-02-28 19:29:14 +0100364}
365
366/* called if config is activated */
367void mode_cardemu_init(void)
368{
Harald Welte13e82022016-03-02 15:17:53 +0100369 int i;
Harald Weltebd717682016-02-28 19:30:05 +0100370
Harald Welte13e82022016-03-02 15:17:53 +0100371 TRACE_ENTRY();
Harald Weltec0bd7f02016-02-29 10:13:33 +0100372
Harald Welte2a6d3af2016-02-28 19:29:14 +0100373 PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
Harald Welte07872b62016-03-20 11:45:36 +0100374#ifdef DETECT_VCC_BY_ADC
375 card_vcc_adc_init();
376#endif /* DETECT_VCC_BY_ADC */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100377
Harald Welte13e82022016-03-02 15:17:53 +0100378 INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
379 rbuf_reset(&cardem_inst[0].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100380 PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
Harald Welte13e82022016-03-02 15:17:53 +0100381 ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100382 NVIC_EnableIRQ(USART1_IRQn);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100383 PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
384 PIO_EnableIt(&pin_usim1_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100385#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100386 PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
387 PIO_EnableIt(&pin_usim1_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100388#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100389 cardem_inst[0].ch = card_emu_init(0, 2, 0);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100390
391#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100392 INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
393 rbuf_reset(&cardem_inst[1].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100394 PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
Harald Welte13e82022016-03-02 15:17:53 +0100395 ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100396 NVIC_EnableIRQ(USART0_IRQn);
Harald Welte13e82022016-03-02 15:17:53 +0100397 PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
398 PIO_EnableIt(&pin_usim2_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100399#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100400 PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
401 PIO_EnableIt(&pin_usim2_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100402#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100403 cardem_inst[1].ch = card_emu_init(1, 0, 1);
Harald Welte07872b62016-03-20 11:45:36 +0100404#endif /* CARDEMU_SECOND_UART */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100405}
406
407/* called if config is deactivated */
408void mode_cardemu_exit(void)
409{
Harald Weltebd717682016-02-28 19:30:05 +0100410 TRACE_ENTRY();
411
Harald Welte7abdb512016-03-03 17:48:32 +0100412 /* FIXME: stop tc_fdt */
413 /* FIXME: release all rctx, unlink them from any queue */
414
Harald Weltec0bd7f02016-02-29 10:13:33 +0100415 PIO_DisableIt(&pin_usim1_rst);
416 PIO_DisableIt(&pin_usim1_vcc);
417
Harald Welte2a6d3af2016-02-28 19:29:14 +0100418 NVIC_DisableIRQ(USART1_IRQn);
419 USART_SetTransmitterEnabled(USART1, 0);
420 USART_SetReceiverEnabled(USART1, 0);
421
422#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100423 PIO_DisableIt(&pin_usim2_rst);
424 PIO_DisableIt(&pin_usim2_vcc);
425
Harald Welte2a6d3af2016-02-28 19:29:14 +0100426 NVIC_DisableIRQ(USART0_IRQn);
427 USART_SetTransmitterEnabled(USART0, 0);
428 USART_SetReceiverEnabled(USART0, 0);
429#endif
430}
431
Harald Welteacae4122016-03-02 10:27:58 +0100432static int llist_count(struct llist_head *head)
433{
434 struct llist_head *list;
435 int i = 0;
436
437 llist_for_each(list, head)
438 i++;
439
440 return i;
441}
442
Harald Welteebb80ed2016-03-02 13:56:59 +0100443/* handle a single USB command as received from the USB host */
Harald Welte0eaa9922016-03-04 03:03:49 +0100444static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100445{
446 struct cardemu_usb_msg_hdr *hdr;
Harald Welte06b27f62016-03-02 14:26:38 +0100447 struct cardemu_usb_msg_set_atr *atr;
Harald Welte0eaa9922016-03-04 03:03:49 +0100448 struct cardemu_usb_msg_cardinsert *cardins;
Harald Welteebb80ed2016-03-02 13:56:59 +0100449 struct llist_head *queue;
450
451 hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
452 switch (hdr->msg_type) {
453 case CEMU_USB_MSGT_DT_TX_DATA:
Harald Welte0eaa9922016-03-04 03:03:49 +0100454 queue = card_emu_get_uart_tx_queue(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100455 req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
456 llist_add_tail(&rctx->list, queue);
Harald Welte0eaa9922016-03-04 03:03:49 +0100457 card_emu_have_new_uart_tx(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100458 break;
459 case CEMU_USB_MSGT_DT_SET_ATR:
Harald Welte06b27f62016-03-02 14:26:38 +0100460 atr = (struct cardemu_usb_msg_set_atr *) hdr;
Harald Welted295b922016-03-18 21:01:36 +0100461 card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
Harald Welte06b27f62016-03-02 14:26:38 +0100462 req_ctx_put(rctx);
463 break;
Harald Welte0eaa9922016-03-04 03:03:49 +0100464 case CEMU_USB_MSGT_DT_CARDINSERT:
465 cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
Harald Weltedde112e2016-03-20 16:42:11 +0100466 TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
467 cardins->card_insert ? "INSERTED" : "REMOVED");
Harald Welte0eaa9922016-03-04 03:03:49 +0100468 if (cardins->card_insert)
469 PIO_Set(&ci->pin_insert);
470 else
471 PIO_Clear(&ci->pin_insert);
Harald Welte5820ea92016-03-16 22:12:00 +0100472 req_ctx_put(rctx);
Harald Welte0eaa9922016-03-04 03:03:49 +0100473 break;
Harald Welteebb80ed2016-03-02 13:56:59 +0100474 case CEMU_USB_MSGT_DT_GET_STATUS:
Harald Welteff160652016-03-19 21:59:06 +0100475 card_emu_report_status(ci->ch);
476 break;
477 case CEMU_USB_MSGT_DT_GET_STATS:
Harald Welteebb80ed2016-03-02 13:56:59 +0100478 default:
479 /* FIXME */
Harald Welte5820ea92016-03-16 22:12:00 +0100480 req_ctx_put(rctx);
Harald Welteebb80ed2016-03-02 13:56:59 +0100481 break;
482 }
483}
484
Harald Welteb26d0032016-03-19 13:33:02 +0100485static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci)
486{
487 struct req_ctx *segm;
488 struct cardemu_usb_msg_hdr *mh;
489 int i = 0;
490
491 /* check if we have multiple concatenated commands in
492 * one message. USB endpoints are streams that don't
493 * preserve the message boundaries */
494 mh = (struct cardemu_usb_msg_hdr *) rctx->data;
Harald Welteb26d0032016-03-19 13:33:02 +0100495 if (mh->msg_len == rctx->tot_len) {
496 /* fast path: only one message in buffer */
497 dispatch_usb_command(rctx, ci);
498 return;
499 }
500
501 /* slow path: iterate over list of messages, allocating one new
502 * reqe_ctx per segment */
503 for (mh = (struct cardemu_usb_msg_hdr *) rctx->data;
504 (uint8_t *)mh < rctx->data + rctx->tot_len;
505 mh = (struct cardemu_usb_msg_hdr * ) ((uint8_t *)mh + mh->msg_len)) {
Harald Welteb26d0032016-03-19 13:33:02 +0100506 segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING);
507 if (!segm) {
Harald Weltedde112e2016-03-20 16:42:11 +0100508 TRACE_ERROR("%u: ENOMEM during rctx segmentation\r\n",
509 ci->num);
Harald Welteb26d0032016-03-19 13:33:02 +0100510 break;
511 }
512 segm->idx = 0;
513 segm->tot_len = mh->msg_len;
514 memcpy(segm->data, mh, segm->tot_len);
515 dispatch_usb_command(segm, ci);
516 i++;
517 }
518
519 /* release the master req_ctx, as all segments have been
520 * processed now */
521 req_ctx_put(rctx);
522}
523
Harald Welteebb80ed2016-03-02 13:56:59 +0100524/* iterate over the queue of incoming USB commands and dispatch/execute
525 * them */
Harald Welte9f240b62016-03-18 10:32:56 +0100526static void process_any_usb_commands(struct llist_head *main_q,
527 struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100528{
Harald Welte9f240b62016-03-18 10:32:56 +0100529 struct llist_head *lh;
530 struct req_ctx *rctx;
531 int i;
Harald Welteebb80ed2016-03-02 13:56:59 +0100532
Harald Welte9f240b62016-03-18 10:32:56 +0100533 /* limit the number of iterations to 10, to ensure we don't get
534 * stuck here without returning to main loop processing */
535 for (i = 0; i < 10; i++) {
536 /* de-queue the list head in an irq-safe way */
537 lh = llist_head_dequeue_irqsafe(main_q);
538 if (!lh)
539 break;
540 rctx = llist_entry(lh, struct req_ctx, list);
Harald Welteb26d0032016-03-19 13:33:02 +0100541 dispatch_received_rctx(rctx, ci);
Harald Welte5820ea92016-03-16 22:12:00 +0100542 }
Harald Welteebb80ed2016-03-02 13:56:59 +0100543}
544
Harald Welte2a6d3af2016-02-28 19:29:14 +0100545/* main loop function, called repeatedly */
546void mode_cardemu_run(void)
547{
Harald Welteacae4122016-03-02 10:27:58 +0100548 struct llist_head *queue;
Harald Welte13e82022016-03-02 15:17:53 +0100549 unsigned int i;
Harald Welteacae4122016-03-02 10:27:58 +0100550
Harald Welte13e82022016-03-02 15:17:53 +0100551 for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
552 struct cardem_inst *ci = &cardem_inst[i];
553
Harald Welte54cb3d02016-02-29 14:12:40 +0100554 /* drain the ring buffer from UART into card_emu */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100555 while (1) {
556 __disable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100557 if (rbuf_is_empty(&ci->rb)) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100558 __enable_irq();
559 break;
560 }
Harald Welte13e82022016-03-02 15:17:53 +0100561 uint8_t byte = rbuf_read(&ci->rb);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100562 __enable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100563 card_emu_process_rx_byte(ci->ch, byte);
Harald Weltedde112e2016-03-20 16:42:11 +0100564 //TRACE_ERROR("%uRx%02x\r\n", i, byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100565 }
Harald Welteacae4122016-03-02 10:27:58 +0100566
Harald Welte13e82022016-03-02 15:17:53 +0100567 queue = card_emu_get_usb_tx_queue(ci->ch);
Harald Welteacae4122016-03-02 10:27:58 +0100568 int usb_pending = llist_count(queue);
Harald Welte13e82022016-03-02 15:17:53 +0100569 if (usb_pending != ci->usb_pending_old) {
Harald Weltedde112e2016-03-20 16:42:11 +0100570 TRACE_DEBUG("%u usb_pending=%d\r\n",
571 i, usb_pending);
Harald Welte13e82022016-03-02 15:17:53 +0100572 ci->usb_pending_old = usb_pending;
Harald Welteacae4122016-03-02 10:27:58 +0100573 }
Harald Welte13e82022016-03-02 15:17:53 +0100574 usb_refill_to_host(queue, ci->ep_in);
Harald Welteacae4122016-03-02 10:27:58 +0100575
Harald Welteebb80ed2016-03-02 13:56:59 +0100576 /* ensure we can handle incoming USB messages from the
577 * host */
Harald Welte13e82022016-03-02 15:17:53 +0100578 queue = &ci->usb_out_queue;
579 usb_refill_from_host(queue, ci->ep_out);
Harald Welte0eaa9922016-03-04 03:03:49 +0100580 process_any_usb_commands(queue, ci);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100581 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100582}