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