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[];
  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                fallthrough;
 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_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
 257                                void __user *data, int cmd)
 258{
 259        struct if_phonet_req *req = (struct if_phonet_req *)ifr;
 260
 261        switch (cmd) {
 262        case SIOCPNGAUTOCONF:
 263                req->ifr_phonet_autoconf.device = PN_DEV_PC;
 264                return 0;
 265        }
 266        return -ENOIOCTLCMD;
 267}
 268
 269static const struct net_device_ops usbpn_ops = {
 270        .ndo_open       = usbpn_open,
 271        .ndo_stop       = usbpn_close,
 272        .ndo_start_xmit = usbpn_xmit,
 273        .ndo_siocdevprivate = usbpn_siocdevprivate,
 274};
 275
 276static void usbpn_setup(struct net_device *dev)
 277{
 278        dev->features           = 0;
 279        dev->netdev_ops         = &usbpn_ops;
 280        dev->header_ops         = &phonet_header_ops;
 281        dev->type               = ARPHRD_PHONET;
 282        dev->flags              = IFF_POINTOPOINT | IFF_NOARP;
 283        dev->mtu                = PHONET_MAX_MTU;
 284        dev->min_mtu            = PHONET_MIN_MTU;
 285        dev->max_mtu            = PHONET_MAX_MTU;
 286        dev->hard_header_len    = 1;
 287        dev->dev_addr[0]        = PN_MEDIA_USB;
 288        dev->addr_len           = 1;
 289        dev->tx_queue_len       = 3;
 290
 291        dev->needs_free_netdev  = true;
 292}
 293
 294/*
 295 * USB driver callbacks
 296 */
 297static const struct usb_device_id usbpn_ids[] = {
 298        {
 299                .match_flags = USB_DEVICE_ID_MATCH_VENDOR
 300                        | USB_DEVICE_ID_MATCH_INT_CLASS
 301                        | USB_DEVICE_ID_MATCH_INT_SUBCLASS,
 302                .idVendor = 0x0421, /* Nokia */
 303                .bInterfaceClass = USB_CLASS_COMM,
 304                .bInterfaceSubClass = 0xFE,
 305        },
 306        { },
 307};
 308
 309MODULE_DEVICE_TABLE(usb, usbpn_ids);
 310
 311static struct usb_driver usbpn_driver;
 312
 313static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
 314{
 315        static const char ifname[] = "usbpn%d";
 316        const struct usb_cdc_union_desc *union_header = NULL;
 317        const struct usb_host_interface *data_desc;
 318        struct usb_interface *data_intf;
 319        struct usb_device *usbdev = interface_to_usbdev(intf);
 320        struct net_device *dev;
 321        struct usbpn_dev *pnd;
 322        u8 *data;
 323        int phonet = 0;
 324        int len, err;
 325        struct usb_cdc_parsed_header hdr;
 326
 327        data = intf->altsetting->extra;
 328        len = intf->altsetting->extralen;
 329        cdc_parse_cdc_header(&hdr, intf, data, len);
 330        union_header = hdr.usb_cdc_union_desc;
 331        phonet = hdr.phonet_magic_present;
 332
 333        if (!union_header || !phonet)
 334                return -EINVAL;
 335
 336        data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0);
 337        if (data_intf == NULL)
 338                return -ENODEV;
 339        /* Data interface has one inactive and one active setting */
 340        if (data_intf->num_altsetting != 2)
 341                return -EINVAL;
 342        if (data_intf->altsetting[0].desc.bNumEndpoints == 0 &&
 343            data_intf->altsetting[1].desc.bNumEndpoints == 2)
 344                data_desc = data_intf->altsetting + 1;
 345        else
 346        if (data_intf->altsetting[0].desc.bNumEndpoints == 2 &&
 347            data_intf->altsetting[1].desc.bNumEndpoints == 0)
 348                data_desc = data_intf->altsetting;
 349        else
 350                return -EINVAL;
 351
 352        dev = alloc_netdev(struct_size(pnd, urbs, rxq_size), ifname,
 353                           NET_NAME_UNKNOWN, usbpn_setup);
 354        if (!dev)
 355                return -ENOMEM;
 356
 357        pnd = netdev_priv(dev);
 358        SET_NETDEV_DEV(dev, &intf->dev);
 359
 360        pnd->dev = dev;
 361        pnd->usb = usbdev;
 362        pnd->intf = intf;
 363        pnd->data_intf = data_intf;
 364        spin_lock_init(&pnd->tx_lock);
 365        spin_lock_init(&pnd->rx_lock);
 366        /* Endpoints */
 367        if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) {
 368                pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
 369                        data_desc->endpoint[0].desc.bEndpointAddress);
 370                pnd->tx_pipe = usb_sndbulkpipe(usbdev,
 371                        data_desc->endpoint[1].desc.bEndpointAddress);
 372        } else {
 373                pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
 374                        data_desc->endpoint[1].desc.bEndpointAddress);
 375                pnd->tx_pipe = usb_sndbulkpipe(usbdev,
 376                        data_desc->endpoint[0].desc.bEndpointAddress);
 377        }
 378        pnd->active_setting = data_desc - data_intf->altsetting;
 379
 380        err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd);
 381        if (err)
 382                goto out;
 383
 384        /* Force inactive mode until the network device is brought UP */
 385        usb_set_interface(usbdev, union_header->bSlaveInterface0,
 386                                !pnd->active_setting);
 387        usb_set_intfdata(intf, pnd);
 388
 389        err = register_netdev(dev);
 390        if (err) {
 391                /* Set disconnected flag so that disconnect() returns early. */
 392                pnd->disconnected = 1;
 393                usb_driver_release_interface(&usbpn_driver, data_intf);
 394                goto out;
 395        }
 396
 397        dev_dbg(&dev->dev, "USB CDC Phonet device found\n");
 398        return 0;
 399
 400out:
 401        usb_set_intfdata(intf, NULL);
 402        free_netdev(dev);
 403        return err;
 404}
 405
 406static void usbpn_disconnect(struct usb_interface *intf)
 407{
 408        struct usbpn_dev *pnd = usb_get_intfdata(intf);
 409
 410        if (pnd->disconnected)
 411                return;
 412
 413        pnd->disconnected = 1;
 414        usb_driver_release_interface(&usbpn_driver,
 415                        (pnd->intf == intf) ? pnd->data_intf : pnd->intf);
 416        unregister_netdev(pnd->dev);
 417}
 418
 419static struct usb_driver usbpn_driver = {
 420        .name =         "cdc_phonet",
 421        .probe =        usbpn_probe,
 422        .disconnect =   usbpn_disconnect,
 423        .id_table =     usbpn_ids,
 424        .disable_hub_initiated_lpm = 1,
 425};
 426
 427module_usb_driver(usbpn_driver);
 428
 429MODULE_AUTHOR("Remi Denis-Courmont");
 430MODULE_DESCRIPTION("USB CDC Phonet host interface");
 431MODULE_LICENSE("GPL");
 432