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