1f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar/** 2f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * Marvell NFC-over-USB driver: USB interface related functions 3f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * 4f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * Copyright (C) 2014, Marvell International Ltd. 5f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * 6f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * This software file (the "File") is distributed by Marvell International 7f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * Ltd. under the terms of the GNU General Public License Version 2, June 1991 8f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * (the "License"). You may use, redistribute and/or modify this File in 9f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * accordance with the terms and conditions of the License, a copy of which 10f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * is available on the worldwide web at 11f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 12f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * 13f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 14f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 15f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 16f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * this warranty disclaimer. 17f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar **/ 18f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 19f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#include <linux/module.h> 20f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#include <linux/usb.h> 21f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#include <linux/nfc.h> 22f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#include <net/nfc/nci.h> 23f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#include <net/nfc/nci_core.h> 24f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#include "nfcmrvl.h" 25f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 26f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#define VERSION "1.0" 27f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 28f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic struct usb_device_id nfcmrvl_table[] = { 29f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar { USB_DEVICE_INTERFACE_CLASS(0x1286, 0x2046, 0xff) }, 30f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar { } /* Terminating entry */ 31f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar}; 32f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 33f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar KarwarMODULE_DEVICE_TABLE(usb, nfcmrvl_table); 34f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 35f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#define NFCMRVL_USB_BULK_RUNNING 1 36f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#define NFCMRVL_USB_SUSPENDING 2 37f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 38f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstruct nfcmrvl_usb_drv_data { 39f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct usb_device *udev; 40f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct usb_interface *intf; 41f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar unsigned long flags; 42f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct work_struct waker; 43f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct usb_anchor tx_anchor; 44f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct usb_anchor bulk_anchor; 45f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct usb_anchor deferred; 46f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int tx_in_flight; 47f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar /* protects tx_in_flight */ 48f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spinlock_t txlock; 49f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct usb_endpoint_descriptor *bulk_tx_ep; 50f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct usb_endpoint_descriptor *bulk_rx_ep; 51f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int suspend_count; 52f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_private *priv; 53f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar}; 54f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 55f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data) 56f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 57f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar unsigned long flags; 58f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int rv; 59f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 60f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_lock_irqsave(&drv_data->txlock, flags); 61f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar rv = test_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags); 62f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!rv) 63f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->tx_in_flight++; 64f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_unlock_irqrestore(&drv_data->txlock, flags); 65f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 66f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return rv; 67f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 68f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 69f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic void nfcmrvl_bulk_complete(struct urb *urb) 70f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 71f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data = urb->context; 72f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int err; 73f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 74f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d", 75f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar urb, urb->status, urb->actual_length); 76f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 77f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags)) 78f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return; 79f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 80f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!urb->status) { 81f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (nfcmrvl_nci_recv_frame(drv_data->priv, urb->transfer_buffer, 82f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar urb->actual_length) < 0) 83f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfc_err(&drv_data->udev->dev, "corrupted Rx packet"); 84f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 85f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 86f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags)) 87f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return; 88f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 89f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_anchor_urb(urb, &drv_data->bulk_anchor); 90f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_mark_last_busy(drv_data->udev); 91f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 92f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = usb_submit_urb(urb, GFP_ATOMIC); 93f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) { 94f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar /* -EPERM: urb is being killed; 95f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar * -ENODEV: device got disconnected 96f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar */ 97f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err != -EPERM && err != -ENODEV) 98f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfc_err(&drv_data->udev->dev, 99f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar "urb %p failed to resubmit (%d)", urb, -err); 100f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_unanchor_urb(urb); 101f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 102f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 103f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 104f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic int 105f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarnfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags) 106f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 107f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct urb *urb; 108f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar unsigned char *buf; 109f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar unsigned int pipe; 110f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int err, size = NFCMRVL_NCI_MAX_EVENT_SIZE; 111f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 112f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!drv_data->bulk_rx_ep) 113f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return -ENODEV; 114f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 115f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar urb = usb_alloc_urb(0, mem_flags); 116f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!urb) 117f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return -ENOMEM; 118f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 119f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar buf = kmalloc(size, mem_flags); 120f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!buf) { 121f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_free_urb(urb); 122f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return -ENOMEM; 123f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 124f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 125f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar pipe = usb_rcvbulkpipe(drv_data->udev, 126f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->bulk_rx_ep->bEndpointAddress); 127f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 128f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_fill_bulk_urb(urb, drv_data->udev, pipe, buf, size, 129f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfcmrvl_bulk_complete, drv_data); 130f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 131f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar urb->transfer_flags |= URB_FREE_BUFFER; 132f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 133f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_mark_last_busy(drv_data->udev); 134f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_anchor_urb(urb, &drv_data->bulk_anchor); 135f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 136f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = usb_submit_urb(urb, mem_flags); 137f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) { 138f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err != -EPERM && err != -ENODEV) 139f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfc_err(&drv_data->udev->dev, 140f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar "urb %p submission failed (%d)", urb, -err); 141f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_unanchor_urb(urb); 142f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 143f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 144f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_free_urb(urb); 145f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 146f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return err; 147f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 148f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 149f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic void nfcmrvl_tx_complete(struct urb *urb) 150f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 151f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct sk_buff *skb = urb->context; 152f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nci_dev *ndev = (struct nci_dev *)skb->dev; 153f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_private *priv = nci_get_drvdata(ndev); 154f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data; 155f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 156f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfc_info(priv->dev, "urb %p status %d count %d", 157f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar urb, urb->status, urb->actual_length); 158f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 159f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_lock(&drv_data->txlock); 160f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->tx_in_flight--; 161f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_unlock(&drv_data->txlock); 162f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 163f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar kfree(urb->setup_packet); 164f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar kfree_skb(skb); 165f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 166f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 167f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic int nfcmrvl_usb_nci_open(struct nfcmrvl_private *priv) 168f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 169f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data; 170f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int err; 171f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 172f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = usb_autopm_get_interface(drv_data->intf); 173f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) 174f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return err; 175f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 176f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->intf->needs_remote_wakeup = 1; 177f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 178f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL); 179f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) 180f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar goto failed; 181f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 182f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar set_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags); 183f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL); 184f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 185f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_autopm_put_interface(drv_data->intf); 186f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return 0; 187f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 188f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarfailed: 189f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_autopm_put_interface(drv_data->intf); 190f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return err; 191f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 192f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 193f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic void nfcmrvl_usb_stop_traffic(struct nfcmrvl_usb_drv_data *drv_data) 194f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 195f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_kill_anchored_urbs(&drv_data->bulk_anchor); 196f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 197f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 198f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic int nfcmrvl_usb_nci_close(struct nfcmrvl_private *priv) 199f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 200f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data; 201f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int err; 202f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 203f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar cancel_work_sync(&drv_data->waker); 204f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 205f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags); 206f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 207f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfcmrvl_usb_stop_traffic(drv_data); 208f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_kill_anchored_urbs(&drv_data->tx_anchor); 209f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = usb_autopm_get_interface(drv_data->intf); 210f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) 211f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar goto failed; 212f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 213f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->intf->needs_remote_wakeup = 0; 214f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_autopm_put_interface(drv_data->intf); 215f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 216f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarfailed: 217f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_scuttle_anchored_urbs(&drv_data->deferred); 218f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return 0; 219f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 220f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 221f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic int nfcmrvl_usb_nci_send(struct nfcmrvl_private *priv, 222f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct sk_buff *skb) 223f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 224f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data; 225f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct urb *urb; 226f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar unsigned int pipe; 227f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int err; 228f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 229f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!drv_data->bulk_tx_ep) 230f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return -ENODEV; 231f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 232f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar urb = usb_alloc_urb(0, GFP_ATOMIC); 233f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!urb) 234f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return -ENOMEM; 235f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 236f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar pipe = usb_sndbulkpipe(drv_data->udev, 237f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->bulk_tx_ep->bEndpointAddress); 238f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 239f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_fill_bulk_urb(urb, drv_data->udev, pipe, skb->data, skb->len, 240f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfcmrvl_tx_complete, skb); 241f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 242f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = nfcmrvl_inc_tx(drv_data); 243f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) { 244f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_anchor_urb(urb, &drv_data->deferred); 245f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar schedule_work(&drv_data->waker); 246f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = 0; 247f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar goto done; 248f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 249f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 250f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_anchor_urb(urb, &drv_data->tx_anchor); 251f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 252f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = usb_submit_urb(urb, GFP_ATOMIC); 253f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) { 254f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err != -EPERM && err != -ENODEV) 255f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfc_err(&drv_data->udev->dev, 256f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar "urb %p submission failed (%d)", urb, -err); 257f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar kfree(urb->setup_packet); 258f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_unanchor_urb(urb); 259f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } else { 260f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_mark_last_busy(drv_data->udev); 261f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 262f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 263f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwardone: 264f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_free_urb(urb); 265f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return err; 266f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 267f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 268f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic struct nfcmrvl_if_ops usb_ops = { 269f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .nci_open = nfcmrvl_usb_nci_open, 270f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .nci_close = nfcmrvl_usb_nci_close, 271f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .nci_send = nfcmrvl_usb_nci_send, 272f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar}; 273f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 274f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic void nfcmrvl_waker(struct work_struct *work) 275f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 276f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data = 277f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar container_of(work, struct nfcmrvl_usb_drv_data, waker); 278f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int err; 279f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 280f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = usb_autopm_get_interface(drv_data->intf); 281f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) 282f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return; 283f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 284f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_autopm_put_interface(drv_data->intf); 285f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 286f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 287f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic int nfcmrvl_probe(struct usb_interface *intf, 288f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar const struct usb_device_id *id) 289f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 290f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct usb_endpoint_descriptor *ep_desc; 291f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data; 292f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_private *priv; 293f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int i; 294f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct usb_device *udev = interface_to_usbdev(intf); 295f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 296f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfc_info(&udev->dev, "intf %p id %p", intf, id); 297f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 298f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data = devm_kzalloc(&intf->dev, sizeof(*drv_data), GFP_KERNEL); 299f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!drv_data) 300f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return -ENOMEM; 301f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 302f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { 303f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar ep_desc = &intf->cur_altsetting->endpoint[i].desc; 304f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 305f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!drv_data->bulk_tx_ep && 306f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_endpoint_is_bulk_out(ep_desc)) { 307f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->bulk_tx_ep = ep_desc; 308f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar continue; 309f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 310f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 311f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!drv_data->bulk_rx_ep && 312f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_endpoint_is_bulk_in(ep_desc)) { 313f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->bulk_rx_ep = ep_desc; 314f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar continue; 315f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 316f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 317f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 318f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!drv_data->bulk_tx_ep || !drv_data->bulk_rx_ep) 319f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return -ENODEV; 320f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 321f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->udev = udev; 322f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->intf = intf; 323f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 324f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar INIT_WORK(&drv_data->waker, nfcmrvl_waker); 325f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_lock_init(&drv_data->txlock); 326f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 327f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar init_usb_anchor(&drv_data->tx_anchor); 328f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar init_usb_anchor(&drv_data->bulk_anchor); 329f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar init_usb_anchor(&drv_data->deferred); 330f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 331f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops, 332f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar &drv_data->udev->dev); 333f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (IS_ERR(priv)) 334f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return PTR_ERR(priv); 335f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 336f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->priv = priv; 337f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar priv->dev = &drv_data->udev->dev; 338f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 339f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_set_intfdata(intf, drv_data); 340f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 341f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return 0; 342f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 343f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 344f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic void nfcmrvl_disconnect(struct usb_interface *intf) 345f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 346f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf); 347f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 348f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!drv_data) 349f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return; 350f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 351f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfc_info(&drv_data->udev->dev, "intf %p", intf); 352f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 353f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfcmrvl_nci_unregister_dev(drv_data->priv); 354f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 355f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_set_intfdata(drv_data->intf, NULL); 356f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 357f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 358f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#ifdef CONFIG_PM 359f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic int nfcmrvl_suspend(struct usb_interface *intf, pm_message_t message) 360f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 361f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf); 362f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 363f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfc_info(&drv_data->udev->dev, "intf %p", intf); 364f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 365f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (drv_data->suspend_count++) 366f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return 0; 367f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 368f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_lock_irq(&drv_data->txlock); 369f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!(PMSG_IS_AUTO(message) && drv_data->tx_in_flight)) { 370f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar set_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags); 371f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_unlock_irq(&drv_data->txlock); 372f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } else { 373f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_unlock_irq(&drv_data->txlock); 374f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->suspend_count--; 375f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return -EBUSY; 376f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 377f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 378f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfcmrvl_usb_stop_traffic(drv_data); 379f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_kill_anchored_urbs(&drv_data->tx_anchor); 380f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 381f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return 0; 382f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 383f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 384f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic void nfcmrvl_play_deferred(struct nfcmrvl_usb_drv_data *drv_data) 385f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 386f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct urb *urb; 387f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int err; 388f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 389f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar while ((urb = usb_get_from_anchor(&drv_data->deferred))) { 390f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = usb_submit_urb(urb, GFP_ATOMIC); 391f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) 392f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar break; 393f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 394f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar drv_data->tx_in_flight++; 395f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 396f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_scuttle_anchored_urbs(&drv_data->deferred); 397f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 398f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 399f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic int nfcmrvl_resume(struct usb_interface *intf) 400f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar{ 401f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf); 402f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar int err = 0; 403f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 404f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfc_info(&drv_data->udev->dev, "intf %p", intf); 405f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 406f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (--drv_data->suspend_count) 407f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return 0; 408f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 409f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags)) 410f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar goto done; 411f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 412f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags)) { 413f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar err = nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO); 414f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar if (err) { 415f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags); 416f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar goto failed; 417f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 418f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 419f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO); 420f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar } 421f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 422f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_lock_irq(&drv_data->txlock); 423f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar nfcmrvl_play_deferred(drv_data); 424f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags); 425f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_unlock_irq(&drv_data->txlock); 426f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 427f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return 0; 428f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 429f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarfailed: 430f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar usb_scuttle_anchored_urbs(&drv_data->deferred); 431f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwardone: 432f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_lock_irq(&drv_data->txlock); 433f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags); 434f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar spin_unlock_irq(&drv_data->txlock); 435f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 436f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar return err; 437f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar} 438f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#endif 439f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 440f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarstatic struct usb_driver nfcmrvl_usb_driver = { 441f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .name = "nfcmrvl", 442f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .probe = nfcmrvl_probe, 443f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .disconnect = nfcmrvl_disconnect, 444f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#ifdef CONFIG_PM 445f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .suspend = nfcmrvl_suspend, 446f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .resume = nfcmrvl_resume, 447f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .reset_resume = nfcmrvl_resume, 448f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar#endif 449f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .id_table = nfcmrvl_table, 450f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .supports_autosuspend = 1, 451f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .disable_hub_initiated_lpm = 1, 452f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar .soft_unbind = 1, 453f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar}; 454f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwarmodule_usb_driver(nfcmrvl_usb_driver); 455f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar Karwar 456f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar KarwarMODULE_AUTHOR("Marvell International Ltd."); 457f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar KarwarMODULE_DESCRIPTION("Marvell NFC-over-USB driver ver " VERSION); 458f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar KarwarMODULE_VERSION(VERSION); 459f26e30cc6b50ba81e30ca3016c29ad4b48b93eaaAmitkumar KarwarMODULE_LICENSE("GPL v2"); 460