blob: 5473a41128cad1fa59f91e7be8afc54eb22acfa1 [file] [log] [blame]
Kévin Redon69b92d92019-01-24 16:39:20 +01001/*
Kévin Redon78d2f442019-01-24 18:45:59 +01002 * Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
Kévin Redon69b92d92019-01-24 16:39:20 +010018
Harald Welte1b9a5b82019-02-24 23:04:45 +010019#include <stdlib.h>
Harald Welte5a8af4d2019-05-12 15:57:20 +020020#include <inttypes.h>
Harald Welte1b9a5b82019-02-24 23:04:45 +010021#include <stdio.h>
Kévin Redon072951b2019-05-02 15:17:46 +020022#include <math.h>
Harald Weltef53f2262019-02-24 11:01:08 +010023#include <parts.h>
Harald Welte65101be2019-04-18 18:30:49 +020024#include <errno.h>
Harald Weltec7a58ba2019-04-18 17:59:19 +020025
26#include <osmocom/core/utils.h>
27
Harald Weltef53f2262019-02-24 11:01:08 +010028#include <hal_cache.h>
Harald Welte93f628a2019-02-24 14:32:30 +010029#include <hri_port_e54.h>
Harald Weltef53f2262019-02-24 11:01:08 +010030
Kévin Redon69b92d92019-01-24 16:39:20 +010031#include "atmel_start.h"
32#include "atmel_start_pins.h"
Kévin Redon072951b2019-05-02 15:17:46 +020033#include "config/hpl_gclk_config.h"
Kévin Redon69b92d92019-01-24 16:39:20 +010034
Harald Weltec3f170d2019-02-24 09:06:59 +010035#include "i2c_bitbang.h"
36#include "octsim_i2c.h"
37#include "ncn8025.h"
Kévin Redon0f050722019-05-02 15:56:25 +020038#include "iso7816_3.h"
Harald Weltec3f170d2019-02-24 09:06:59 +010039
Harald Welteff9f4ce2019-02-24 22:51:09 +010040#include "command.h"
41
Eric Wildff5c3902019-10-17 20:21:44 +020042#include "ccid_device.h"
43#include "usb_descriptors.h"
44extern struct ccid_slot_ops iso_fsm_slot_ops;
45static struct ccid_instance g_ci;
Kévin Redonc89bb8c2019-04-17 01:20:23 +020046
Harald Weltec7a58ba2019-04-18 17:59:19 +020047static void ccid_app_init(void);
48
Harald Weltec3f170d2019-02-24 09:06:59 +010049static void board_init()
50{
51 int i;
52
53 for (i = 0; i < 4; i++)
54 i2c_init(&i2c[i]);
55
Harald Welte255da5e2019-04-16 18:19:53 +020056 for (i = 0; i < 8; i++)
Harald Weltec3f170d2019-02-24 09:06:59 +010057 ncn8025_init(i);
Harald Weltef53f2262019-02-24 11:01:08 +010058
59 cache_init();
60 cache_enable(CMCC);
Harald Welted1bd5c42019-05-17 16:38:30 +020061 calendar_enable(&CALENDAR_0);
Harald Welte93f628a2019-02-24 14:32:30 +010062
63 /* increase drive strength of 20Mhz SIM clock output to 8mA
64 * (there are 8 inputs + traces to drive!) */
65 hri_port_set_PINCFG_DRVSTR_bit(PORT, 0, 11);
Kévin Redonc89bb8c2019-04-17 01:20:23 +020066
Harald Weltec7a58ba2019-04-18 17:59:19 +020067 ccid_app_init();
Harald Weltec3f170d2019-02-24 09:06:59 +010068}
69
Harald Weltec7a58ba2019-04-18 17:59:19 +020070/***********************************************************************
71 * CCID Driver integration
72 ***********************************************************************/
73
74#include <osmocom/core/linuxlist.h>
75#include <osmocom/core/msgb.h>
76#include "linuxlist_atomic.h"
77#include "ccid_df.h"
78
79struct usb_ep_q {
80 const char *name;
81 /* msgb queue of pending to-be-transmitted (IN/IRQ) or completed received (OUT)
82 * USB transfers */
83 struct llist_head list;
84 /* currently ongoing/processed msgb (USB transmit or receive */
85 struct msgb *in_progress;
86};
87
88struct ccid_state {
89 /* msgb queue of free msgs */
90 struct llist_head free_q;
91
92 /* msgb queue of pending to-be-transmitted (IN EP) */
93 struct usb_ep_q in_ep;
94 /* msgb queue of pending to-be-transmitted (IRQ EP) */
95 struct usb_ep_q irq_ep;
96 /* msgb queue of completed received (OUT EP) */
97 struct usb_ep_q out_ep;
Harald Welte5a8af4d2019-05-12 15:57:20 +020098
99 /* bit-mask of card-insert status, as determined from NCN8025 IRQ output */
100 uint8_t card_insert_mask;
Harald Weltec7a58ba2019-04-18 17:59:19 +0200101};
102static struct ccid_state g_ccid_s;
103
104static void ccid_out_read_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred);
105static void ccid_in_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred);
106static void ccid_irq_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred);
107
108static void usb_ep_q_init(struct usb_ep_q *ep_q, const char *name)
109{
110 ep_q->name = name;
111 INIT_LLIST_HEAD(&ep_q->list);
112 ep_q->in_progress = NULL;
113}
114
115static void ccid_app_init(void)
116{
117 /* initialize data structures */
118 INIT_LLIST_HEAD(&g_ccid_s.free_q);
119 usb_ep_q_init(&g_ccid_s.in_ep, "IN");
120 usb_ep_q_init(&g_ccid_s.irq_ep, "IRQ");
121 usb_ep_q_init(&g_ccid_s.out_ep, "OUT");
122
123 /* OUT endpoint read complete callback (irq context) */
124 ccid_df_register_callback(CCID_DF_CB_READ_OUT, (FUNC_PTR)&ccid_out_read_compl);
125 /* IN endpoint write complete callback (irq context) */
126 ccid_df_register_callback(CCID_DF_CB_WRITE_IN, (FUNC_PTR)&ccid_in_write_compl);
127 /* IRQ endpoint write complete callback (irq context) */
128 ccid_df_register_callback(CCID_DF_CB_WRITE_IRQ, (FUNC_PTR)&ccid_irq_write_compl);
129}
130
131/* irqsafe version of msgb_enqueue */
132struct msgb *msgb_dequeue_irqsafe(struct llist_head *q)
133{
134 struct msgb *msg;
135 CRITICAL_SECTION_ENTER()
136 msg = msgb_dequeue(q);
137 CRITICAL_SECTION_LEAVE()
138 return msg;
139}
140
Harald Welte5a8af4d2019-05-12 15:57:20 +0200141void msgb_enqueue_irqsafe(struct llist_head *q, struct msgb *msg)
142{
143 CRITICAL_SECTION_ENTER()
144 msgb_enqueue(q, msg);
145 CRITICAL_SECTION_LEAVE()
146}
147
Harald Weltec7a58ba2019-04-18 17:59:19 +0200148/* submit the next pending (if any) message for the IN EP */
149static int submit_next_in(void)
150{
151 struct usb_ep_q *ep_q = &g_ccid_s.in_ep;
152 struct msgb *msg;
153 int rc;
154
Eric Wildff5c3902019-10-17 20:21:44 +0200155 if (ep_q->in_progress)
156 return 0;
157
Harald Weltec7a58ba2019-04-18 17:59:19 +0200158 msg = msgb_dequeue_irqsafe(&ep_q->list);
159 if (!msg)
160 return 0;
161
162 ep_q->in_progress = msg;
163 rc = ccid_df_write_in(msgb_data(msg), msgb_length(msg));
164 if (rc != ERR_NONE) {
165 printf("EP %s failed: %d\r\n", ep_q->name, rc);
166 return -1;
167 }
168 return 1;
169
170}
171
172/* submit the next pending (if any) message for the IRQ EP */
173static int submit_next_irq(void)
174{
175 struct usb_ep_q *ep_q = &g_ccid_s.irq_ep;
176 struct msgb *msg;
177 int rc;
178
Eric Wildc619c0c2019-10-01 15:22:14 +0200179 if (ep_q->in_progress)
180 return 0;
181
Harald Weltec7a58ba2019-04-18 17:59:19 +0200182 msg = msgb_dequeue_irqsafe(&ep_q->list);
183 if (!msg)
184 return 0;
185
186 ep_q->in_progress = msg;
187 rc = ccid_df_write_irq(msgb_data(msg), msgb_length(msg));
188 /* may return HALTED/ERROR/DISABLED/BUSY/ERR_PARAM/ERR_FUNC/ERR_DENIED */
189 if (rc != ERR_NONE) {
190 printf("EP %s failed: %d\r\n", ep_q->name, rc);
191 return -1;
192 }
193 return 1;
194}
195
196static int submit_next_out(void)
197{
198 struct usb_ep_q *ep_q = &g_ccid_s.out_ep;
199 struct msgb *msg;
200 int rc;
201
202 OSMO_ASSERT(!ep_q->in_progress);
203 msg = msgb_dequeue_irqsafe(&g_ccid_s.free_q);
204 if (!msg)
205 return -1;
Eric Wildff5c3902019-10-17 20:21:44 +0200206 msgb_reset(msg);
Harald Weltec7a58ba2019-04-18 17:59:19 +0200207 ep_q->in_progress = msg;
208
209 rc = ccid_df_read_out(msgb_data(msg), msgb_tailroom(msg));
210 if (rc != ERR_NONE) {
211 /* re-add to the list of free msgb's */
212 llist_add_tail_at(&g_ccid_s.free_q, &msg->list);
213 return 0;
214 }
215 return 1;
216}
217
218/* OUT endpoint read complete callback (irq context) */
219static void ccid_out_read_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred)
220{
221 struct msgb *msg = g_ccid_s.out_ep.in_progress;
222
223 /* add just-received msg to tail of endpoint queue */
224 OSMO_ASSERT(msg);
225 /* update msgb with the amount of data received */
226 msgb_put(msg, transferred);
227 /* append to list of pending-to-be-handed messages */
228 llist_add_tail_at(&msg->list, &g_ccid_s.out_ep.list);
Eric Wildff5c3902019-10-17 20:21:44 +0200229 g_ccid_s.out_ep.in_progress = NULL;
Harald Weltec7a58ba2019-04-18 17:59:19 +0200230
231 /* submit another [free] msgb to receive the next transfer */
232 submit_next_out();
233}
234
235/* IN endpoint write complete callback (irq context) */
236static void ccid_in_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred)
237{
238 struct msgb *msg = g_ccid_s.in_ep.in_progress;
239
240 OSMO_ASSERT(msg);
241 /* return the message back to the queue of free message buffers */
242 llist_add_tail_at(&msg->list, &g_ccid_s.free_q);
243 g_ccid_s.in_ep.in_progress = NULL;
244
245 /* submit the next pending to-be-transmitted msgb (if any) */
246 submit_next_in();
247}
248
249/* IRQ endpoint write complete callback (irq context) */
250static void ccid_irq_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred)
251{
252 struct msgb *msg = g_ccid_s.irq_ep.in_progress;
253
254 OSMO_ASSERT(msg);
255 /* return the message back to the queue of free message buffers */
256 llist_add_tail_at(&msg->list, &g_ccid_s.free_q);
257 g_ccid_s.irq_ep.in_progress = NULL;
258
259 /* submit the next pending to-be-transmitted msgb (if any) */
260 submit_next_irq();
261}
262
Harald Welte5a8af4d2019-05-12 15:57:20 +0200263#include "ccid_proto.h"
Eric Wild2de998a2019-10-01 15:20:32 +0200264static struct msgb *ccid_gen_notify_slot_status(uint8_t old_bm, uint8_t new_bm)
Harald Welte5a8af4d2019-05-12 15:57:20 +0200265{
Eric Wild2de998a2019-10-01 15:20:32 +0200266 uint8_t statusbytes[2] = {0};
Harald Welte5a8af4d2019-05-12 15:57:20 +0200267 //struct msgb *msg = ccid_msgb_alloc();
268 struct msgb *msg = msgb_alloc(64, "IRQ");
Eric Wild2de998a2019-10-01 15:20:32 +0200269 struct ccid_rdr_to_pc_notify_slot_change *nsc = msgb_put(msg, sizeof(*nsc) + sizeof(statusbytes));
Harald Welte5a8af4d2019-05-12 15:57:20 +0200270 nsc->bMessageType = RDR_to_PC_NotifySlotChange;
Eric Wild2de998a2019-10-01 15:20:32 +0200271
272 for(int i = 0; i <8; i++) {
273 uint8_t byteidx = i >> 2;
274 uint8_t old_bit = old_bm & (1 << i);
275 uint8_t new_bit = new_bm & (1 << i);
276 uint8_t bv;
277 if (old_bit == new_bit && new_bit == 0)
278 bv = 0x00;
279 else if (old_bit == new_bit && new_bit == 1)
280 bv = 0x01;
281 else if (old_bit != new_bit && new_bit == 0)
282 bv = 0x02;
283 else
284 bv = 0x03;
285
286 statusbytes[byteidx] |= bv << ((i % 4) << 1);
287 }
288
289 memcpy(&nsc->bmSlotCCState, statusbytes, sizeof(statusbytes));
Harald Welte5a8af4d2019-05-12 15:57:20 +0200290
291 return msg;
292}
293
294/* check if any card detect state has changed */
295static void poll_card_detect(void)
296{
297 uint8_t new_mask = 0;
298 struct msgb *msg;
299 unsigned int i;
300
Eric Wildff5c3902019-10-17 20:21:44 +0200301 for (i = 0; i < 8; i++){
302 bool level = ncn8025_interrupt_level(i);
303 new_mask |= level << i;
304 g_ci.slot[i].icc_present = level;
305 }
Harald Welte5a8af4d2019-05-12 15:57:20 +0200306
307 /* notify the user/host about any changes */
308 if (g_ccid_s.card_insert_mask != new_mask) {
309 printf("CARD_DET 0x%02x -> 0x%02x\r\n",
310 g_ccid_s.card_insert_mask, new_mask);
Eric Wild2de998a2019-10-01 15:20:32 +0200311 msg = ccid_gen_notify_slot_status(g_ccid_s.card_insert_mask, new_mask);
Harald Welte5a8af4d2019-05-12 15:57:20 +0200312 msgb_enqueue_irqsafe(&g_ccid_s.irq_ep.list, msg);
313
314 g_ccid_s.card_insert_mask = new_mask;
315 }
316}
317
Harald Weltebdf1b352019-05-17 10:21:45 +0200318extern void libosmo_emb_init(void);
Harald Welte1b9a5b82019-02-24 23:04:45 +0100319
Harald Welte8049d662019-04-17 21:19:18 +0200320#include "talloc.h"
Harald Weltebdf1b352019-05-17 10:21:45 +0200321#include "logging.h"
Eric Wildff5c3902019-10-17 20:21:44 +0200322//#include <osmocom/core/msgb.h>
Harald Welte8049d662019-04-17 21:19:18 +0200323void *g_tall_ctx;
324
Harald Welte8049d662019-04-17 21:19:18 +0200325
Harald Welte65101be2019-04-18 18:30:49 +0200326/* Section 9.6 of SAMD5x/E5x Family Data Sheet */
327static int get_chip_unique_serial(uint8_t *out, size_t len)
328{
329 uint32_t *out32 = (uint32_t *)out;
330 if (len < 16)
331 return -EINVAL;
332
333 out32[0] = *(uint32_t *)0x008061fc;
334 out32[1] = *(uint32_t *)0x00806010;
335 out32[2] = *(uint32_t *)0x00806014;
336 out32[3] = *(uint32_t *)0x00806018;
337
338 return 0;
339}
340
341/* same as get_chip_unique_serial but in hex-string format */
342static int get_chip_unique_serial_str(char *out, size_t len)
343{
344 uint8_t buf[16];
345 int rc;
346
347 if (len < 16*2 + 1)
348 return -EINVAL;
349
350 rc = get_chip_unique_serial(buf, sizeof(buf));
351 if (rc < 0)
352 return rc;
353 osmo_hexdump_buf(out, len, buf, sizeof(buf), NULL, false);
354 return 0;
355}
356
Harald Welte9ab4bc82019-05-17 18:36:01 +0200357#define RSTCAUSE_STR_SIZE 64
358static void get_rstcause_str(char *out)
359{
360 uint8_t val = hri_rstc_read_RCAUSE_reg(RSTC);
361 *out = '\0';
362 if (val & RSTC_RCAUSE_POR)
363 strcat(out, "POR ");
364 if (val & RSTC_RCAUSE_BODCORE)
365 strcat(out, "BODCORE ");
366 if (val & RSTC_RCAUSE_BODVDD)
367 strcat(out, "BODVDD ");
368 if (val & RSTC_RCAUSE_NVM)
369 strcat(out, "NVM ");
370 if (val & RSTC_RCAUSE_EXT)
371 strcat(out, "EXT ");
372 if (val & RSTC_RCAUSE_WDT)
373 strcat(out, "WDT ");
374 if (val & RSTC_RCAUSE_SYST)
375 strcat(out, "SYST ");
376 if (val & RSTC_RCAUSE_BACKUP)
377 strcat(out, "BACKUP ");
378}
379
Eric Wildff5c3902019-10-17 20:21:44 +0200380//#######################
381
382
383
384static uint32_t clock_freqs[] = {
385 2500000
386};
387
388static uint32_t data_rates[] = {
389 9600
390};
391extern struct usb_desc_collection usb_fs_descs;
392
393
394
395static int feed_ccid(void)
396{
397 struct usb_ep_q *ep_q = &g_ccid_s.out_ep;
398 struct msgb *msg;
399 int rc;
400
401 msg = msgb_dequeue_irqsafe(&g_ccid_s.out_ep.list);
402 if (!msg)
403 return -1;
404
405 ccid_handle_out(&g_ci, msg);
406 return 1;
407}
408
409static int ccid_ops_send_in(struct ccid_instance *ci, struct msgb *msg)
410{
411 /* add just-received msg to tail of endpoint queue */
412 OSMO_ASSERT(msg);
413
414 /* append to list of pending-to-be-handed messages */
415 llist_add_tail_at(&msg->list, &g_ccid_s.in_ep.list);
416 submit_next_in();
417 return 0;
418}
419
420static const struct ccid_ops c_ops = {
421 .send_in = ccid_ops_send_in,
422 .send_int = 0,
423};
424
425//#######################
426
427#define NUM_OUT_BUF 7
428
Kévin Redon69b92d92019-01-24 16:39:20 +0100429int main(void)
430{
Harald Welte65101be2019-04-18 18:30:49 +0200431 char sernr_buf[16*2+1];
Harald Welte9ab4bc82019-05-17 18:36:01 +0200432 char rstcause_buf[RSTCAUSE_STR_SIZE];
Harald Welte65101be2019-04-18 18:30:49 +0200433
Kévin Redon69b92d92019-01-24 16:39:20 +0100434 atmel_start_init();
Harald Welte65101be2019-04-18 18:30:49 +0200435 get_chip_unique_serial_str(sernr_buf, sizeof(sernr_buf));
Harald Welte9ab4bc82019-05-17 18:36:01 +0200436 get_rstcause_str(rstcause_buf);
Kévin Redon78d2f442019-01-24 18:45:59 +0100437
Kévin Redon8e538002019-01-30 11:19:19 +0100438 usb_start();
439
Harald Weltec3f170d2019-02-24 09:06:59 +0100440 board_init();
441
Harald Welte729a7622019-05-17 11:02:11 +0200442 printf("\r\n\r\n"
443 "=============================================================================\n\r"
444 "sysmoOCTSIM firmware " GIT_VERSION "\n\r"
445 "(C) 2018-2019 by sysmocom - s.f.m.c. GmbH and contributors\n\r"
446 "=============================================================================\n\r");
447 printf("Chip ID: %s\r\n", sernr_buf);
Harald Welte9ab4bc82019-05-17 18:36:01 +0200448 printf("Reset cause: %s\r\n", rstcause_buf);
Harald Weltee7aa5342019-04-16 21:11:14 +0200449
Harald Welte8049d662019-04-17 21:19:18 +0200450 talloc_enable_null_tracking();
451 g_tall_ctx = talloc_named_const(NULL, 0, "global");
452 printf("g_tall_ctx=%p\r\n", g_tall_ctx);
Harald Weltebdf1b352019-05-17 10:21:45 +0200453
454 libosmo_emb_init();
455
456 LOGP(DUSB, LOGL_ERROR, "foobar usb\n");
Harald Welte8049d662019-04-17 21:19:18 +0200457
Eric Wildff5c3902019-10-17 20:21:44 +0200458 //FIXME osmo_emb has a pool?
459 msgb_set_talloc_ctx(g_tall_ctx);
460
Eric Wild8ebd7d62019-10-23 15:55:51 +0200461 //prevent spurious interrupts before our driver structs are ready
462 CRITICAL_SECTION_ENTER()
Eric Wildff5c3902019-10-17 20:21:44 +0200463 ccid_instance_init(&g_ci, &c_ops, &iso_fsm_slot_ops, &usb_fs_descs.ccid.class,
464 data_rates, clock_freqs, "", 0);
465
466 for(int i =0; i < NUM_OUT_BUF; i++){
467 struct msgb *msg = msgb_alloc(300, "ccid");
468 OSMO_ASSERT(msg);
469 /* return the message back to the queue of free message buffers */
470 llist_add_tail_at(&msg->list, &g_ccid_s.free_q);
471 }
472 submit_next_out();
Eric Wild8ebd7d62019-10-23 15:55:51 +0200473 CRITICAL_SECTION_LEAVE()
Eric Wildff5c3902019-10-17 20:21:44 +0200474
475// command_print_prompt();
Kévin Redon8e538002019-01-30 11:19:19 +0100476 while (true) { // main loop
Harald Welteff9f4ce2019-02-24 22:51:09 +0100477 command_try_recv();
Harald Welte5a8af4d2019-05-12 15:57:20 +0200478 poll_card_detect();
Eric Wildc619c0c2019-10-01 15:22:14 +0200479 submit_next_irq();
Eric Wildff5c3902019-10-17 20:21:44 +0200480 feed_ccid();
Harald Welte1017a752019-05-17 20:39:49 +0200481 osmo_timers_update();
Eric Wildff5c3902019-10-17 20:21:44 +0200482 int qs = llist_count_at(&g_ccid_s.free_q);
483 if(qs > NUM_OUT_BUF)
484 for (int i= 0; i < qs-NUM_OUT_BUF; i++){
485 struct msgb *msg = msgb_dequeue_irqsafe(&g_ccid_s.free_q);
486 if (msg)
487 msgb_free(msg);
488 }
489 if(qs < NUM_OUT_BUF)
490 for (int i= 0; i < qs-NUM_OUT_BUF; i++){
491 struct msgb *msg = msgb_alloc(300,"ccid");
492 OSMO_ASSERT(msg);
493 /* return the message back to the queue of free message buffers */
494 llist_add_tail_at(&msg->list, &g_ccid_s.free_q);
495 }
496
497
Kévin Redon8e538002019-01-30 11:19:19 +0100498 }
Kévin Redon69b92d92019-01-24 16:39:20 +0100499}