linux/drivers/net/usb/cdc-phonet.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * phonet.c -- USB CDC Phonet host driver
   4 *
   5 * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved.
   6 *
   7 * Author: RĂ©mi Denis-Courmont
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/mm.h>
  12#include <linux/module.h>
  13#include <linux/gfp.h>
  14#include <linux/usb.h>
  15#include <linux/usb/cdc.h>
  16#include <linux/netdevice.h>
  17#include <linux/if_arp.h>
  18#include <linux/if_phonet.h>
  19#include <linux/phonet.h>
  20
  21#define PN_MEDIA_USB    0x1B
  22
  23static const unsigned rxq_size = 17;
  24
  25struct usbpn_dev {
  26        struct net_device       *dev;
  27
  28        struct usb_interface    *intf, *data_intf;
  29        struct usb_device       *usb;
  30        unsigned int            tx_pipe, rx_pipe;
  31        u8 active_setting;
  32        u8 disconnected;
  33
  34        unsigned                tx_queue;
  35        spinlock_t              tx_lock;
  36
  37        spinlock_t              rx_lock;
  38        struct sk_buff          *rx_skb;
  39        struct urb              *urbs[0];
  40};
  41
  42static void tx_complete(struct urb *req);
  43static void rx_complete(struct urb *req);
  44
  45/*
  46 * Network device callbacks
  47 */
  48static netdev_tx_t usbpn_xmit(struct sk_buff *skb, struct net_device *dev)
  49{
  50        struct usbpn_dev *pnd = netdev_priv(dev);
  51        struct urb *req = NULL;
  52        unsigned long flags;
  53        int err;
  54
  55        if (skb->protocol != htons(ETH_P_PHONET))
  56                goto drop;
  57
  58        req = usb_alloc_urb(0, GFP_ATOMIC);
  59        if (!req)
  60                goto drop;
  61        usb_fill_bulk_urb(req, pnd->usb, pnd->tx_pipe, skb->data, skb->len,
  62                                tx_complete, skb);
  63        req->transfer_flags = URB_ZERO_PACKET;
  64        err = usb_submit_urb(req, GFP_ATOMIC);
  65        if (err) {
  66                usb_free_urb(req);
  67                goto drop;
  68        }
  69
  70        spin_lock_irqsave(&pnd->tx_lock, flags);
  71        pnd->tx_queue++;
  72        if (pnd->tx_queue >= dev->tx_queue_len)
  73                netif_stop_queue(dev);
  74        spin_unlock_irqrestore(&pnd->tx_lock, flags);
  75        return NETDEV_TX_OK;
  76
  77drop:
  78        dev_kfree_skb(skb);
  79        dev->stats.tx_dropped++;
  80        return NETDEV_TX_OK;
  81}
  82
  83static void tx_complete(struct urb *req)
  84{
  85        struct sk_buff *skb = req->context;
  86        struct net_device *dev = skb->dev;
  87        struct usbpn_dev *pnd = netdev_priv(dev);
  88        int status = req->status;
  89        unsigned long flags;
  90
  91        switch (status) {
  92        case 0:
  93                dev->stats.tx_bytes += skb->len;
  94                break;
  95
  96        case -ENOENT:
  97        case -ECONNRESET:
  98        case -ESHUTDOWN:
  99                dev->stats.tx_aborted_errors++;
 100                /* fall through */
 101        default:
 102                dev->stats.tx_errors++;
 103                dev_dbg(&dev->dev, "TX error (%d)\n", status);
 104        }
 105        dev->stats.tx_packets++;
 106
 107        spin_lock_irqsave(&pnd->tx_lock, flags);
 108        pnd->tx_queue--;
 109        netif_wake_queue(dev);
 110        spin_unlock_irqrestore(&pnd->tx_lock, flags);
 111
 112        dev_kfree_skb_any(skb);
 113        usb_free_urb(req);
 114}
 115
 116static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags)
 117{
 118        struct net_device *dev = pnd->dev;
 119        struct page *page;
 120        int err;
 121
 122        page = __dev_alloc_page(gfp_flags | __GFP_NOMEMALLOC);
 123        if (!page)
 124                return -ENOMEM;
 125
 126        usb_fill_bulk_urb(req, pnd->usb, pnd->rx_pipe, page_address(page),
 127                                PAGE_SIZE, rx_complete, dev);
 128        req->transfer_flags = 0;
 129        err = usb_submit_urb(req, gfp_flags);
 130        if (unlikely(err)) {
 131                dev_dbg(&dev->dev, "RX submit error (%d)\n", err);
 132                put_page(page);
 133        }
 134        return err;
 135}
 136
 137static void rx_complete(struct urb *req)
 138{
 139        struct net_device *dev = req->context;
 140        struct usbpn_dev *pnd = netdev_priv(dev);
 141        struct page *page = virt_to_page(req->transfer_buffer);
 142        struct sk_buff *skb;
 143        unsigned long flags;
 144        int status = req->status;
 145
 146        switch (status) {
 147        case 0:
 148                spin_lock_irqsave(&pnd->rx_lock, flags);
 149                skb = pnd->rx_skb;
 150                if (!skb) {
 151                        skb = pnd->rx_skb = netdev_alloc_skb(dev, 12);
 152                        if (likely(skb)) {
 153                                /* Can't use pskb_pull() on page in IRQ */
 154                                skb_put_data(skb, page_address(page), 1);
 155                                skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
 156                                                page, 1, req->actual_length,
 157                                                PAGE_SIZE);
 158                                page = NULL;
 159                        }
 160                } else {
 161                        skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
 162                                        page, 0, req->actual_length,
 163                                        PAGE_SIZE);
 164                        page = NULL;
 165                }
 166                if (req->actual_length < PAGE_SIZE)
 167                        pnd->rx_skb = NULL; /* Last fragment */
 168                else
 169                        skb = NULL;
 170                spin_unlock_irqrestore(&pnd->rx_lock, flags);
 171                if (skb) {
 172                        skb->protocol = htons(ETH_P_PHONET);
 173                        skb_reset_mac_header(skb);
 174                        __skb_pull(skb, 1);
 175                        skb->dev = dev;
 176                        dev->stats.rx_packets++;
 177                        dev->stats.rx_bytes += skb->len;
 178
 179                        netif_rx(skb);
 180                }
 181                goto resubmit;
 182
 183        case -ENOENT:
 184        case -ECONNRESET:
 185        case -ESHUTDOWN:
 186                req = NULL;
 187                break;
 188
 189        case -EOVERFLOW:
 190                dev->stats.rx_over_errors++;
 191                dev_dbg(&dev->dev, "RX overflow\n");
 192                break;
 193
 194        case -EILSEQ:
 195                dev->stats.rx_crc_errors++;
 196                break;
 197        }
 198
 199        dev->stats.rx_errors++;
 200resubmit:
 201        if (page)
 202                put_page(page);
 203        if (req)
 204                rx_submit(pnd, req, GFP_ATOMIC);
 205}
 206
 207static int usbpn_close(struct net_device *dev);
 208
 209static int usbpn_open(struct net_device *dev)
 210{
 211        struct usbpn_dev *pnd = netdev_priv(dev);
 212        int err;
 213        unsigned i;
 214        unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
 215
 216        err = usb_set_interface(pnd->usb, num, pnd->active_setting);
 217        if (err)
 218                return err;
 219
 220        for (i = 0; i < rxq_size; i++) {
 221                struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
 222
 223                if (!req || rx_submit(pnd, req, GFP_KERNEL)) {
 224                        usb_free_urb(req);
 225                        usbpn_close(dev);
 226                        return -ENOMEM;
 227                }
 228                pnd->urbs[i] = req;
 229        }
 230
 231        netif_wake_queue(dev);
 232        return 0;
 233}
 234
 235static int usbpn_close(struct net_device *dev)
 236{
 237        struct usbpn_dev *pnd = netdev_priv(dev);
 238        unsigned i;
 239        unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
 240
 241        netif_stop_queue(dev);
 242
 243        for (i = 0; i < rxq_size; i++) {
 244                struct urb *req = pnd->urbs[i];
 245
 246                if (!req)
 247                        continue;
 248                usb_kill_urb(req);
 249                usb_free_urb(req);
 250                pnd->urbs[i] = NULL;
 251        }
 252
 253        return usb_set_interface(pnd->usb, num, !pnd->active_setting);
 254}
 255
 256static int usbpn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 257{
 258        struct if_phonet_req *req = (struct if_phonet_req *)ifr;
 259
 260        switch (cmd) {
 261        case SIOCPNGAUTOCONF:
 262                req->ifr_phonet_autoconf.device = PN_DEV_PC;
 263                return 0;
 264        }
 265        return -ENOIOCTLCMD;
 266}
 267
 268static const struct net_device_ops usbpn_ops = {
 269        .ndo_open       = usbpn_open,
 270        .ndo_stop       = usbpn_close,
 271        .ndo_start_xmit = usbpn_xmit,
 272        .ndo_do_ioctl   = usbpn_ioctl,
 273};
 274
 275static void usbpn_setup(struct net_device *dev)
 276{
 277        dev->features           = 0;
 278        dev->netdev_ops         = &usbpn_ops,
 279        dev->header_ops         = &phonet_header_ops;
 280        dev->type               = ARPHRD_PHONET;
 281        dev->flags              = IFF_POINTOPOINT | IFF_NOARP;
 282        dev->mtu                = PHONET_MAX_MTU;
 283        dev->min_mtu            = PHONET_MIN_MTU;
 284        dev->max_mtu            = PHONET_MAX_MTU;
 285        dev->hard_header_len    = 1;
 286        dev->dev_addr[0]        = PN_MEDIA_USB;
 287        dev->addr_len           = 1;
 288        dev->tx_queue_len       = 3;
 289
 290        dev->needs_free_netdev  = true;
 291}
 292
 293/*
 294 * USB driver callbacks
 295 */
 296static const struct usb_device_id usbpn_ids[] = {
 297        {
 298                .match_flags = USB_DEVICE_ID_MATCH_VENDOR
 299                        | USB_DEVICE_ID_MATCH_INT_CLASS
 300                        | USB_DEVICE_ID_MATCH_INT_SUBCLASS,
 301                .idVendor = 0x0421, /* Nokia */
 302                .bInterfaceClass = USB_CLASS_COMM,
 303                .bInterfaceSubClass = 0xFE,
 304        },
 305        { },
 306};
 307
 308MODULE_DEVICE_TABLE(usb, usbpn_ids);
 309
 310static struct usb_driver usbpn_driver;
 311
 312static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
 313{
 314        static const char ifname[] = "usbpn%d";
 315        const struct usb_cdc_union_desc *union_header = NULL;
 316        const struct usb_host_interface *data_desc;
 317        struct usb_interface *data_intf;
 318        struct usb_device *usbdev = interface_to_usbdev(intf);
 319        struct net_device *dev;
 320        struct usbpn_dev *pnd;
 321        u8 *data;
 322        int phonet = 0;
 323        int len, err;
 324        struct usb_cdc_parsed_header hdr;
 325
 326        data = intf->altsetting->extra;
 327        len = intf->altsetting->extralen;
 328        cdc_parse_cdc_header(&hdr, intf, data, len);
 329        union_header = hdr.usb_cdc_union_desc;
 330        phonet = hdr.phonet_magic_present;
 331
 332        if (!union_header || !phonet)
 333                return -EINVAL;
 334
 335        data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0);
 336        if (data_intf == NULL)
 337                return -ENODEV;
 338        /* Data interface has one inactive and one active setting */
 339        if (data_intf->num_altsetting != 2)
 340                return -EINVAL;
 341        if (data_intf->altsetting[0].desc.bNumEndpoints == 0 &&
 342            data_intf->altsetting[1].desc.bNumEndpoints == 2)
 343                data_desc = data_intf->altsetting + 1;
 344        else
 345        if (data_intf->altsetting[0].desc.bNumEndpoints == 2 &&
 346            data_intf->altsetting[1].desc.bNumEndpoints == 0)
 347                data_desc = data_intf->altsetting;
 348        else
 349                return -EINVAL;
 350
 351        dev = alloc_netdev(struct_size(pnd, urbs, rxq_size), ifname,
 352                           NET_NAME_UNKNOWN, usbpn_setup);
 353        if (!dev)
 354                return -ENOMEM;
 355
 356        pnd = netdev_priv(dev);
 357        SET_NETDEV_DEV(dev, &intf->dev);
 358
 359        pnd->dev = dev;
 360        pnd->usb = usbdev;
 361        pnd->intf = intf;
 362        pnd->data_intf = data_intf;
 363        spin_lock_init(&pnd->tx_lock);
 364        spin_lock_init(&pnd->rx_lock);
 365        /* Endpoints */
 366        if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) {
 367                pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
 368                        data_desc->endpoint[0].desc.bEndpointAddress);
 369                pnd->tx_pipe = usb_sndbulkpipe(usbdev,
 370                        data_desc->endpoint[1].desc.bEndpointAddress);
 371        } else {
 372                pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
 373                        data_desc->endpoint[1].desc.bEndpointAddress);
 374                pnd->tx_pipe = usb_sndbulkpipe(usbdev,
 375                        data_desc->endpoint[0].desc.bEndpointAddress);
 376        }
 377        pnd->active_setting = data_desc - data_intf->altsetting;
 378
 379        err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd);
 380        if (err)
 381                goto out;
 382
 383        /* Force inactive mode until the network device is brought UP */
 384        usb_set_interface(usbdev, union_header->bSlaveInterface0,
 385                                !pnd->active_setting);
 386        usb_set_intfdata(intf, pnd);
 387
 388        err = register_netdev(dev);
 389        if (err) {
 390                usb_driver_release_interface(&usbpn_driver, data_intf);
 391                goto out;
 392        }
 393
 394        dev_dbg(&dev->dev, "USB CDC Phonet device found\n");
 395        return 0;
 396
 397out:
 398        usb_set_intfdata(intf, NULL);
 399        free_netdev(dev);
 400        return err;
 401}
 402
 403static void usbpn_disconnect(struct usb_interface *intf)
 404{
 405        struct usbpn_dev *pnd = usb_get_intfdata(intf);
 406
 407        if (pnd->disconnected)
 408                return;
 409
 410        pnd->disconnected = 1;
 411        usb_driver_release_interface(&usbpn_driver,
 412                        (pnd->intf == intf) ? pnd->data_intf : pnd->intf);
 413        unregister_netdev(pnd->dev);
 414}
 415
 416static struct usb_driver usbpn_driver = {
 417        .name =         "cdc_phonet",
 418        .probe =        usbpn_probe,
 419        .disconnect =   usbpn_disconnect,
 420        .id_table =     usbpn_ids,
 421        .disable_hub_initiated_lpm = 1,
 422};
 423
 424module_usb_driver(usbpn_driver);
 425
 426MODULE_AUTHOR("Remi Denis-Courmont");
 427MODULE_DESCRIPTION("USB CDC Phonet host interface");
 428MODULE_LICENSE("GPL");
 429