Commit 53cf48399ad3b08c9115b4fce73dee0b6e726c91
Committed by
Samuel Ortiz
1 parent
58520373d8
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
NFC: pn533: Add support for ACS ACR122U reader
ACS ACR122U is an USB NFC reader, PC/SC and CCID compilant, based on NXP PN532 chip. Internally, it's build of MCU, PN532 and an antenna. MCU makes the device CCID and PC/SC compilant and provide USB connection. In this achitecture, a host cannot talk directly to PN532 and must rely on MCU. Luckily, MCU exposes pseud-APDU through PC/SC Escape mechanism which let the host to transmit standard PN532 commands directly to PN532 chip with some limitations. The frame roughly looks like: CCID header | APDU header | PN532 header (pc_to_rdr_escape) | (pseudo apdu Direct Tramsmit) | (len, TFI, cmd, params) Accordign to limitations, ACR122U does't provide any mechanism to abort last issued command. Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Showing 1 changed file with 217 additions and 2 deletions Side-by-side Diff
drivers/nfc/pn533.c
... | ... | @@ -38,9 +38,13 @@ |
38 | 38 | #define SONY_VENDOR_ID 0x054c |
39 | 39 | #define PASORI_PRODUCT_ID 0x02e1 |
40 | 40 | |
41 | -#define PN533_DEVICE_STD 0x1 | |
42 | -#define PN533_DEVICE_PASORI 0x2 | |
41 | +#define ACS_VENDOR_ID 0x072f | |
42 | +#define ACR122U_PRODUCT_ID 0x2200 | |
43 | 43 | |
44 | +#define PN533_DEVICE_STD 0x1 | |
45 | +#define PN533_DEVICE_PASORI 0x2 | |
46 | +#define PN533_DEVICE_ACR122U 0x3 | |
47 | + | |
44 | 48 | #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ |
45 | 49 | NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ |
46 | 50 | NFC_PROTO_NFC_DEP_MASK |\ |
... | ... | @@ -68,6 +72,11 @@ |
68 | 72 | .idProduct = PASORI_PRODUCT_ID, |
69 | 73 | .driver_info = PN533_DEVICE_PASORI, |
70 | 74 | }, |
75 | + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | |
76 | + .idVendor = ACS_VENDOR_ID, | |
77 | + .idProduct = ACR122U_PRODUCT_ID, | |
78 | + .driver_info = PN533_DEVICE_ACR122U, | |
79 | + }, | |
71 | 80 | { } |
72 | 81 | }; |
73 | 82 | MODULE_DEVICE_TABLE(usb, pn533_table); |
... | ... | @@ -99,6 +108,21 @@ |
99 | 108 | #define PN533_STD_FRAME_DIR_OUT 0xD4 |
100 | 109 | #define PN533_STD_FRAME_DIR_IN 0xD5 |
101 | 110 | |
111 | +/* ACS ACR122 pn533 frame definitions */ | |
112 | +#define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \ | |
113 | + + 2) | |
114 | +#define PN533_ACR122_TX_FRAME_TAIL_LEN 0 | |
115 | +#define PN533_ACR122_RX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_rx_frame) \ | |
116 | + + 2) | |
117 | +#define PN533_ACR122_RX_FRAME_TAIL_LEN 2 | |
118 | +#define PN533_ACR122_FRAME_MAX_PAYLOAD_LEN PN533_STD_FRAME_MAX_PAYLOAD_LEN | |
119 | + | |
120 | +/* CCID messages types */ | |
121 | +#define PN533_ACR122_PC_TO_RDR_ICCPOWERON 0x62 | |
122 | +#define PN533_ACR122_PC_TO_RDR_ESCAPE 0x6B | |
123 | + | |
124 | +#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83 | |
125 | + | |
102 | 126 | /* PN533 Commands */ |
103 | 127 | #define PN533_STD_FRAME_CMD(f) (f->data[1]) |
104 | 128 | |
... | ... | @@ -394,6 +418,116 @@ |
394 | 418 | u8 (*get_cmd_code)(void *frame); |
395 | 419 | }; |
396 | 420 | |
421 | +struct pn533_acr122_ccid_hdr { | |
422 | + u8 type; | |
423 | + u32 datalen; | |
424 | + u8 slot; | |
425 | + u8 seq; | |
426 | + u8 params[3]; /* 3 msg specific bytes or status, error and 1 specific | |
427 | + byte for reposnse msg */ | |
428 | + u8 data[]; /* payload */ | |
429 | +} __packed; | |
430 | + | |
431 | +struct pn533_acr122_apdu_hdr { | |
432 | + u8 class; | |
433 | + u8 ins; | |
434 | + u8 p1; | |
435 | + u8 p2; | |
436 | +} __packed; | |
437 | + | |
438 | +struct pn533_acr122_tx_frame { | |
439 | + struct pn533_acr122_ccid_hdr ccid; | |
440 | + struct pn533_acr122_apdu_hdr apdu; | |
441 | + u8 datalen; | |
442 | + u8 data[]; /* pn533 frame: TFI ... */ | |
443 | +} __packed; | |
444 | + | |
445 | +struct pn533_acr122_rx_frame { | |
446 | + struct pn533_acr122_ccid_hdr ccid; | |
447 | + u8 data[]; /* pn533 frame : TFI ... */ | |
448 | +} __packed; | |
449 | + | |
450 | +static void pn533_acr122_tx_frame_init(void *_frame, u8 cmd_code) | |
451 | +{ | |
452 | + struct pn533_acr122_tx_frame *frame = _frame; | |
453 | + | |
454 | + frame->ccid.type = PN533_ACR122_PC_TO_RDR_ESCAPE; | |
455 | + frame->ccid.datalen = sizeof(frame->apdu) + 1; /* sizeof(apdu_hdr) + | |
456 | + sizeof(datalen) */ | |
457 | + frame->ccid.slot = 0; | |
458 | + frame->ccid.seq = 0; | |
459 | + frame->ccid.params[0] = 0; | |
460 | + frame->ccid.params[1] = 0; | |
461 | + frame->ccid.params[2] = 0; | |
462 | + | |
463 | + frame->data[0] = PN533_STD_FRAME_DIR_OUT; | |
464 | + frame->data[1] = cmd_code; | |
465 | + frame->datalen = 2; /* data[0] + data[1] */ | |
466 | + | |
467 | + frame->apdu.class = 0xFF; | |
468 | + frame->apdu.ins = 0; | |
469 | + frame->apdu.p1 = 0; | |
470 | + frame->apdu.p2 = 0; | |
471 | +} | |
472 | + | |
473 | +static void pn533_acr122_tx_frame_finish(void *_frame) | |
474 | +{ | |
475 | + struct pn533_acr122_tx_frame *frame = _frame; | |
476 | + | |
477 | + frame->ccid.datalen += frame->datalen; | |
478 | +} | |
479 | + | |
480 | +static void pn533_acr122_tx_update_payload_len(void *_frame, int len) | |
481 | +{ | |
482 | + struct pn533_acr122_tx_frame *frame = _frame; | |
483 | + | |
484 | + frame->datalen += len; | |
485 | +} | |
486 | + | |
487 | +static bool pn533_acr122_is_rx_frame_valid(void *_frame) | |
488 | +{ | |
489 | + struct pn533_acr122_rx_frame *frame = _frame; | |
490 | + | |
491 | + if (frame->ccid.type != 0x83) | |
492 | + return false; | |
493 | + | |
494 | + if (frame->data[frame->ccid.datalen - 2] == 0x63) | |
495 | + return false; | |
496 | + | |
497 | + return true; | |
498 | +} | |
499 | + | |
500 | +static int pn533_acr122_rx_frame_size(void *frame) | |
501 | +{ | |
502 | + struct pn533_acr122_rx_frame *f = frame; | |
503 | + | |
504 | + /* f->ccid.datalen already includes tail length */ | |
505 | + return sizeof(struct pn533_acr122_rx_frame) + f->ccid.datalen; | |
506 | +} | |
507 | + | |
508 | +static u8 pn533_acr122_get_cmd_code(void *frame) | |
509 | +{ | |
510 | + struct pn533_acr122_rx_frame *f = frame; | |
511 | + | |
512 | + return PN533_STD_FRAME_CMD(f); | |
513 | +} | |
514 | + | |
515 | +static struct pn533_frame_ops pn533_acr122_frame_ops = { | |
516 | + .tx_frame_init = pn533_acr122_tx_frame_init, | |
517 | + .tx_frame_finish = pn533_acr122_tx_frame_finish, | |
518 | + .tx_update_payload_len = pn533_acr122_tx_update_payload_len, | |
519 | + .tx_header_len = PN533_ACR122_TX_FRAME_HEADER_LEN, | |
520 | + .tx_tail_len = PN533_ACR122_TX_FRAME_TAIL_LEN, | |
521 | + | |
522 | + .rx_is_frame_valid = pn533_acr122_is_rx_frame_valid, | |
523 | + .rx_header_len = PN533_ACR122_RX_FRAME_HEADER_LEN, | |
524 | + .rx_tail_len = PN533_ACR122_RX_FRAME_TAIL_LEN, | |
525 | + .rx_frame_size = pn533_acr122_rx_frame_size, | |
526 | + | |
527 | + .max_payload_len = PN533_ACR122_FRAME_MAX_PAYLOAD_LEN, | |
528 | + .get_cmd_code = pn533_acr122_get_cmd_code, | |
529 | +}; | |
530 | + | |
397 | 531 | /* The rule: value + checksum = 0 */ |
398 | 532 | static inline u8 pn533_std_checksum(u8 value) |
399 | 533 | { |
... | ... | @@ -2335,6 +2469,72 @@ |
2335 | 2469 | return 0; |
2336 | 2470 | } |
2337 | 2471 | |
2472 | +struct pn533_acr122_poweron_rdr_arg { | |
2473 | + int rc; | |
2474 | + struct completion done; | |
2475 | +}; | |
2476 | + | |
2477 | +static void pn533_acr122_poweron_rdr_resp(struct urb *urb) | |
2478 | +{ | |
2479 | + struct pn533_acr122_poweron_rdr_arg *arg = urb->context; | |
2480 | + | |
2481 | + nfc_dev_dbg(&urb->dev->dev, "%s", __func__); | |
2482 | + | |
2483 | + print_hex_dump(KERN_ERR, "ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1, | |
2484 | + urb->transfer_buffer, urb->transfer_buffer_length, | |
2485 | + false); | |
2486 | + | |
2487 | + arg->rc = urb->status; | |
2488 | + complete(&arg->done); | |
2489 | +} | |
2490 | + | |
2491 | +static int pn533_acr122_poweron_rdr(struct pn533 *dev) | |
2492 | +{ | |
2493 | + /* Power on th reader (CCID cmd) */ | |
2494 | + u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON, | |
2495 | + 0, 0, 0, 0, 0, 0, 3, 0, 0}; | |
2496 | + u8 buf[255]; | |
2497 | + int rc; | |
2498 | + void *cntx; | |
2499 | + struct pn533_acr122_poweron_rdr_arg arg; | |
2500 | + | |
2501 | + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | |
2502 | + | |
2503 | + init_completion(&arg.done); | |
2504 | + cntx = dev->in_urb->context; /* backup context */ | |
2505 | + | |
2506 | + dev->in_urb->transfer_buffer = buf; | |
2507 | + dev->in_urb->transfer_buffer_length = 255; | |
2508 | + dev->in_urb->complete = pn533_acr122_poweron_rdr_resp; | |
2509 | + dev->in_urb->context = &arg; | |
2510 | + | |
2511 | + dev->out_urb->transfer_buffer = cmd; | |
2512 | + dev->out_urb->transfer_buffer_length = sizeof(cmd); | |
2513 | + | |
2514 | + print_hex_dump(KERN_ERR, "ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1, | |
2515 | + cmd, sizeof(cmd), false); | |
2516 | + | |
2517 | + rc = usb_submit_urb(dev->out_urb, GFP_KERNEL); | |
2518 | + if (rc) { | |
2519 | + nfc_dev_err(&dev->interface->dev, | |
2520 | + "Reader power on cmd error %d", rc); | |
2521 | + return rc; | |
2522 | + } | |
2523 | + | |
2524 | + rc = usb_submit_urb(dev->in_urb, GFP_KERNEL); | |
2525 | + if (rc) { | |
2526 | + nfc_dev_err(&dev->interface->dev, | |
2527 | + "Can't submit for reader power on cmd response %d", | |
2528 | + rc); | |
2529 | + return rc; | |
2530 | + } | |
2531 | + | |
2532 | + wait_for_completion(&arg.done); | |
2533 | + dev->in_urb->context = cntx; /* restore context */ | |
2534 | + | |
2535 | + return arg.rc; | |
2536 | +} | |
2537 | + | |
2338 | 2538 | static struct nfc_ops pn533_nfc_ops = { |
2339 | 2539 | .dev_up = NULL, |
2340 | 2540 | .dev_down = NULL, |
... | ... | @@ -2369,6 +2569,7 @@ |
2369 | 2569 | break; |
2370 | 2570 | |
2371 | 2571 | case PN533_DEVICE_PASORI: |
2572 | + case PN533_DEVICE_ACR122U: | |
2372 | 2573 | max_retries.mx_rty_atr = 0x2; |
2373 | 2574 | max_retries.mx_rty_psl = 0x1; |
2374 | 2575 | max_retries.mx_rty_passive_act = |
... | ... | @@ -2508,6 +2709,20 @@ |
2508 | 2709 | |
2509 | 2710 | case PN533_DEVICE_PASORI: |
2510 | 2711 | protocols = PN533_NO_TYPE_B_PROTOCOLS; |
2712 | + break; | |
2713 | + | |
2714 | + case PN533_DEVICE_ACR122U: | |
2715 | + protocols = PN533_NO_TYPE_B_PROTOCOLS; | |
2716 | + dev->ops = &pn533_acr122_frame_ops; | |
2717 | + dev->protocol_type = PN533_PROTO_REQ_RESP, | |
2718 | + | |
2719 | + rc = pn533_acr122_poweron_rdr(dev); | |
2720 | + if (rc < 0) { | |
2721 | + nfc_dev_err(&dev->interface->dev, | |
2722 | + "Couldn't poweron the reader (error %d)", | |
2723 | + rc); | |
2724 | + goto destroy_wq; | |
2725 | + } | |
2511 | 2726 | break; |
2512 | 2727 | |
2513 | 2728 | default: |