162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for NXP PN533 NFC Chip - USB transport layer 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Instituto Nokia de Tecnologia 662306a36Sopenharmony_ci * Copyright (C) 2012-2013 Tieto Poland 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/device.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/usb.h> 1462306a36Sopenharmony_ci#include <linux/nfc.h> 1562306a36Sopenharmony_ci#include <linux/netdevice.h> 1662306a36Sopenharmony_ci#include <net/nfc/nfc.h> 1762306a36Sopenharmony_ci#include "pn533.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define VERSION "0.1" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define PN533_VENDOR_ID 0x4CC 2262306a36Sopenharmony_ci#define PN533_PRODUCT_ID 0x2533 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define SCM_VENDOR_ID 0x4E6 2562306a36Sopenharmony_ci#define SCL3711_PRODUCT_ID 0x5591 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define SONY_VENDOR_ID 0x054c 2862306a36Sopenharmony_ci#define PASORI_PRODUCT_ID 0x02e1 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define ACS_VENDOR_ID 0x072f 3162306a36Sopenharmony_ci#define ACR122U_PRODUCT_ID 0x2200 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic const struct usb_device_id pn533_usb_table[] = { 3462306a36Sopenharmony_ci { USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID), 3562306a36Sopenharmony_ci .driver_info = PN533_DEVICE_STD }, 3662306a36Sopenharmony_ci { USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID), 3762306a36Sopenharmony_ci .driver_info = PN533_DEVICE_STD }, 3862306a36Sopenharmony_ci { USB_DEVICE(SONY_VENDOR_ID, PASORI_PRODUCT_ID), 3962306a36Sopenharmony_ci .driver_info = PN533_DEVICE_PASORI }, 4062306a36Sopenharmony_ci { USB_DEVICE(ACS_VENDOR_ID, ACR122U_PRODUCT_ID), 4162306a36Sopenharmony_ci .driver_info = PN533_DEVICE_ACR122U }, 4262306a36Sopenharmony_ci { } 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, pn533_usb_table); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct pn533_usb_phy { 4762306a36Sopenharmony_ci struct usb_device *udev; 4862306a36Sopenharmony_ci struct usb_interface *interface; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci struct urb *out_urb; 5162306a36Sopenharmony_ci struct urb *in_urb; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci struct urb *ack_urb; 5462306a36Sopenharmony_ci u8 *ack_buffer; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci struct pn533 *priv; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void pn533_recv_response(struct urb *urb) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct pn533_usb_phy *phy = urb->context; 6262306a36Sopenharmony_ci struct sk_buff *skb = NULL; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (!urb->status) { 6562306a36Sopenharmony_ci skb = alloc_skb(urb->actual_length, GFP_ATOMIC); 6662306a36Sopenharmony_ci if (!skb) { 6762306a36Sopenharmony_ci nfc_err(&phy->udev->dev, "failed to alloc memory\n"); 6862306a36Sopenharmony_ci } else { 6962306a36Sopenharmony_ci skb_put_data(skb, urb->transfer_buffer, 7062306a36Sopenharmony_ci urb->actual_length); 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci pn533_recv_frame(phy->priv, skb, urb->status); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int pn533_submit_urb_for_response(struct pn533_usb_phy *phy, gfp_t flags) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci phy->in_urb->complete = pn533_recv_response; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return usb_submit_urb(phy->in_urb, flags); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void pn533_recv_ack(struct urb *urb) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct pn533_usb_phy *phy = urb->context; 8762306a36Sopenharmony_ci struct pn533 *priv = phy->priv; 8862306a36Sopenharmony_ci struct pn533_cmd *cmd = priv->cmd; 8962306a36Sopenharmony_ci struct pn533_std_frame *in_frame; 9062306a36Sopenharmony_ci int rc; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci cmd->status = urb->status; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci switch (urb->status) { 9562306a36Sopenharmony_ci case 0: 9662306a36Sopenharmony_ci break; /* success */ 9762306a36Sopenharmony_ci case -ECONNRESET: 9862306a36Sopenharmony_ci case -ENOENT: 9962306a36Sopenharmony_ci dev_dbg(&phy->udev->dev, 10062306a36Sopenharmony_ci "The urb has been stopped (status %d)\n", 10162306a36Sopenharmony_ci urb->status); 10262306a36Sopenharmony_ci goto sched_wq; 10362306a36Sopenharmony_ci case -ESHUTDOWN: 10462306a36Sopenharmony_ci default: 10562306a36Sopenharmony_ci nfc_err(&phy->udev->dev, 10662306a36Sopenharmony_ci "Urb failure (status %d)\n", urb->status); 10762306a36Sopenharmony_ci goto sched_wq; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci in_frame = phy->in_urb->transfer_buffer; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (!pn533_rx_frame_is_ack(in_frame)) { 11362306a36Sopenharmony_ci nfc_err(&phy->udev->dev, "Received an invalid ack\n"); 11462306a36Sopenharmony_ci cmd->status = -EIO; 11562306a36Sopenharmony_ci goto sched_wq; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci rc = pn533_submit_urb_for_response(phy, GFP_ATOMIC); 11962306a36Sopenharmony_ci if (rc) { 12062306a36Sopenharmony_ci nfc_err(&phy->udev->dev, 12162306a36Sopenharmony_ci "usb_submit_urb failed with result %d\n", rc); 12262306a36Sopenharmony_ci cmd->status = rc; 12362306a36Sopenharmony_ci goto sched_wq; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cisched_wq: 12962306a36Sopenharmony_ci queue_work(priv->wq, &priv->cmd_complete_work); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int pn533_submit_urb_for_ack(struct pn533_usb_phy *phy, gfp_t flags) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci phy->in_urb->complete = pn533_recv_ack; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return usb_submit_urb(phy->in_urb, flags); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct pn533_usb_phy *phy = dev->phy; 14262306a36Sopenharmony_ci static const u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; 14362306a36Sopenharmony_ci /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (!phy->ack_buffer) { 14662306a36Sopenharmony_ci phy->ack_buffer = kmemdup(ack, sizeof(ack), flags); 14762306a36Sopenharmony_ci if (!phy->ack_buffer) 14862306a36Sopenharmony_ci return -ENOMEM; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci phy->ack_urb->transfer_buffer = phy->ack_buffer; 15262306a36Sopenharmony_ci phy->ack_urb->transfer_buffer_length = sizeof(ack); 15362306a36Sopenharmony_ci return usb_submit_urb(phy->ack_urb, flags); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistruct pn533_out_arg { 15762306a36Sopenharmony_ci struct pn533_usb_phy *phy; 15862306a36Sopenharmony_ci struct completion done; 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int pn533_usb_send_frame(struct pn533 *dev, 16262306a36Sopenharmony_ci struct sk_buff *out) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct pn533_usb_phy *phy = dev->phy; 16562306a36Sopenharmony_ci struct pn533_out_arg arg; 16662306a36Sopenharmony_ci void *cntx; 16762306a36Sopenharmony_ci int rc; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (phy->priv == NULL) 17062306a36Sopenharmony_ci phy->priv = dev; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci phy->out_urb->transfer_buffer = out->data; 17362306a36Sopenharmony_ci phy->out_urb->transfer_buffer_length = out->len; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1, 17662306a36Sopenharmony_ci out->data, out->len, false); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci arg.phy = phy; 17962306a36Sopenharmony_ci init_completion(&arg.done); 18062306a36Sopenharmony_ci cntx = phy->out_urb->context; 18162306a36Sopenharmony_ci phy->out_urb->context = &arg; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci rc = usb_submit_urb(phy->out_urb, GFP_KERNEL); 18462306a36Sopenharmony_ci if (rc) 18562306a36Sopenharmony_ci return rc; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci wait_for_completion(&arg.done); 18862306a36Sopenharmony_ci phy->out_urb->context = cntx; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (dev->protocol_type == PN533_PROTO_REQ_RESP) { 19162306a36Sopenharmony_ci /* request for response for sent packet directly */ 19262306a36Sopenharmony_ci rc = pn533_submit_urb_for_response(phy, GFP_KERNEL); 19362306a36Sopenharmony_ci if (rc) 19462306a36Sopenharmony_ci goto error; 19562306a36Sopenharmony_ci } else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) { 19662306a36Sopenharmony_ci /* request for ACK if that's the case */ 19762306a36Sopenharmony_ci rc = pn533_submit_urb_for_ack(phy, GFP_KERNEL); 19862306a36Sopenharmony_ci if (rc) 19962306a36Sopenharmony_ci goto error; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cierror: 20562306a36Sopenharmony_ci usb_unlink_urb(phy->out_urb); 20662306a36Sopenharmony_ci return rc; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic void pn533_usb_abort_cmd(struct pn533 *dev, gfp_t flags) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct pn533_usb_phy *phy = dev->phy; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* ACR122U does not support any command which aborts last 21462306a36Sopenharmony_ci * issued command i.e. as ACK for standard PN533. Additionally, 21562306a36Sopenharmony_ci * it behaves stange, sending broken or incorrect responses, 21662306a36Sopenharmony_ci * when we cancel urb before the chip will send response. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci if (dev->device_type == PN533_DEVICE_ACR122U) 21962306a36Sopenharmony_ci return; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* An ack will cancel the last issued command */ 22262306a36Sopenharmony_ci pn533_usb_send_ack(dev, flags); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* cancel the urb request */ 22562306a36Sopenharmony_ci usb_kill_urb(phy->in_urb); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/* ACR122 specific structs and functions */ 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* ACS ACR122 pn533 frame definitions */ 23162306a36Sopenharmony_ci#define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \ 23262306a36Sopenharmony_ci + 2) 23362306a36Sopenharmony_ci#define PN533_ACR122_TX_FRAME_TAIL_LEN 0 23462306a36Sopenharmony_ci#define PN533_ACR122_RX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_rx_frame) \ 23562306a36Sopenharmony_ci + 2) 23662306a36Sopenharmony_ci#define PN533_ACR122_RX_FRAME_TAIL_LEN 2 23762306a36Sopenharmony_ci#define PN533_ACR122_FRAME_MAX_PAYLOAD_LEN PN533_STD_FRAME_MAX_PAYLOAD_LEN 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* CCID messages types */ 24062306a36Sopenharmony_ci#define PN533_ACR122_PC_TO_RDR_ICCPOWERON 0x62 24162306a36Sopenharmony_ci#define PN533_ACR122_PC_TO_RDR_ESCAPE 0x6B 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistruct pn533_acr122_ccid_hdr { 24762306a36Sopenharmony_ci u8 type; 24862306a36Sopenharmony_ci u32 datalen; 24962306a36Sopenharmony_ci u8 slot; 25062306a36Sopenharmony_ci u8 seq; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* 25362306a36Sopenharmony_ci * 3 msg specific bytes or status, error and 1 specific 25462306a36Sopenharmony_ci * byte for reposnse msg 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci u8 params[3]; 25762306a36Sopenharmony_ci u8 data[]; /* payload */ 25862306a36Sopenharmony_ci} __packed; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistruct pn533_acr122_apdu_hdr { 26162306a36Sopenharmony_ci u8 class; 26262306a36Sopenharmony_ci u8 ins; 26362306a36Sopenharmony_ci u8 p1; 26462306a36Sopenharmony_ci u8 p2; 26562306a36Sopenharmony_ci} __packed; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistruct pn533_acr122_tx_frame { 26862306a36Sopenharmony_ci struct pn533_acr122_ccid_hdr ccid; 26962306a36Sopenharmony_ci struct pn533_acr122_apdu_hdr apdu; 27062306a36Sopenharmony_ci u8 datalen; 27162306a36Sopenharmony_ci u8 data[]; /* pn533 frame: TFI ... */ 27262306a36Sopenharmony_ci} __packed; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistruct pn533_acr122_rx_frame { 27562306a36Sopenharmony_ci struct pn533_acr122_ccid_hdr ccid; 27662306a36Sopenharmony_ci u8 data[]; /* pn533 frame : TFI ... */ 27762306a36Sopenharmony_ci} __packed; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic void pn533_acr122_tx_frame_init(void *_frame, u8 cmd_code) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct pn533_acr122_tx_frame *frame = _frame; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci frame->ccid.type = PN533_ACR122_PC_TO_RDR_ESCAPE; 28462306a36Sopenharmony_ci /* sizeof(apdu_hdr) + sizeof(datalen) */ 28562306a36Sopenharmony_ci frame->ccid.datalen = sizeof(frame->apdu) + 1; 28662306a36Sopenharmony_ci frame->ccid.slot = 0; 28762306a36Sopenharmony_ci frame->ccid.seq = 0; 28862306a36Sopenharmony_ci frame->ccid.params[0] = 0; 28962306a36Sopenharmony_ci frame->ccid.params[1] = 0; 29062306a36Sopenharmony_ci frame->ccid.params[2] = 0; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci frame->data[0] = PN533_STD_FRAME_DIR_OUT; 29362306a36Sopenharmony_ci frame->data[1] = cmd_code; 29462306a36Sopenharmony_ci frame->datalen = 2; /* data[0] + data[1] */ 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci frame->apdu.class = 0xFF; 29762306a36Sopenharmony_ci frame->apdu.ins = 0; 29862306a36Sopenharmony_ci frame->apdu.p1 = 0; 29962306a36Sopenharmony_ci frame->apdu.p2 = 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic void pn533_acr122_tx_frame_finish(void *_frame) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct pn533_acr122_tx_frame *frame = _frame; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci frame->ccid.datalen += frame->datalen; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic void pn533_acr122_tx_update_payload_len(void *_frame, int len) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct pn533_acr122_tx_frame *frame = _frame; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci frame->datalen += len; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct pn533_acr122_rx_frame *frame = _frame; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (frame->ccid.type != 0x83) 32162306a36Sopenharmony_ci return false; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (!frame->ccid.datalen) 32462306a36Sopenharmony_ci return false; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (frame->data[frame->ccid.datalen - 2] == 0x63) 32762306a36Sopenharmony_ci return false; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return true; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int pn533_acr122_rx_frame_size(void *frame) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct pn533_acr122_rx_frame *f = frame; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* f->ccid.datalen already includes tail length */ 33762306a36Sopenharmony_ci return sizeof(struct pn533_acr122_rx_frame) + f->ccid.datalen; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic u8 pn533_acr122_get_cmd_code(void *frame) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct pn533_acr122_rx_frame *f = frame; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return PN533_FRAME_CMD(f); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic struct pn533_frame_ops pn533_acr122_frame_ops = { 34862306a36Sopenharmony_ci .tx_frame_init = pn533_acr122_tx_frame_init, 34962306a36Sopenharmony_ci .tx_frame_finish = pn533_acr122_tx_frame_finish, 35062306a36Sopenharmony_ci .tx_update_payload_len = pn533_acr122_tx_update_payload_len, 35162306a36Sopenharmony_ci .tx_header_len = PN533_ACR122_TX_FRAME_HEADER_LEN, 35262306a36Sopenharmony_ci .tx_tail_len = PN533_ACR122_TX_FRAME_TAIL_LEN, 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci .rx_is_frame_valid = pn533_acr122_is_rx_frame_valid, 35562306a36Sopenharmony_ci .rx_header_len = PN533_ACR122_RX_FRAME_HEADER_LEN, 35662306a36Sopenharmony_ci .rx_tail_len = PN533_ACR122_RX_FRAME_TAIL_LEN, 35762306a36Sopenharmony_ci .rx_frame_size = pn533_acr122_rx_frame_size, 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci .max_payload_len = PN533_ACR122_FRAME_MAX_PAYLOAD_LEN, 36062306a36Sopenharmony_ci .get_cmd_code = pn533_acr122_get_cmd_code, 36162306a36Sopenharmony_ci}; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistruct pn533_acr122_poweron_rdr_arg { 36462306a36Sopenharmony_ci int rc; 36562306a36Sopenharmony_ci struct completion done; 36662306a36Sopenharmony_ci}; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic void pn533_acr122_poweron_rdr_resp(struct urb *urb) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct pn533_acr122_poweron_rdr_arg *arg = urb->context; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci print_hex_dump_debug("ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1, 37362306a36Sopenharmony_ci urb->transfer_buffer, urb->transfer_buffer_length, 37462306a36Sopenharmony_ci false); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci arg->rc = urb->status; 37762306a36Sopenharmony_ci complete(&arg->done); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci /* Power on th reader (CCID cmd) */ 38362306a36Sopenharmony_ci u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON, 38462306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, 3, 0, 0}; 38562306a36Sopenharmony_ci char *buffer; 38662306a36Sopenharmony_ci int transferred; 38762306a36Sopenharmony_ci int rc; 38862306a36Sopenharmony_ci void *cntx; 38962306a36Sopenharmony_ci struct pn533_acr122_poweron_rdr_arg arg; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci buffer = kmemdup(cmd, sizeof(cmd), GFP_KERNEL); 39262306a36Sopenharmony_ci if (!buffer) 39362306a36Sopenharmony_ci return -ENOMEM; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci init_completion(&arg.done); 39662306a36Sopenharmony_ci cntx = phy->in_urb->context; /* backup context */ 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci phy->in_urb->complete = pn533_acr122_poweron_rdr_resp; 39962306a36Sopenharmony_ci phy->in_urb->context = &arg; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci print_hex_dump_debug("ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1, 40262306a36Sopenharmony_ci cmd, sizeof(cmd), false); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci rc = usb_bulk_msg(phy->udev, phy->out_urb->pipe, buffer, sizeof(cmd), 40562306a36Sopenharmony_ci &transferred, 5000); 40662306a36Sopenharmony_ci kfree(buffer); 40762306a36Sopenharmony_ci if (rc || (transferred != sizeof(cmd))) { 40862306a36Sopenharmony_ci nfc_err(&phy->udev->dev, 40962306a36Sopenharmony_ci "Reader power on cmd error %d\n", rc); 41062306a36Sopenharmony_ci return rc; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci rc = usb_submit_urb(phy->in_urb, GFP_KERNEL); 41462306a36Sopenharmony_ci if (rc) { 41562306a36Sopenharmony_ci nfc_err(&phy->udev->dev, 41662306a36Sopenharmony_ci "Can't submit reader poweron cmd response %d\n", rc); 41762306a36Sopenharmony_ci return rc; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci wait_for_completion(&arg.done); 42162306a36Sopenharmony_ci phy->in_urb->context = cntx; /* restore context */ 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return arg.rc; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic void pn533_out_complete(struct urb *urb) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct pn533_out_arg *arg = urb->context; 42962306a36Sopenharmony_ci struct pn533_usb_phy *phy = arg->phy; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci switch (urb->status) { 43262306a36Sopenharmony_ci case 0: 43362306a36Sopenharmony_ci break; /* success */ 43462306a36Sopenharmony_ci case -ECONNRESET: 43562306a36Sopenharmony_ci case -ENOENT: 43662306a36Sopenharmony_ci dev_dbg(&phy->udev->dev, 43762306a36Sopenharmony_ci "The urb has been stopped (status %d)\n", 43862306a36Sopenharmony_ci urb->status); 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci case -ESHUTDOWN: 44162306a36Sopenharmony_ci default: 44262306a36Sopenharmony_ci nfc_err(&phy->udev->dev, 44362306a36Sopenharmony_ci "Urb failure (status %d)\n", 44462306a36Sopenharmony_ci urb->status); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci complete(&arg->done); 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic void pn533_ack_complete(struct urb *urb) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct pn533_usb_phy *phy = urb->context; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci switch (urb->status) { 45562306a36Sopenharmony_ci case 0: 45662306a36Sopenharmony_ci break; /* success */ 45762306a36Sopenharmony_ci case -ECONNRESET: 45862306a36Sopenharmony_ci case -ENOENT: 45962306a36Sopenharmony_ci dev_dbg(&phy->udev->dev, 46062306a36Sopenharmony_ci "The urb has been stopped (status %d)\n", 46162306a36Sopenharmony_ci urb->status); 46262306a36Sopenharmony_ci break; 46362306a36Sopenharmony_ci case -ESHUTDOWN: 46462306a36Sopenharmony_ci default: 46562306a36Sopenharmony_ci nfc_err(&phy->udev->dev, 46662306a36Sopenharmony_ci "Urb failure (status %d)\n", 46762306a36Sopenharmony_ci urb->status); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic const struct pn533_phy_ops usb_phy_ops = { 47262306a36Sopenharmony_ci .send_frame = pn533_usb_send_frame, 47362306a36Sopenharmony_ci .send_ack = pn533_usb_send_ack, 47462306a36Sopenharmony_ci .abort_cmd = pn533_usb_abort_cmd, 47562306a36Sopenharmony_ci}; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int pn533_usb_probe(struct usb_interface *interface, 47862306a36Sopenharmony_ci const struct usb_device_id *id) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct pn533 *priv; 48162306a36Sopenharmony_ci struct pn533_usb_phy *phy; 48262306a36Sopenharmony_ci struct usb_host_interface *iface_desc; 48362306a36Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 48462306a36Sopenharmony_ci int in_endpoint = 0; 48562306a36Sopenharmony_ci int out_endpoint = 0; 48662306a36Sopenharmony_ci int rc = -ENOMEM; 48762306a36Sopenharmony_ci int i; 48862306a36Sopenharmony_ci u32 protocols; 48962306a36Sopenharmony_ci enum pn533_protocol_type protocol_type = PN533_PROTO_REQ_ACK_RESP; 49062306a36Sopenharmony_ci struct pn533_frame_ops *fops = NULL; 49162306a36Sopenharmony_ci unsigned char *in_buf; 49262306a36Sopenharmony_ci int in_buf_len = PN533_EXT_FRAME_HEADER_LEN + 49362306a36Sopenharmony_ci PN533_STD_FRAME_MAX_PAYLOAD_LEN + 49462306a36Sopenharmony_ci PN533_STD_FRAME_TAIL_LEN; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci phy = devm_kzalloc(&interface->dev, sizeof(*phy), GFP_KERNEL); 49762306a36Sopenharmony_ci if (!phy) 49862306a36Sopenharmony_ci return -ENOMEM; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci in_buf = kzalloc(in_buf_len, GFP_KERNEL); 50162306a36Sopenharmony_ci if (!in_buf) 50262306a36Sopenharmony_ci return -ENOMEM; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci phy->udev = usb_get_dev(interface_to_usbdev(interface)); 50562306a36Sopenharmony_ci phy->interface = interface; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci iface_desc = interface->cur_altsetting; 50862306a36Sopenharmony_ci for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 50962306a36Sopenharmony_ci endpoint = &iface_desc->endpoint[i].desc; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint)) 51262306a36Sopenharmony_ci in_endpoint = endpoint->bEndpointAddress; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint)) 51562306a36Sopenharmony_ci out_endpoint = endpoint->bEndpointAddress; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (!in_endpoint || !out_endpoint) { 51962306a36Sopenharmony_ci nfc_err(&interface->dev, 52062306a36Sopenharmony_ci "Could not find bulk-in or bulk-out endpoint\n"); 52162306a36Sopenharmony_ci rc = -ENODEV; 52262306a36Sopenharmony_ci goto error; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci phy->in_urb = usb_alloc_urb(0, GFP_KERNEL); 52662306a36Sopenharmony_ci phy->out_urb = usb_alloc_urb(0, GFP_KERNEL); 52762306a36Sopenharmony_ci phy->ack_urb = usb_alloc_urb(0, GFP_KERNEL); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (!phy->in_urb || !phy->out_urb || !phy->ack_urb) 53062306a36Sopenharmony_ci goto error; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci usb_fill_bulk_urb(phy->in_urb, phy->udev, 53362306a36Sopenharmony_ci usb_rcvbulkpipe(phy->udev, in_endpoint), 53462306a36Sopenharmony_ci in_buf, in_buf_len, NULL, phy); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci usb_fill_bulk_urb(phy->out_urb, phy->udev, 53762306a36Sopenharmony_ci usb_sndbulkpipe(phy->udev, out_endpoint), 53862306a36Sopenharmony_ci NULL, 0, pn533_out_complete, phy); 53962306a36Sopenharmony_ci usb_fill_bulk_urb(phy->ack_urb, phy->udev, 54062306a36Sopenharmony_ci usb_sndbulkpipe(phy->udev, out_endpoint), 54162306a36Sopenharmony_ci NULL, 0, pn533_ack_complete, phy); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci switch (id->driver_info) { 54462306a36Sopenharmony_ci case PN533_DEVICE_STD: 54562306a36Sopenharmony_ci protocols = PN533_ALL_PROTOCOLS; 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci case PN533_DEVICE_PASORI: 54962306a36Sopenharmony_ci protocols = PN533_NO_TYPE_B_PROTOCOLS; 55062306a36Sopenharmony_ci break; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci case PN533_DEVICE_ACR122U: 55362306a36Sopenharmony_ci protocols = PN533_NO_TYPE_B_PROTOCOLS; 55462306a36Sopenharmony_ci fops = &pn533_acr122_frame_ops; 55562306a36Sopenharmony_ci protocol_type = PN533_PROTO_REQ_RESP; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci rc = pn533_acr122_poweron_rdr(phy); 55862306a36Sopenharmony_ci if (rc < 0) { 55962306a36Sopenharmony_ci nfc_err(&interface->dev, 56062306a36Sopenharmony_ci "Couldn't poweron the reader (error %d)\n", rc); 56162306a36Sopenharmony_ci goto error; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci break; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci default: 56662306a36Sopenharmony_ci nfc_err(&interface->dev, "Unknown device type %lu\n", 56762306a36Sopenharmony_ci id->driver_info); 56862306a36Sopenharmony_ci rc = -EINVAL; 56962306a36Sopenharmony_ci goto error; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci priv = pn53x_common_init(id->driver_info, protocol_type, 57362306a36Sopenharmony_ci phy, &usb_phy_ops, fops, 57462306a36Sopenharmony_ci &phy->udev->dev); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (IS_ERR(priv)) { 57762306a36Sopenharmony_ci rc = PTR_ERR(priv); 57862306a36Sopenharmony_ci goto error; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci phy->priv = priv; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci rc = pn533_finalize_setup(priv); 58462306a36Sopenharmony_ci if (rc) 58562306a36Sopenharmony_ci goto err_clean; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci usb_set_intfdata(interface, phy); 58862306a36Sopenharmony_ci rc = pn53x_register_nfc(priv, protocols, &interface->dev); 58962306a36Sopenharmony_ci if (rc) 59062306a36Sopenharmony_ci goto err_clean; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cierr_clean: 59562306a36Sopenharmony_ci pn53x_common_clean(priv); 59662306a36Sopenharmony_cierror: 59762306a36Sopenharmony_ci usb_kill_urb(phy->in_urb); 59862306a36Sopenharmony_ci usb_kill_urb(phy->out_urb); 59962306a36Sopenharmony_ci usb_kill_urb(phy->ack_urb); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci usb_free_urb(phy->in_urb); 60262306a36Sopenharmony_ci usb_free_urb(phy->out_urb); 60362306a36Sopenharmony_ci usb_free_urb(phy->ack_urb); 60462306a36Sopenharmony_ci usb_put_dev(phy->udev); 60562306a36Sopenharmony_ci kfree(in_buf); 60662306a36Sopenharmony_ci kfree(phy->ack_buffer); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return rc; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic void pn533_usb_disconnect(struct usb_interface *interface) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct pn533_usb_phy *phy = usb_get_intfdata(interface); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (!phy) 61662306a36Sopenharmony_ci return; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci pn53x_unregister_nfc(phy->priv); 61962306a36Sopenharmony_ci pn53x_common_clean(phy->priv); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci usb_set_intfdata(interface, NULL); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci usb_kill_urb(phy->in_urb); 62462306a36Sopenharmony_ci usb_kill_urb(phy->out_urb); 62562306a36Sopenharmony_ci usb_kill_urb(phy->ack_urb); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci kfree(phy->in_urb->transfer_buffer); 62862306a36Sopenharmony_ci usb_free_urb(phy->in_urb); 62962306a36Sopenharmony_ci usb_free_urb(phy->out_urb); 63062306a36Sopenharmony_ci usb_free_urb(phy->ack_urb); 63162306a36Sopenharmony_ci kfree(phy->ack_buffer); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci nfc_info(&interface->dev, "NXP PN533 NFC device disconnected\n"); 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic struct usb_driver pn533_usb_driver = { 63762306a36Sopenharmony_ci .name = "pn533_usb", 63862306a36Sopenharmony_ci .probe = pn533_usb_probe, 63962306a36Sopenharmony_ci .disconnect = pn533_usb_disconnect, 64062306a36Sopenharmony_ci .id_table = pn533_usb_table, 64162306a36Sopenharmony_ci}; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cimodule_usb_driver(pn533_usb_driver); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ciMODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>"); 64662306a36Sopenharmony_ciMODULE_AUTHOR("Aloisio Almeida Jr <aloisio.almeida@openbossa.org>"); 64762306a36Sopenharmony_ciMODULE_AUTHOR("Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>"); 64862306a36Sopenharmony_ciMODULE_DESCRIPTION("PN533 USB driver ver " VERSION); 64962306a36Sopenharmony_ciMODULE_VERSION(VERSION); 65062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 651