aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nfc/pn533.c
diff options
context:
space:
mode:
authorWaldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>2013-04-03 02:02:13 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2013-04-11 10:29:07 -0400
commit53cf48399ad3b08c9115b4fce73dee0b6e726c91 (patch)
tree69048951e15fc273952de4c019f0f26c8a799bf8 /drivers/nfc/pn533.c
parent58520373d8aff974f4b3f1bd9eb84c1ff3d6bd8b (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.c219
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};
73MODULE_DEVICE_TABLE(usb, pn533_table); 82MODULE_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
421struct 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
431struct pn533_acr122_apdu_hdr {
432 u8 class;
433 u8 ins;
434 u8 p1;
435 u8 p2;
436} __packed;
437
438struct 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
445struct pn533_acr122_rx_frame {
446 struct pn533_acr122_ccid_hdr ccid;
447 u8 data[]; /* pn533 frame : TFI ... */
448} __packed;
449
450static 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
473static 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
480static 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
487static 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
500static 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
508static 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
515static 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 */
398static inline u8 pn533_std_checksum(u8 value) 532static 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
2472struct pn533_acr122_poweron_rdr_arg {
2473 int rc;
2474 struct completion done;
2475};
2476
2477static 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
2491static 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
2338static struct nfc_ops pn533_nfc_ops = { 2538static 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);