blob: 13a5b738904b19345ebb7a349a4aa0636d5b37fa [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 Welteb41598b2017-02-04 12:15:58 +01009#include "osmocom/core/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
Harald Welte6d1128e2017-05-05 20:23:10 +020016#ifdef PINS_CARDSIM
Harald Welte2a6d3af2016-02-28 19:29:14 +010017static const Pin pins_cardsim[] = PINS_CARDSIM;
Harald Welte6d1128e2017-05-05 20:23:10 +020018#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +010019
20/* UART pins */
21static const Pin pins_usim1[] = {PINS_USIM1};
22static const Pin pin_usim1_rst = PIN_USIM1_nRST;
23static const Pin pin_usim1_vcc = PIN_USIM1_VCC;
24
25#ifdef CARDEMU_SECOND_UART
Harald Welte6dcacf32016-03-19 14:01:31 +010026static const Pin pins_usim2[] = {PINS_USIM2};
Harald Welte2a6d3af2016-02-28 19:29:14 +010027static const Pin pin_usim2_rst = PIN_USIM2_nRST;
28static const Pin pin_usim2_vcc = PIN_USIM2_VCC;
29#endif
30
Harald Welte13e82022016-03-02 15:17:53 +010031struct cardem_inst {
Harald Weltedde112e2016-03-20 16:42:11 +010032 uint32_t num;
Harald Welte13e82022016-03-02 15:17:53 +010033 struct card_handle *ch;
34 struct llist_head usb_out_queue;
35 struct ringbuf rb;
36 struct Usart_info usart_info;
37 int usb_pending_old;
38 uint8_t ep_out;
39 uint8_t ep_in;
40 uint8_t ep_int;
Harald Welte0eaa9922016-03-04 03:03:49 +010041 const Pin pin_insert;
Harald Welte07872b62016-03-20 11:45:36 +010042 uint32_t vcc_uv;
43 uint32_t vcc_uv_last;
Harald Welte13e82022016-03-02 15:17:53 +010044};
Harald Welte2a6d3af2016-02-28 19:29:14 +010045
Harald Welte13e82022016-03-02 15:17:53 +010046static struct cardem_inst cardem_inst[] = {
Harald Welte2a6d3af2016-02-28 19:29:14 +010047 {
Harald Weltedde112e2016-03-20 16:42:11 +010048 .num = 0,
Harald Welte13e82022016-03-02 15:17:53 +010049 .usart_info = {
50 .base = USART1,
51 .id = ID_USART1,
52 .state = USART_RCV
53 },
54 .ep_out = PHONE_DATAOUT,
55 .ep_in = PHONE_DATAIN,
56 .ep_int = PHONE_INT,
Harald Welte6d1128e2017-05-05 20:23:10 +020057#ifdef PIN_SET_USIM1_PRES
Harald Welte0eaa9922016-03-04 03:03:49 +010058 .pin_insert = PIN_SET_USIM1_PRES,
Harald Welte6d1128e2017-05-05 20:23:10 +020059#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +010060 },
61#ifdef CARDEMU_SECOND_UART
62 {
Harald Weltedde112e2016-03-20 16:42:11 +010063 .num = 1,
Harald Welte13e82022016-03-02 15:17:53 +010064 .usart_info = {
65 .base = USART0,
66 .id = ID_USART0,
67 .state = USART_RCV
68 },
69 .ep_out = CARDEM_USIM2_DATAOUT,
70 .ep_in = CARDEM_USIM2_DATAIN,
71 .ep_int = CARDEM_USIM2_INT,
Harald Welte6d1128e2017-05-05 20:23:10 +020072#ifdef PIN_SET_USIM2_PRES
Harald Welte0eaa9922016-03-04 03:03:49 +010073 .pin_insert = PIN_SET_USIM2_PRES,
Harald Welte6d1128e2017-05-05 20:23:10 +020074#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +010075 },
76#endif
77};
78
79static Usart *get_usart_by_chan(uint8_t uart_chan)
80{
81 switch (uart_chan) {
82 case 0:
83 return USART1;
84#ifdef CARDEMU_SECOND_UART
85 case 1:
86 return USART0;
87#endif
88 }
89 return NULL;
90}
91
92/***********************************************************************
93 * Call-Backs from card_emu.c
94 ***********************************************************************/
95
Harald Weltec8beefb2016-03-20 14:40:47 +010096static void wait_tx_idle(Usart *usart)
97{
98 int i = 1;
99
100 /* wait until last char has been fully transmitted */
101 while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) {
102 if (!(i%1000000)) {
103 TRACE_ERROR("s: %x \r\n", usart->US_CSR);
104 }
105 i++;
106 }
107}
108
Harald Weltec58bba02016-03-20 14:57:53 +0100109void card_emu_uart_wait_tx_idle(uint8_t uart_chan)
110{
111 Usart *usart = get_usart_by_chan(uart_chan);
112 wait_tx_idle(usart);
113}
114
Harald Welte2a6d3af2016-02-28 19:29:14 +0100115/* call-back from card_emu.c to enable/disable transmit and/or receive */
116void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
117{
118 Usart *usart = get_usart_by_chan(uart_chan);
119 switch (rxtx) {
120 case ENABLE_TX:
Harald Welte9dbc46e2016-02-29 10:05:10 +0100121 USART_DisableIt(usart, ~US_IER_TXRDY);
Harald Weltec8beefb2016-03-20 14:40:47 +0100122 /* as irritating as it is, we actually want to keep the
123 * receiver enabled during transmit */
124 USART_SetReceiverEnabled(usart, 1);
Harald Welte8a416b12016-03-01 00:42:04 +0100125 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
126 USART_EnableIt(usart, US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100127 USART_SetTransmitterEnabled(usart, 1);
128 break;
129 case ENABLE_RX:
Harald Welte9dbc46e2016-02-29 10:05:10 +0100130 USART_DisableIt(usart, ~US_IER_RXRDY);
Harald Weltec8beefb2016-03-20 14:40:47 +0100131 /* as irritating as it is, we actually want to keep the
132 * transmitter enabled during receive */
133 USART_SetTransmitterEnabled(usart, 1);
134 wait_tx_idle(usart);
Harald Welte8a416b12016-03-01 00:42:04 +0100135 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
136 USART_EnableIt(usart, US_IER_RXRDY);
137 USART_SetReceiverEnabled(usart, 1);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100138 break;
139 case 0:
140 default:
141 USART_SetTransmitterEnabled(usart, 0);
142 USART_SetReceiverEnabled(usart, 0);
Harald Welte9dbc46e2016-02-29 10:05:10 +0100143 USART_DisableIt(usart, 0xFFFFFFFF);
Harald Welte8a416b12016-03-01 00:42:04 +0100144 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100145 break;
146 }
147}
148
149/* call-back from card_emu.c to transmit a byte */
150int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
151{
Harald Welte13e82022016-03-02 15:17:53 +0100152 Usart *usart = get_usart_by_chan(uart_chan);
153#if 0
Harald Welte2a6d3af2016-02-28 19:29:14 +0100154 Usart_info *ui = &usart_info[uart_chan];
155 ISO7816_SendChar(byte, ui);
Harald Welte13e82022016-03-02 15:17:53 +0100156#else
Harald Welte53079bb2016-03-20 14:58:35 +0100157 int i = 1;
Harald Welte13e82022016-03-02 15:17:53 +0100158 while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
159 if (!(i%1000000)) {
Harald Weltedde112e2016-03-20 16:42:11 +0100160 TRACE_ERROR("%u: s: %x %02X\r\n",
161 uart_chan, usart->US_CSR,
162 usart->US_RHR & 0xFF);
Harald Welte13e82022016-03-02 15:17:53 +0100163 usart->US_CR = US_CR_RSTTX;
164 usart->US_CR = US_CR_RSTRX;
165 }
Harald Welte53079bb2016-03-20 14:58:35 +0100166 i++;
Harald Welte13e82022016-03-02 15:17:53 +0100167 }
168 usart->US_THR = byte;
Harald Welte53079bb2016-03-20 14:58:35 +0100169 //TRACE_ERROR("Sx%02x\r\n", byte);
Harald Welte13e82022016-03-02 15:17:53 +0100170#endif
Harald Welte2a6d3af2016-02-28 19:29:14 +0100171 return 1;
172}
173
174
175/* FIXME: integrate this with actual irq handler */
Harald Welte3bafe432016-03-20 16:43:12 +0100176static void usart_irq_rx(uint8_t inst_num)
Harald Welte2a6d3af2016-02-28 19:29:14 +0100177{
Harald Welte3bafe432016-03-20 16:43:12 +0100178 Usart *usart = get_usart_by_chan(inst_num);
179 struct cardem_inst *ci = &cardem_inst[inst_num];
Harald Weltec0bd7f02016-02-29 10:13:33 +0100180 uint32_t csr;
181 uint8_t byte = 0;
182
Harald Welteda15ca02016-03-17 21:14:04 +0100183 csr = usart->US_CSR & usart->US_IMR;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100184
Harald Weltec0bd7f02016-02-29 10:13:33 +0100185 if (csr & US_CSR_RXRDY) {
186 byte = (usart->US_RHR) & 0xFF;
Harald Welte13e82022016-03-02 15:17:53 +0100187 rbuf_write(&ci->rb, byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100188 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100189
Harald Welte12d4bdf2016-03-02 10:31:03 +0100190 if (csr & US_CSR_TXRDY) {
Harald Welte13e82022016-03-02 15:17:53 +0100191 if (card_emu_tx_byte(ci->ch) == 0)
Harald Welte12d4bdf2016-03-02 10:31:03 +0100192 USART_DisableIt(usart, US_IER_TXRDY);
193 }
194
Harald Welte2a6d3af2016-02-28 19:29:14 +0100195 if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
196 US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100197 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Harald Weltedde112e2016-03-20 16:42:11 +0100198 TRACE_ERROR("%u e 0x%x st: 0x%x\n", ci->num, byte, csr);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100199 }
200}
201
Harald Welte3bafe432016-03-20 16:43:12 +0100202void mode_cardemu_usart0_irq(void)
203{
204 /* USART0 == Instance 1 == USIM 2 */
205 usart_irq_rx(1);
206}
207
208void mode_cardemu_usart1_irq(void)
209{
210 /* USART1 == Instance 0 == USIM 1 */
211 usart_irq_rx(0);
212}
213
Harald Weltebd717682016-02-28 19:30:05 +0100214/* call-back from card_emu.c to change UART baud rate */
215int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
216{
217 int rc;
Harald Weltebd717682016-02-28 19:30:05 +0100218 Usart *usart = get_usart_by_chan(uart_chan);
219
Harald Welte99f62a62016-02-29 10:08:49 +0100220 usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
221 usart->US_FIDI = fidi & 0x3ff;
222 usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
223 return 0;
Harald Weltebd717682016-02-28 19:30:05 +0100224}
Harald Welte2a6d3af2016-02-28 19:29:14 +0100225
226/***********************************************************************
Harald Welte419eb8a2016-03-20 10:04:03 +0100227 * ADC for VCC voltage detection
228 ***********************************************************************/
229
Harald Welte07872b62016-03-20 11:45:36 +0100230#ifdef DETECT_VCC_BY_ADC
231
232static int adc_triggered = 0;
Harald Welte28772eb2016-03-20 15:44:52 +0100233static int adc_sam3s_reva_errata = 0;
Harald Welte07872b62016-03-20 11:45:36 +0100234
Harald Welte419eb8a2016-03-20 10:04:03 +0100235static int card_vcc_adc_init(void)
236{
Harald Welte622b6be2016-03-20 16:43:59 +0100237 uint32_t chip_arch = CHIPID->CHIPID_CIDR & CHIPID_CIDR_ARCH_Msk;
238 uint32_t chip_ver = CHIPID->CHIPID_CIDR & CHIPID_CIDR_VERSION_Msk;
Harald Welte28772eb2016-03-20 15:44:52 +0100239
Harald Welte07872b62016-03-20 11:45:36 +0100240 PMC_EnablePeripheral(ID_ADC);
241
Harald Welte419eb8a2016-03-20 10:04:03 +0100242 ADC->ADC_CR |= ADC_CR_SWRST;
Harald Welte28772eb2016-03-20 15:44:52 +0100243 if (chip_ver == 0 &&
244 (chip_arch == CHIPID_CIDR_ARCH_SAM3SxA ||
245 chip_arch == CHIPID_CIDR_ARCH_SAM3SxB ||
246 chip_arch == CHIPID_CIDR_ARCH_SAM3SxC)) {
247 TRACE_INFO("Enabling Rev.A ADC Errata work-around\r\n");
248 adc_sam3s_reva_errata = 1;
249 }
250
251 if (adc_sam3s_reva_errata) {
252 /* Errata Work-Around to clear EOCx flags */
Harald Welte07872b62016-03-20 11:45:36 +0100253 volatile uint32_t foo;
254 int i;
255 for (i = 0; i < 16; i++)
256 foo = ADC->ADC_CDR[i];
257 }
258
259 /* Initialize ADC for AD7 / AD6, fADC=48/24=2MHz */
Harald Welte419eb8a2016-03-20 10:04:03 +0100260 ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_LOWRES_BITS_12 |
261 ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF |
Harald Welte07872b62016-03-20 11:45:36 +0100262 ADC_MR_FREERUN_OFF | ADC_MR_PRESCAL(23) |
263 ADC_MR_STARTUP_SUT8 | ADC_MR_SETTLING(3) |
264 ADC_MR_ANACH_NONE | ADC_MR_TRACKTIM(4) |
Harald Welte419eb8a2016-03-20 10:04:03 +0100265 ADC_MR_TRANSFER(1) | ADC_MR_USEQ_NUM_ORDER;
266 /* enable AD6 + AD7 channels */
Harald Welte07872b62016-03-20 11:45:36 +0100267 ADC->ADC_CHER = ADC_CHER_CH7;
268 ADC->ADC_IER = ADC_IER_EOC7;
269#ifdef CARDEMU_SECOND_UART
270 ADC->ADC_CHER |= ADC_CHER_CH6;
271 ADC->ADC_IER |= ADC_IER_EOC6;
272#endif
273 NVIC_EnableIRQ(ADC_IRQn);
Harald Welte419eb8a2016-03-20 10:04:03 +0100274 ADC->ADC_CR |= ADC_CR_START;
Harald Welte07872b62016-03-20 11:45:36 +0100275
276 return 0;
Harald Welte419eb8a2016-03-20 10:04:03 +0100277}
278
Harald Welte07872b62016-03-20 11:45:36 +0100279#define UV_PER_LSB ((3300 * 1000) / 4096)
280#define VCC_UV_THRESH_1V8 1500000
281#define VCC_UV_THRESH_3V 2800000
282
283static void process_vcc_adc(struct cardem_inst *ci)
Harald Welte419eb8a2016-03-20 10:04:03 +0100284{
Harald Welte07872b62016-03-20 11:45:36 +0100285 if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
286 ci->vcc_uv_last < VCC_UV_THRESH_3V) {
287 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1);
288 /* FIXME do this for real */
289 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1);
290 } else if (ci->vcc_uv < VCC_UV_THRESH_3V &&
291 ci->vcc_uv_last >= VCC_UV_THRESH_3V) {
292 /* FIXME do this for real */
293 card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0);
294 card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0);
Harald Welte419eb8a2016-03-20 10:04:03 +0100295 }
Harald Welte07872b62016-03-20 11:45:36 +0100296 ci->vcc_uv_last = ci->vcc_uv;
297}
298
299static uint32_t adc2uv(uint16_t adc)
300{
301 uint32_t uv = (uint32_t) adc * UV_PER_LSB;
Harald Welte622b6be2016-03-20 16:43:59 +0100302 return uv;
Harald Welte07872b62016-03-20 11:45:36 +0100303}
304
305void ADC_IrqHandler(void)
306{
307#ifdef CARDEMU_SECOND_UART
308 if (ADC->ADC_ISR & ADC_ISR_EOC6) {
309 uint16_t val = ADC->ADC_CDR[6] & 0xFFF;
310 cardem_inst[1].vcc_uv = adc2uv(val);
311 process_vcc_adc(&cardem_inst[1]);
Harald Welte28772eb2016-03-20 15:44:52 +0100312 if (adc_sam3s_reva_errata) {
313 /* Errata: START doesn't start a conversion
314 * sequence, but only a single conversion */
315 ADC->ADC_CR |= ADC_CR_START;
316 }
Harald Welte07872b62016-03-20 11:45:36 +0100317 }
318#endif
Harald Welte419eb8a2016-03-20 10:04:03 +0100319
320 if (ADC->ADC_ISR & ADC_ISR_EOC7) {
Harald Welte07872b62016-03-20 11:45:36 +0100321 uint16_t val = ADC->ADC_CDR[7] & 0xFFF;
322 cardem_inst[0].vcc_uv = adc2uv(val);
323 process_vcc_adc(&cardem_inst[0]);
324 ADC->ADC_CR |= ADC_CR_START;
Harald Welte419eb8a2016-03-20 10:04:03 +0100325 }
326}
Harald Welte07872b62016-03-20 11:45:36 +0100327#endif /* DETECT_VCC_BY_ADC */
Harald Welte419eb8a2016-03-20 10:04:03 +0100328
329/***********************************************************************
Harald Welte2a6d3af2016-02-28 19:29:14 +0100330 * Core USB / mainloop integration
331 ***********************************************************************/
332
Harald Weltec0bd7f02016-02-29 10:13:33 +0100333static void usim1_rst_irqhandler(const Pin *pPin)
334{
335 int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
Harald Welte13e82022016-03-02 15:17:53 +0100336 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100337}
338
Harald Welte07872b62016-03-20 11:45:36 +0100339#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100340static void usim1_vcc_irqhandler(const Pin *pPin)
341{
342 int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
Harald Welte13e82022016-03-02 15:17:53 +0100343 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100344 /* FIXME do this for real */
Harald Welte13e82022016-03-02 15:17:53 +0100345 card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100346}
Harald Welte07872b62016-03-20 11:45:36 +0100347#endif /* !DETECT_VCC_BY_ADC */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100348
Harald Welte13e82022016-03-02 15:17:53 +0100349#ifdef CARDEMU_SECOND_UART
350static void usim2_rst_irqhandler(const Pin *pPin)
351{
352 int active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
353 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
354}
355
Harald Welte07872b62016-03-20 11:45:36 +0100356#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100357static void usim2_vcc_irqhandler(const Pin *pPin)
358{
359 int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
360 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
361 /* FIXME do this for real */
362 card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
363}
Harald Welte07872b62016-03-20 11:45:36 +0100364#endif /* !DETECT_VCC_BY_ADC */
365#endif /* CARDEMU_SECOND_UART */
Harald Welte13e82022016-03-02 15:17:53 +0100366
Harald Welte2a6d3af2016-02-28 19:29:14 +0100367/* executed once at system boot for each config */
368void mode_cardemu_configure(void)
369{
Harald Weltebd717682016-02-28 19:30:05 +0100370 TRACE_ENTRY();
Harald Welte2a6d3af2016-02-28 19:29:14 +0100371}
372
373/* called if config is activated */
374void mode_cardemu_init(void)
375{
Harald Welte13e82022016-03-02 15:17:53 +0100376 int i;
Harald Weltebd717682016-02-28 19:30:05 +0100377
Harald Welte13e82022016-03-02 15:17:53 +0100378 TRACE_ENTRY();
Harald Weltec0bd7f02016-02-29 10:13:33 +0100379
Harald Welte6d1128e2017-05-05 20:23:10 +0200380#ifdef PINS_CARDSIM
Harald Welte2a6d3af2016-02-28 19:29:14 +0100381 PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
Harald Welte6d1128e2017-05-05 20:23:10 +0200382#endif
Harald Welte07872b62016-03-20 11:45:36 +0100383#ifdef DETECT_VCC_BY_ADC
384 card_vcc_adc_init();
385#endif /* DETECT_VCC_BY_ADC */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100386
Harald Welte13e82022016-03-02 15:17:53 +0100387 INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
388 rbuf_reset(&cardem_inst[0].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100389 PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
Harald Welte13e82022016-03-02 15:17:53 +0100390 ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100391 NVIC_EnableIRQ(USART1_IRQn);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100392 PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
393 PIO_EnableIt(&pin_usim1_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100394#ifndef DETECT_VCC_BY_ADC
Harald Weltec0bd7f02016-02-29 10:13:33 +0100395 PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
396 PIO_EnableIt(&pin_usim1_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100397#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100398 cardem_inst[0].ch = card_emu_init(0, 2, 0);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100399
400#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100401 INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
402 rbuf_reset(&cardem_inst[1].rb);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100403 PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
Harald Welte13e82022016-03-02 15:17:53 +0100404 ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100405 NVIC_EnableIRQ(USART0_IRQn);
Harald Welte13e82022016-03-02 15:17:53 +0100406 PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
407 PIO_EnableIt(&pin_usim2_rst);
Harald Welte07872b62016-03-20 11:45:36 +0100408#ifndef DETECT_VCC_BY_ADC
Harald Welte13e82022016-03-02 15:17:53 +0100409 PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
410 PIO_EnableIt(&pin_usim2_vcc);
Harald Welte07872b62016-03-20 11:45:36 +0100411#endif /* DETECT_VCC_BY_ADC */
Harald Welte13e82022016-03-02 15:17:53 +0100412 cardem_inst[1].ch = card_emu_init(1, 0, 1);
Harald Welte07872b62016-03-20 11:45:36 +0100413#endif /* CARDEMU_SECOND_UART */
Harald Welte2a6d3af2016-02-28 19:29:14 +0100414}
415
416/* called if config is deactivated */
417void mode_cardemu_exit(void)
418{
Harald Weltebd717682016-02-28 19:30:05 +0100419 TRACE_ENTRY();
420
Harald Welte7abdb512016-03-03 17:48:32 +0100421 /* FIXME: stop tc_fdt */
422 /* FIXME: release all rctx, unlink them from any queue */
423
Harald Weltec0bd7f02016-02-29 10:13:33 +0100424 PIO_DisableIt(&pin_usim1_rst);
425 PIO_DisableIt(&pin_usim1_vcc);
426
Harald Welte2a6d3af2016-02-28 19:29:14 +0100427 NVIC_DisableIRQ(USART1_IRQn);
428 USART_SetTransmitterEnabled(USART1, 0);
429 USART_SetReceiverEnabled(USART1, 0);
430
431#ifdef CARDEMU_SECOND_UART
Harald Welte13e82022016-03-02 15:17:53 +0100432 PIO_DisableIt(&pin_usim2_rst);
433 PIO_DisableIt(&pin_usim2_vcc);
434
Harald Welte2a6d3af2016-02-28 19:29:14 +0100435 NVIC_DisableIRQ(USART0_IRQn);
436 USART_SetTransmitterEnabled(USART0, 0);
437 USART_SetReceiverEnabled(USART0, 0);
438#endif
439}
440
Harald Welteebb80ed2016-03-02 13:56:59 +0100441/* handle a single USB command as received from the USB host */
Harald Welte0eaa9922016-03-04 03:03:49 +0100442static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100443{
444 struct cardemu_usb_msg_hdr *hdr;
Harald Welte06b27f62016-03-02 14:26:38 +0100445 struct cardemu_usb_msg_set_atr *atr;
Harald Welte0eaa9922016-03-04 03:03:49 +0100446 struct cardemu_usb_msg_cardinsert *cardins;
Harald Welteebb80ed2016-03-02 13:56:59 +0100447 struct llist_head *queue;
448
449 hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
450 switch (hdr->msg_type) {
451 case CEMU_USB_MSGT_DT_TX_DATA:
Harald Welte0eaa9922016-03-04 03:03:49 +0100452 queue = card_emu_get_uart_tx_queue(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100453 req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
454 llist_add_tail(&rctx->list, queue);
Harald Welte0eaa9922016-03-04 03:03:49 +0100455 card_emu_have_new_uart_tx(ci->ch);
Harald Welteebb80ed2016-03-02 13:56:59 +0100456 break;
457 case CEMU_USB_MSGT_DT_SET_ATR:
Harald Welte06b27f62016-03-02 14:26:38 +0100458 atr = (struct cardemu_usb_msg_set_atr *) hdr;
Harald Welted295b922016-03-18 21:01:36 +0100459 card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
Harald Welte06b27f62016-03-02 14:26:38 +0100460 req_ctx_put(rctx);
461 break;
Harald Welte0eaa9922016-03-04 03:03:49 +0100462 case CEMU_USB_MSGT_DT_CARDINSERT:
463 cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
Harald Weltedde112e2016-03-20 16:42:11 +0100464 TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
465 cardins->card_insert ? "INSERTED" : "REMOVED");
Harald Welte0eaa9922016-03-04 03:03:49 +0100466 if (cardins->card_insert)
467 PIO_Set(&ci->pin_insert);
468 else
469 PIO_Clear(&ci->pin_insert);
Harald Welte5820ea92016-03-16 22:12:00 +0100470 req_ctx_put(rctx);
Harald Welte0eaa9922016-03-04 03:03:49 +0100471 break;
Harald Welteebb80ed2016-03-02 13:56:59 +0100472 case CEMU_USB_MSGT_DT_GET_STATUS:
Harald Welteff160652016-03-19 21:59:06 +0100473 card_emu_report_status(ci->ch);
474 break;
475 case CEMU_USB_MSGT_DT_GET_STATS:
Harald Welteebb80ed2016-03-02 13:56:59 +0100476 default:
477 /* FIXME */
Harald Welte5820ea92016-03-16 22:12:00 +0100478 req_ctx_put(rctx);
Harald Welteebb80ed2016-03-02 13:56:59 +0100479 break;
480 }
481}
482
Harald Welteb26d0032016-03-19 13:33:02 +0100483static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci)
484{
485 struct req_ctx *segm;
486 struct cardemu_usb_msg_hdr *mh;
487 int i = 0;
488
489 /* check if we have multiple concatenated commands in
490 * one message. USB endpoints are streams that don't
491 * preserve the message boundaries */
492 mh = (struct cardemu_usb_msg_hdr *) rctx->data;
Harald Welteb26d0032016-03-19 13:33:02 +0100493 if (mh->msg_len == rctx->tot_len) {
494 /* fast path: only one message in buffer */
495 dispatch_usb_command(rctx, ci);
496 return;
497 }
498
499 /* slow path: iterate over list of messages, allocating one new
500 * reqe_ctx per segment */
501 for (mh = (struct cardemu_usb_msg_hdr *) rctx->data;
502 (uint8_t *)mh < rctx->data + rctx->tot_len;
503 mh = (struct cardemu_usb_msg_hdr * ) ((uint8_t *)mh + mh->msg_len)) {
Harald Welteb26d0032016-03-19 13:33:02 +0100504 segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING);
505 if (!segm) {
Harald Weltedde112e2016-03-20 16:42:11 +0100506 TRACE_ERROR("%u: ENOMEM during rctx segmentation\r\n",
507 ci->num);
Harald Welteb26d0032016-03-19 13:33:02 +0100508 break;
509 }
510 segm->idx = 0;
511 segm->tot_len = mh->msg_len;
512 memcpy(segm->data, mh, segm->tot_len);
513 dispatch_usb_command(segm, ci);
514 i++;
515 }
516
517 /* release the master req_ctx, as all segments have been
518 * processed now */
519 req_ctx_put(rctx);
520}
521
Harald Welteebb80ed2016-03-02 13:56:59 +0100522/* iterate over the queue of incoming USB commands and dispatch/execute
523 * them */
Harald Welte9f240b62016-03-18 10:32:56 +0100524static void process_any_usb_commands(struct llist_head *main_q,
525 struct cardem_inst *ci)
Harald Welteebb80ed2016-03-02 13:56:59 +0100526{
Harald Welte9f240b62016-03-18 10:32:56 +0100527 struct llist_head *lh;
528 struct req_ctx *rctx;
529 int i;
Harald Welteebb80ed2016-03-02 13:56:59 +0100530
Harald Welte9f240b62016-03-18 10:32:56 +0100531 /* limit the number of iterations to 10, to ensure we don't get
532 * stuck here without returning to main loop processing */
533 for (i = 0; i < 10; i++) {
534 /* de-queue the list head in an irq-safe way */
535 lh = llist_head_dequeue_irqsafe(main_q);
536 if (!lh)
537 break;
538 rctx = llist_entry(lh, struct req_ctx, list);
Harald Welteb26d0032016-03-19 13:33:02 +0100539 dispatch_received_rctx(rctx, ci);
Harald Welte5820ea92016-03-16 22:12:00 +0100540 }
Harald Welteebb80ed2016-03-02 13:56:59 +0100541}
542
Harald Welte2a6d3af2016-02-28 19:29:14 +0100543/* main loop function, called repeatedly */
544void mode_cardemu_run(void)
545{
Harald Welteacae4122016-03-02 10:27:58 +0100546 struct llist_head *queue;
Harald Welte13e82022016-03-02 15:17:53 +0100547 unsigned int i;
Harald Welteacae4122016-03-02 10:27:58 +0100548
Harald Welte13e82022016-03-02 15:17:53 +0100549 for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
550 struct cardem_inst *ci = &cardem_inst[i];
551
Harald Welte54cb3d02016-02-29 14:12:40 +0100552 /* drain the ring buffer from UART into card_emu */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100553 while (1) {
554 __disable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100555 if (rbuf_is_empty(&ci->rb)) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100556 __enable_irq();
557 break;
558 }
Harald Welte13e82022016-03-02 15:17:53 +0100559 uint8_t byte = rbuf_read(&ci->rb);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100560 __enable_irq();
Harald Welte13e82022016-03-02 15:17:53 +0100561 card_emu_process_rx_byte(ci->ch, byte);
Harald Weltedde112e2016-03-20 16:42:11 +0100562 //TRACE_ERROR("%uRx%02x\r\n", i, byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100563 }
Harald Welteacae4122016-03-02 10:27:58 +0100564
Harald Welte13e82022016-03-02 15:17:53 +0100565 queue = card_emu_get_usb_tx_queue(ci->ch);
Harald Welteacae4122016-03-02 10:27:58 +0100566 int usb_pending = llist_count(queue);
Harald Welte13e82022016-03-02 15:17:53 +0100567 if (usb_pending != ci->usb_pending_old) {
Harald Weltedde112e2016-03-20 16:42:11 +0100568 TRACE_DEBUG("%u usb_pending=%d\r\n",
569 i, usb_pending);
Harald Welte13e82022016-03-02 15:17:53 +0100570 ci->usb_pending_old = usb_pending;
Harald Welteacae4122016-03-02 10:27:58 +0100571 }
Harald Welte13e82022016-03-02 15:17:53 +0100572 usb_refill_to_host(queue, ci->ep_in);
Harald Welteacae4122016-03-02 10:27:58 +0100573
Harald Welteebb80ed2016-03-02 13:56:59 +0100574 /* ensure we can handle incoming USB messages from the
575 * host */
Harald Welte13e82022016-03-02 15:17:53 +0100576 queue = &ci->usb_out_queue;
577 usb_refill_from_host(queue, ci->ep_out);
Harald Welte0eaa9922016-03-04 03:03:49 +0100578 process_any_usb_commands(queue, ci);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100579 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100580}