diff options
Diffstat (limited to 'drivers/nfc/pn533/usb.c')
| -rw-r--r-- | drivers/nfc/pn533/usb.c | 131 |
1 files changed, 91 insertions, 40 deletions
diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index e153e8b64bb8..ffd7367ce119 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for NXP PN533 NFC Chip - USB transport layer * * Copyright (C) 2011 Instituto Nokia de Tecnologia * Copyright (C) 2012-2013 Tieto Poland - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/device.h> @@ -62,6 +50,9 @@ struct pn533_usb_phy { struct urb *out_urb; struct urb *in_urb; + struct urb *ack_urb; + u8 *ack_buffer; + struct pn533 *priv; }; @@ -71,7 +62,7 @@ static void pn533_recv_response(struct urb *urb) struct sk_buff *skb = NULL; if (!urb->status) { - skb = alloc_skb(urb->actual_length, GFP_KERNEL); + skb = alloc_skb(urb->actual_length, GFP_ATOMIC); if (!skb) { nfc_err(&phy->udev->dev, "failed to alloc memory\n"); } else { @@ -150,19 +141,29 @@ static int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags) struct pn533_usb_phy *phy = dev->phy; static const u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ - int rc; - phy->out_urb->transfer_buffer = (u8 *)ack; - phy->out_urb->transfer_buffer_length = sizeof(ack); - rc = usb_submit_urb(phy->out_urb, flags); + if (!phy->ack_buffer) { + phy->ack_buffer = kmemdup(ack, sizeof(ack), flags); + if (!phy->ack_buffer) + return -ENOMEM; + } - return rc; + phy->ack_urb->transfer_buffer = phy->ack_buffer; + phy->ack_urb->transfer_buffer_length = sizeof(ack); + return usb_submit_urb(phy->ack_urb, flags); } +struct pn533_out_arg { + struct pn533_usb_phy *phy; + struct completion done; +}; + static int pn533_usb_send_frame(struct pn533 *dev, struct sk_buff *out) { struct pn533_usb_phy *phy = dev->phy; + struct pn533_out_arg arg; + void *cntx; int rc; if (phy->priv == NULL) @@ -174,13 +175,21 @@ static int pn533_usb_send_frame(struct pn533 *dev, print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1, out->data, out->len, false); + arg.phy = phy; + init_completion(&arg.done); + cntx = phy->out_urb->context; + phy->out_urb->context = &arg; + rc = usb_submit_urb(phy->out_urb, GFP_KERNEL); if (rc) return rc; + wait_for_completion(&arg.done); + phy->out_urb->context = cntx; + if (dev->protocol_type == PN533_PROTO_REQ_RESP) { /* request for response for sent packet directly */ - rc = pn533_submit_urb_for_response(phy, GFP_ATOMIC); + rc = pn533_submit_urb_for_response(phy, GFP_KERNEL); if (rc) goto error; } else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) { @@ -216,7 +225,7 @@ static void pn533_usb_abort_cmd(struct pn533 *dev, gfp_t flags) usb_kill_urb(phy->in_urb); } -/* ACR122 specific structs and fucntions */ +/* ACR122 specific structs and functions */ /* ACS ACR122 pn533 frame definitions */ #define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \ @@ -245,7 +254,6 @@ struct pn533_acr122_ccid_hdr { * byte for reposnse msg */ u8 params[3]; - u8 data[]; /* payload */ } __packed; struct pn533_acr122_apdu_hdr { @@ -360,8 +368,6 @@ static void pn533_acr122_poweron_rdr_resp(struct urb *urb) { struct pn533_acr122_poweron_rdr_arg *arg = urb->context; - dev_dbg(&urb->dev->dev, "%s\n", __func__); - print_hex_dump_debug("ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1, urb->transfer_buffer, urb->transfer_buffer_length, false); @@ -375,11 +381,15 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) /* Power on th reader (CCID cmd) */ u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON, 0, 0, 0, 0, 0, 0, 3, 0, 0}; + char *buffer; + int transferred; int rc; void *cntx; struct pn533_acr122_poweron_rdr_arg arg; - dev_dbg(&phy->udev->dev, "%s\n", __func__); + buffer = kmemdup(cmd, sizeof(cmd), GFP_KERNEL); + if (!buffer) + return -ENOMEM; init_completion(&arg.done); cntx = phy->in_urb->context; /* backup context */ @@ -387,14 +397,13 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) phy->in_urb->complete = pn533_acr122_poweron_rdr_resp; phy->in_urb->context = &arg; - phy->out_urb->transfer_buffer = cmd; - phy->out_urb->transfer_buffer_length = sizeof(cmd); - print_hex_dump_debug("ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1, cmd, sizeof(cmd), false); - rc = usb_submit_urb(phy->out_urb, GFP_KERNEL); - if (rc) { + rc = usb_bulk_msg(phy->udev, phy->out_urb->pipe, buffer, sizeof(cmd), + &transferred, 5000); + kfree(buffer); + if (rc || (transferred != sizeof(cmd))) { nfc_err(&phy->udev->dev, "Reader power on cmd error %d\n", rc); return rc; @@ -413,7 +422,31 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) return arg.rc; } -static void pn533_send_complete(struct urb *urb) +static void pn533_out_complete(struct urb *urb) +{ + struct pn533_out_arg *arg = urb->context; + struct pn533_usb_phy *phy = arg->phy; + + switch (urb->status) { + case 0: + break; /* success */ + case -ECONNRESET: + case -ENOENT: + dev_dbg(&phy->udev->dev, + "The urb has been stopped (status %d)\n", + urb->status); + break; + case -ESHUTDOWN: + default: + nfc_err(&phy->udev->dev, + "Urb failure (status %d)\n", + urb->status); + } + + complete(&arg->done); +} + +static void pn533_ack_complete(struct urb *urb) { struct pn533_usb_phy *phy = urb->context; @@ -434,7 +467,7 @@ static void pn533_send_complete(struct urb *urb) } } -static struct pn533_phy_ops usb_phy_ops = { +static const struct pn533_phy_ops usb_phy_ops = { .send_frame = pn533_usb_send_frame, .send_ack = pn533_usb_send_ack, .abort_cmd = pn533_usb_abort_cmd, @@ -490,8 +523,9 @@ static int pn533_usb_probe(struct usb_interface *interface, phy->in_urb = usb_alloc_urb(0, GFP_KERNEL); phy->out_urb = usb_alloc_urb(0, GFP_KERNEL); + phy->ack_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!phy->in_urb || !phy->out_urb) + if (!phy->in_urb || !phy->out_urb || !phy->ack_urb) goto error; usb_fill_bulk_urb(phy->in_urb, phy->udev, @@ -500,8 +534,10 @@ static int pn533_usb_probe(struct usb_interface *interface, usb_fill_bulk_urb(phy->out_urb, phy->udev, usb_sndbulkpipe(phy->udev, out_endpoint), - NULL, 0, pn533_send_complete, phy); - + NULL, 0, pn533_out_complete, phy); + usb_fill_bulk_urb(phy->ack_urb, phy->udev, + usb_sndbulkpipe(phy->udev, out_endpoint), + NULL, 0, pn533_ack_complete, phy); switch (id->driver_info) { case PN533_DEVICE_STD: @@ -515,7 +551,7 @@ static int pn533_usb_probe(struct usb_interface *interface, case PN533_DEVICE_ACR122U: protocols = PN533_NO_TYPE_B_PROTOCOLS; fops = &pn533_acr122_frame_ops; - protocol_type = PN533_PROTO_REQ_RESP, + protocol_type = PN533_PROTO_REQ_RESP; rc = pn533_acr122_poweron_rdr(phy); if (rc < 0) { @@ -532,9 +568,9 @@ static int pn533_usb_probe(struct usb_interface *interface, goto error; } - priv = pn533_register_device(id->driver_info, protocols, protocol_type, + priv = pn53x_common_init(id->driver_info, protocol_type, phy, &usb_phy_ops, fops, - &phy->udev->dev, &interface->dev); + &phy->udev->dev); if (IS_ERR(priv)) { rc = PTR_ERR(priv); @@ -545,17 +581,28 @@ static int pn533_usb_probe(struct usb_interface *interface, rc = pn533_finalize_setup(priv); if (rc) - goto error; + goto err_clean; usb_set_intfdata(interface, phy); + rc = pn53x_register_nfc(priv, protocols, &interface->dev); + if (rc) + goto err_clean; return 0; +err_clean: + pn53x_common_clean(priv); error: + usb_kill_urb(phy->in_urb); + usb_kill_urb(phy->out_urb); + usb_kill_urb(phy->ack_urb); + usb_free_urb(phy->in_urb); usb_free_urb(phy->out_urb); + usb_free_urb(phy->ack_urb); usb_put_dev(phy->udev); kfree(in_buf); + kfree(phy->ack_buffer); return rc; } @@ -567,16 +614,20 @@ static void pn533_usb_disconnect(struct usb_interface *interface) if (!phy) return; - pn533_unregister_device(phy->priv); + pn53x_unregister_nfc(phy->priv); + pn53x_common_clean(phy->priv); usb_set_intfdata(interface, NULL); usb_kill_urb(phy->in_urb); usb_kill_urb(phy->out_urb); + usb_kill_urb(phy->ack_urb); kfree(phy->in_urb->transfer_buffer); usb_free_urb(phy->in_urb); usb_free_urb(phy->out_urb); + usb_free_urb(phy->ack_urb); + kfree(phy->ack_buffer); nfc_info(&interface->dev, "NXP PN533 NFC device disconnected\n"); } |
