blob: 9bf706dace14ee0ff3ad99c0cfac3651435c244b [file] [log] [blame]
Harald Welte2a6d3af2016-02-28 19:29:14 +01001#include "board.h"
2#include "card_emu.h"
Harald Weltebd717682016-02-28 19:30:05 +01003#include "iso7816_fidi.h"
Harald Welte54cb3d02016-02-29 14:12:40 +01004#include "utils.h"
Harald Welteacae4122016-03-02 10:27:58 +01005#include "linuxlist.h"
Harald Welteebb80ed2016-03-02 13:56:59 +01006#include "req_ctx.h"
7#include "cardemu_prot.h"
Harald Weltebd717682016-02-28 19:30:05 +01008
9#define TRACE_ENTRY() TRACE_DEBUG("%s entering\n", __func__)
Harald Welte2a6d3af2016-02-28 19:29:14 +010010
11static const Pin pins_cardsim[] = PINS_CARDSIM;
12
13/* UART pins */
14static const Pin pins_usim1[] = {PINS_USIM1};
15static const Pin pin_usim1_rst = PIN_USIM1_nRST;
16static const Pin pin_usim1_vcc = PIN_USIM1_VCC;
Harald Welteebb80ed2016-03-02 13:56:59 +010017static LLIST_HEAD(usb_out_queue_usim1);
Harald Welte2a6d3af2016-02-28 19:29:14 +010018
19#ifdef CARDEMU_SECOND_UART
20static const Pin pins_usim2[] = {PINS_USIM1};
21static const Pin pin_usim2_rst = PIN_USIM2_nRST;
22static const Pin pin_usim2_vcc = PIN_USIM2_VCC;
Harald Welteebb80ed2016-03-02 13:56:59 +010023static LLIST_HEAD(usb_out_queue_usim2);
Harald Welte2a6d3af2016-02-28 19:29:14 +010024#endif
25
26static struct card_handle *ch1, *ch2;
Harald Weltec0bd7f02016-02-29 10:13:33 +010027static struct ringbuf ch1_rb;
Harald Welte2a6d3af2016-02-28 19:29:14 +010028
29static struct Usart_info usart_info[] = {
30 {
31 .base = USART1,
32 .id = ID_USART1,
33 .state = USART_RCV
34 },
35#ifdef CARDEMU_SECOND_UART
36 {
37 .base = USART0,
38 .id = ID_USART0,
39 .state = USART_RCV
40 },
41#endif
42};
43
44static Usart *get_usart_by_chan(uint8_t uart_chan)
45{
46 switch (uart_chan) {
47 case 0:
48 return USART1;
49#ifdef CARDEMU_SECOND_UART
50 case 1:
51 return USART0;
52#endif
53 }
54 return NULL;
55}
56
57/***********************************************************************
58 * Call-Backs from card_emu.c
59 ***********************************************************************/
60
61/* call-back from card_emu.c to enable/disable transmit and/or receive */
62void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
63{
64 Usart *usart = get_usart_by_chan(uart_chan);
65 switch (rxtx) {
66 case ENABLE_TX:
Harald Welte9dbc46e2016-02-29 10:05:10 +010067 USART_DisableIt(usart, ~US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +010068 USART_SetReceiverEnabled(usart, 0);
Harald Welte8a416b12016-03-01 00:42:04 +010069 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
70 USART_EnableIt(usart, US_IER_TXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +010071 USART_SetTransmitterEnabled(usart, 1);
72 break;
73 case ENABLE_RX:
Harald Welte9dbc46e2016-02-29 10:05:10 +010074 USART_DisableIt(usart, ~US_IER_RXRDY);
Harald Welte8a416b12016-03-01 00:42:04 +010075 USART_SetTransmitterEnabled(usart, 0);
76 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
77 USART_EnableIt(usart, US_IER_RXRDY);
78 USART_SetReceiverEnabled(usart, 1);
Harald Welte2a6d3af2016-02-28 19:29:14 +010079 break;
80 case 0:
81 default:
82 USART_SetTransmitterEnabled(usart, 0);
83 USART_SetReceiverEnabled(usart, 0);
Harald Welte9dbc46e2016-02-29 10:05:10 +010084 USART_DisableIt(usart, 0xFFFFFFFF);
Harald Welte8a416b12016-03-01 00:42:04 +010085 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Harald Welte2a6d3af2016-02-28 19:29:14 +010086 break;
87 }
88}
89
90/* call-back from card_emu.c to transmit a byte */
91int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
92{
93 Usart_info *ui = &usart_info[uart_chan];
94 ISO7816_SendChar(byte, ui);
95 return 1;
96}
97
98
99/* FIXME: integrate this with actual irq handler */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100100void usart_irq_rx(uint8_t uart)
Harald Welte2a6d3af2016-02-28 19:29:14 +0100101{
Harald Weltec0bd7f02016-02-29 10:13:33 +0100102 Usart *usart = get_usart_by_chan(uart);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100103 struct card_handle *ch = ch1;
Harald Weltec0bd7f02016-02-29 10:13:33 +0100104 uint32_t csr;
105 uint8_t byte = 0;
106
Harald Welte2a6d3af2016-02-28 19:29:14 +0100107#ifdef CARDEMU_SECOND_UART
Harald Weltec0bd7f02016-02-29 10:13:33 +0100108 if (uart == 1)
Harald Welte2a6d3af2016-02-28 19:29:14 +0100109 ch = ch2;
110#endif
Harald Weltec0bd7f02016-02-29 10:13:33 +0100111 csr = usart->US_CSR;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100112
Harald Weltec0bd7f02016-02-29 10:13:33 +0100113 if (csr & US_CSR_RXRDY) {
114 byte = (usart->US_RHR) & 0xFF;
115 rbuf_write(&ch1_rb, byte);
116 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100117
Harald Welte12d4bdf2016-03-02 10:31:03 +0100118 if (csr & US_CSR_TXRDY) {
119 if (card_emu_tx_byte(ch) == 0)
120 USART_DisableIt(usart, US_IER_TXRDY);
121 }
122
Harald Welte2a6d3af2016-02-28 19:29:14 +0100123 if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
124 US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
Harald Weltec0bd7f02016-02-29 10:13:33 +0100125 usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
126 TRACE_ERROR("e 0x%x st: 0x%x\n", byte, csr);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100127 }
128}
129
Harald Weltebd717682016-02-28 19:30:05 +0100130/* call-back from card_emu.c to change UART baud rate */
131int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
132{
133 int rc;
Harald Weltebd717682016-02-28 19:30:05 +0100134 Usart *usart = get_usart_by_chan(uart_chan);
135
Harald Welte99f62a62016-02-29 10:08:49 +0100136 usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
137 usart->US_FIDI = fidi & 0x3ff;
138 usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
139 return 0;
Harald Weltebd717682016-02-28 19:30:05 +0100140}
Harald Welte2a6d3af2016-02-28 19:29:14 +0100141
142/***********************************************************************
143 * Core USB / mainloop integration
144 ***********************************************************************/
145
Harald Weltec0bd7f02016-02-29 10:13:33 +0100146static void usim1_rst_irqhandler(const Pin *pPin)
147{
148 int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
149 card_emu_io_statechg(ch1, CARD_IO_RST, active);
150}
151
152static void usim1_vcc_irqhandler(const Pin *pPin)
153{
154 int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
155 card_emu_io_statechg(ch1, CARD_IO_VCC, active);
156 /* FIXME do this for real */
157 card_emu_io_statechg(ch1, CARD_IO_CLK, active);
158}
159
Harald Welte2a6d3af2016-02-28 19:29:14 +0100160/* executed once at system boot for each config */
161void mode_cardemu_configure(void)
162{
Harald Weltebd717682016-02-28 19:30:05 +0100163 TRACE_ENTRY();
Harald Welte2a6d3af2016-02-28 19:29:14 +0100164}
165
166/* called if config is activated */
167void mode_cardemu_init(void)
168{
Harald Weltebd717682016-02-28 19:30:05 +0100169 TRACE_ENTRY();
170
Harald Weltec0bd7f02016-02-29 10:13:33 +0100171 rbuf_reset(&ch1_rb);
172
Harald Welte2a6d3af2016-02-28 19:29:14 +0100173 PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
174
175 PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
176 ISO7816_Init(&usart_info[0], CLK_SLAVE);
Harald Welte9dbc46e2016-02-29 10:05:10 +0100177 //USART_EnableIt(USART1, US_IER_RXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100178 NVIC_EnableIRQ(USART1_IRQn);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100179
180 PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
181 PIO_EnableIt(&pin_usim1_rst);
182 PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
183 PIO_EnableIt(&pin_usim1_vcc);
184
Harald Welte2a6d3af2016-02-28 19:29:14 +0100185 ch1 = card_emu_init(0, 2, 0);
186
187#ifdef CARDEMU_SECOND_UART
188 PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
189 ISO7816_Init(&usart_info[1], CLK_SLAVE);
Harald Welte9dbc46e2016-02-29 10:05:10 +0100190 //USART_EnableIt(USART0, US_IER_RXRDY);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100191 NVIC_EnableIRQ(USART0_IRQn);
192 ch2 = card_emu_init(1, 0, 1);
193#endif
194}
195
196/* called if config is deactivated */
197void mode_cardemu_exit(void)
198{
Harald Weltebd717682016-02-28 19:30:05 +0100199 TRACE_ENTRY();
200
Harald Weltec0bd7f02016-02-29 10:13:33 +0100201 PIO_DisableIt(&pin_usim1_rst);
202 PIO_DisableIt(&pin_usim1_vcc);
203
Harald Welte2a6d3af2016-02-28 19:29:14 +0100204 NVIC_DisableIRQ(USART1_IRQn);
205 USART_SetTransmitterEnabled(USART1, 0);
206 USART_SetReceiverEnabled(USART1, 0);
207
208#ifdef CARDEMU_SECOND_UART
209 NVIC_DisableIRQ(USART0_IRQn);
210 USART_SetTransmitterEnabled(USART0, 0);
211 USART_SetReceiverEnabled(USART0, 0);
212#endif
213}
214
Harald Welteacae4122016-03-02 10:27:58 +0100215static int llist_count(struct llist_head *head)
216{
217 struct llist_head *list;
218 int i = 0;
219
220 llist_for_each(list, head)
221 i++;
222
223 return i;
224}
225
226static int usb_pending_old = 0;
227
Harald Welteebb80ed2016-03-02 13:56:59 +0100228/* handle a single USB command as received from the USB host */
229static void dispatch_usb_command(struct req_ctx *rctx, struct card_handle *ch)
230{
231 struct cardemu_usb_msg_hdr *hdr;
Harald Welte06b27f62016-03-02 14:26:38 +0100232 struct cardemu_usb_msg_set_atr *atr;
Harald Welteebb80ed2016-03-02 13:56:59 +0100233 struct llist_head *queue;
234
235 hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
236 switch (hdr->msg_type) {
237 case CEMU_USB_MSGT_DT_TX_DATA:
238 queue = card_emu_get_uart_tx_queue(ch);
239 req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
240 llist_add_tail(&rctx->list, queue);
241 card_emu_have_new_uart_tx(ch);
242 break;
243 case CEMU_USB_MSGT_DT_SET_ATR:
Harald Welte06b27f62016-03-02 14:26:38 +0100244 atr = (struct cardemu_usb_msg_set_atr *) hdr;
245 card_emu_set_atr(ch, atr->atr, hdr->data_len);
246 llist_del(&rctx->list);
247 req_ctx_put(rctx);
248 break;
Harald Welteebb80ed2016-03-02 13:56:59 +0100249 case CEMU_USB_MSGT_DT_GET_STATS:
250 case CEMU_USB_MSGT_DT_GET_STATUS:
251 default:
252 /* FIXME */
253 break;
254 }
255}
256
257/* iterate over the queue of incoming USB commands and dispatch/execute
258 * them */
259static void process_any_usb_commands(struct llist_head *main_q, struct card_handle *ch)
260{
Harald Welte06b27f62016-03-02 14:26:38 +0100261 struct req_ctx *rctx, *tmp;
Harald Welteebb80ed2016-03-02 13:56:59 +0100262
Harald Welte06b27f62016-03-02 14:26:38 +0100263 llist_for_each_entry_safe(rctx, tmp, main_q, list)
Harald Welteebb80ed2016-03-02 13:56:59 +0100264 dispatch_usb_command(rctx, ch);
265}
266
Harald Welte2a6d3af2016-02-28 19:29:14 +0100267/* main loop function, called repeatedly */
268void mode_cardemu_run(void)
269{
Harald Welteacae4122016-03-02 10:27:58 +0100270 struct llist_head *queue;
271
Harald Welte2a6d3af2016-02-28 19:29:14 +0100272 if (ch1) {
Harald Welte54cb3d02016-02-29 14:12:40 +0100273 /* drain the ring buffer from UART into card_emu */
Harald Weltec0bd7f02016-02-29 10:13:33 +0100274 while (1) {
275 __disable_irq();
276 if (rbuf_is_empty(&ch1_rb)) {
277 __enable_irq();
278 break;
279 }
280 uint8_t byte = rbuf_read(&ch1_rb);
281 __enable_irq();
282 card_emu_process_rx_byte(ch1, byte);
Harald Welteacae4122016-03-02 10:27:58 +0100283 TRACE_ERROR("Rx%02x\r\n", byte);
Harald Weltec0bd7f02016-02-29 10:13:33 +0100284 }
Harald Welteacae4122016-03-02 10:27:58 +0100285
286 queue = card_emu_get_usb_tx_queue(ch1);
287 int usb_pending = llist_count(queue);
288 if (usb_pending != usb_pending_old) {
289// printf("usb_pending=%d\r\n", usb_pending);
290 usb_pending_old = usb_pending;
291 }
292 usb_refill_to_host(queue, PHONE_DATAIN);
293
Harald Welteebb80ed2016-03-02 13:56:59 +0100294 /* ensure we can handle incoming USB messages from the
295 * host */
296 queue = &usb_out_queue_usim1;
Harald Welteacae4122016-03-02 10:27:58 +0100297 usb_refill_from_host(queue, PHONE_DATAOUT);
Harald Welteebb80ed2016-03-02 13:56:59 +0100298 process_any_usb_commands(queue, ch1);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100299 }
Harald Welte2a6d3af2016-02-28 19:29:14 +0100300
301#ifdef CARDEMU_SECOND_UART
302 if (ch2) {
303 rst_active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
304 vcc_active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
305 card_emu_io_statechg(ch2, CARD_IO_RST, rst_active);
306 card_emu_io_statechg(ch2, CARD_IO_VCC, vcc_active);
307 /* FIXME: clock ? */
308 }
309 usb_from_host(FIXME);
310#endif
311}