diff options
author | Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> | 2013-04-03 02:02:13 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-04-11 10:29:07 -0400 |
commit | 53cf48399ad3b08c9115b4fce73dee0b6e726c91 (patch) | |
tree | 69048951e15fc273952de4c019f0f26c8a799bf8 /drivers/nfc/pn533.c | |
parent | 58520373d8aff974f4b3f1bd9eb84c1ff3d6bd8b (diff) |
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>
Diffstat (limited to 'drivers/nfc/pn533.c')
-rw-r--r-- | drivers/nfc/pn533.c | 219 |
1 files changed, 217 insertions, 2 deletions
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 2fd8029f377d..697f154331ed 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -38,8 +38,12 @@ | |||
38 | #define SONY_VENDOR_ID 0x054c | 38 | #define SONY_VENDOR_ID 0x054c |
39 | #define PASORI_PRODUCT_ID 0x02e1 | 39 | #define PASORI_PRODUCT_ID 0x02e1 |
40 | 40 | ||
41 | #define PN533_DEVICE_STD 0x1 | 41 | #define ACS_VENDOR_ID 0x072f |
42 | #define PN533_DEVICE_PASORI 0x2 | 42 | #define ACR122U_PRODUCT_ID 0x2200 |
43 | |||
44 | #define PN533_DEVICE_STD 0x1 | ||
45 | #define PN533_DEVICE_PASORI 0x2 | ||
46 | #define PN533_DEVICE_ACR122U 0x3 | ||
43 | 47 | ||
44 | #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ | 48 | #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ |
45 | NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ | 49 | NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ |
@@ -68,6 +72,11 @@ static const struct usb_device_id pn533_table[] = { | |||
68 | .idProduct = PASORI_PRODUCT_ID, | 72 | .idProduct = PASORI_PRODUCT_ID, |
69 | .driver_info = PN533_DEVICE_PASORI, | 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 | MODULE_DEVICE_TABLE(usb, pn533_table); | 82 | MODULE_DEVICE_TABLE(usb, pn533_table); |
@@ -99,6 +108,21 @@ MODULE_DEVICE_TABLE(usb, pn533_table); | |||
99 | #define PN533_STD_FRAME_DIR_OUT 0xD4 | 108 | #define PN533_STD_FRAME_DIR_OUT 0xD4 |
100 | #define PN533_STD_FRAME_DIR_IN 0xD5 | 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 | /* PN533 Commands */ | 126 | /* PN533 Commands */ |
103 | #define PN533_STD_FRAME_CMD(f) (f->data[1]) | 127 | #define PN533_STD_FRAME_CMD(f) (f->data[1]) |
104 | 128 | ||
@@ -394,6 +418,116 @@ struct pn533_frame_ops { | |||
394 | u8 (*get_cmd_code)(void *frame); | 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 | /* The rule: value + checksum = 0 */ | 531 | /* The rule: value + checksum = 0 */ |
398 | static inline u8 pn533_std_checksum(u8 value) | 532 | static inline u8 pn533_std_checksum(u8 value) |
399 | { | 533 | { |
@@ -2335,6 +2469,72 @@ static int pn533_pasori_fw_reset(struct pn533 *dev) | |||
2335 | return 0; | 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 | static struct nfc_ops pn533_nfc_ops = { | 2538 | static struct nfc_ops pn533_nfc_ops = { |
2339 | .dev_up = NULL, | 2539 | .dev_up = NULL, |
2340 | .dev_down = NULL, | 2540 | .dev_down = NULL, |
@@ -2369,6 +2569,7 @@ static int pn533_setup(struct pn533 *dev) | |||
2369 | break; | 2569 | break; |
2370 | 2570 | ||
2371 | case PN533_DEVICE_PASORI: | 2571 | case PN533_DEVICE_PASORI: |
2572 | case PN533_DEVICE_ACR122U: | ||
2372 | max_retries.mx_rty_atr = 0x2; | 2573 | max_retries.mx_rty_atr = 0x2; |
2373 | max_retries.mx_rty_psl = 0x1; | 2574 | max_retries.mx_rty_psl = 0x1; |
2374 | max_retries.mx_rty_passive_act = | 2575 | max_retries.mx_rty_passive_act = |
@@ -2510,6 +2711,20 @@ static int pn533_probe(struct usb_interface *interface, | |||
2510 | protocols = PN533_NO_TYPE_B_PROTOCOLS; | 2711 | protocols = PN533_NO_TYPE_B_PROTOCOLS; |
2511 | break; | 2712 | break; |
2512 | 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 | } | ||
2726 | break; | ||
2727 | |||
2513 | default: | 2728 | default: |
2514 | nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n", | 2729 | nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n", |
2515 | dev->device_type); | 2730 | dev->device_type); |