Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * ipheth.c - Apple iPhone USB Ethernet driver
0003  *
0004  * Copyright (c) 2009 Diego Giagio <diego@giagio.com>
0005  * All rights reserved.
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  * 1. Redistributions of source code must retain the above copyright
0011  *    notice, this list of conditions and the following disclaimer.
0012  * 2. Redistributions in binary form must reproduce the above copyright
0013  *    notice, this list of conditions and the following disclaimer in the
0014  *    documentation and/or other materials provided with the distribution.
0015  * 3. Neither the name of GIAGIO.COM nor the names of its contributors
0016  *    may be used to endorse or promote products derived from this software
0017  *    without specific prior written permission.
0018  *
0019  * Alternatively, provided that this notice is retained in full, this
0020  * software may be distributed under the terms of the GNU General
0021  * Public License ("GPL") version 2, in which case the provisions of the
0022  * GPL apply INSTEAD OF those given above.
0023  *
0024  * The provided data structures and external interfaces from this code
0025  * are not restricted to be used by modules with a GPL compatible license.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0028  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0029  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0030  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0031  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0032  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0033  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0034  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0035  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0036  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0037  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
0038  * DAMAGE.
0039  *
0040  *
0041  * Attention: iPhone device must be paired, otherwise it won't respond to our
0042  * driver. For more info: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver
0043  *
0044  */
0045 
0046 #include <linux/kernel.h>
0047 #include <linux/errno.h>
0048 #include <linux/slab.h>
0049 #include <linux/module.h>
0050 #include <linux/netdevice.h>
0051 #include <linux/etherdevice.h>
0052 #include <linux/ethtool.h>
0053 #include <linux/usb.h>
0054 #include <linux/workqueue.h>
0055 
0056 #define USB_VENDOR_APPLE        0x05ac
0057 
0058 #define IPHETH_USBINTF_CLASS    255
0059 #define IPHETH_USBINTF_SUBCLASS 253
0060 #define IPHETH_USBINTF_PROTO    1
0061 
0062 #define IPHETH_BUF_SIZE         1514
0063 #define IPHETH_IP_ALIGN     2   /* padding at front of URB */
0064 #define IPHETH_TX_TIMEOUT       (5 * HZ)
0065 
0066 #define IPHETH_INTFNUM          2
0067 #define IPHETH_ALT_INTFNUM      1
0068 
0069 #define IPHETH_CTRL_ENDP        0x00
0070 #define IPHETH_CTRL_BUF_SIZE    0x40
0071 #define IPHETH_CTRL_TIMEOUT     (5 * HZ)
0072 
0073 #define IPHETH_CMD_GET_MACADDR   0x00
0074 #define IPHETH_CMD_CARRIER_CHECK 0x45
0075 
0076 #define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ)
0077 #define IPHETH_CARRIER_ON       0x04
0078 
0079 static const struct usb_device_id ipheth_table[] = {
0080     { USB_VENDOR_AND_INTERFACE_INFO(USB_VENDOR_APPLE, IPHETH_USBINTF_CLASS,
0081                     IPHETH_USBINTF_SUBCLASS,
0082                     IPHETH_USBINTF_PROTO) },
0083     { }
0084 };
0085 MODULE_DEVICE_TABLE(usb, ipheth_table);
0086 
0087 struct ipheth_device {
0088     struct usb_device *udev;
0089     struct usb_interface *intf;
0090     struct net_device *net;
0091     struct urb *tx_urb;
0092     struct urb *rx_urb;
0093     unsigned char *tx_buf;
0094     unsigned char *rx_buf;
0095     unsigned char *ctrl_buf;
0096     u8 bulk_in;
0097     u8 bulk_out;
0098     struct delayed_work carrier_work;
0099     bool confirmed_pairing;
0100 };
0101 
0102 static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags);
0103 
0104 static int ipheth_alloc_urbs(struct ipheth_device *iphone)
0105 {
0106     struct urb *tx_urb = NULL;
0107     struct urb *rx_urb = NULL;
0108     u8 *tx_buf = NULL;
0109     u8 *rx_buf = NULL;
0110 
0111     tx_urb = usb_alloc_urb(0, GFP_KERNEL);
0112     if (tx_urb == NULL)
0113         goto error_nomem;
0114 
0115     rx_urb = usb_alloc_urb(0, GFP_KERNEL);
0116     if (rx_urb == NULL)
0117         goto free_tx_urb;
0118 
0119     tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
0120                     GFP_KERNEL, &tx_urb->transfer_dma);
0121     if (tx_buf == NULL)
0122         goto free_rx_urb;
0123 
0124     rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
0125                     GFP_KERNEL, &rx_urb->transfer_dma);
0126     if (rx_buf == NULL)
0127         goto free_tx_buf;
0128 
0129 
0130     iphone->tx_urb = tx_urb;
0131     iphone->rx_urb = rx_urb;
0132     iphone->tx_buf = tx_buf;
0133     iphone->rx_buf = rx_buf;
0134     return 0;
0135 
0136 free_tx_buf:
0137     usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
0138               tx_urb->transfer_dma);
0139 free_rx_urb:
0140     usb_free_urb(rx_urb);
0141 free_tx_urb:
0142     usb_free_urb(tx_urb);
0143 error_nomem:
0144     return -ENOMEM;
0145 }
0146 
0147 static void ipheth_free_urbs(struct ipheth_device *iphone)
0148 {
0149     usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf,
0150               iphone->rx_urb->transfer_dma);
0151     usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
0152               iphone->tx_urb->transfer_dma);
0153     usb_free_urb(iphone->rx_urb);
0154     usb_free_urb(iphone->tx_urb);
0155 }
0156 
0157 static void ipheth_kill_urbs(struct ipheth_device *dev)
0158 {
0159     usb_kill_urb(dev->tx_urb);
0160     usb_kill_urb(dev->rx_urb);
0161 }
0162 
0163 static void ipheth_rcvbulk_callback(struct urb *urb)
0164 {
0165     struct ipheth_device *dev;
0166     struct sk_buff *skb;
0167     int status;
0168     char *buf;
0169     int len;
0170 
0171     dev = urb->context;
0172     if (dev == NULL)
0173         return;
0174 
0175     status = urb->status;
0176     switch (status) {
0177     case -ENOENT:
0178     case -ECONNRESET:
0179     case -ESHUTDOWN:
0180     case -EPROTO:
0181         return;
0182     case 0:
0183         break;
0184     default:
0185         dev_err(&dev->intf->dev, "%s: urb status: %d\n",
0186             __func__, status);
0187         return;
0188     }
0189 
0190     if (urb->actual_length <= IPHETH_IP_ALIGN) {
0191         dev->net->stats.rx_length_errors++;
0192         return;
0193     }
0194     len = urb->actual_length - IPHETH_IP_ALIGN;
0195     buf = urb->transfer_buffer + IPHETH_IP_ALIGN;
0196 
0197     skb = dev_alloc_skb(len);
0198     if (!skb) {
0199         dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n",
0200             __func__);
0201         dev->net->stats.rx_dropped++;
0202         return;
0203     }
0204 
0205     skb_put_data(skb, buf, len);
0206     skb->dev = dev->net;
0207     skb->protocol = eth_type_trans(skb, dev->net);
0208 
0209     dev->net->stats.rx_packets++;
0210     dev->net->stats.rx_bytes += len;
0211     dev->confirmed_pairing = true;
0212     netif_rx(skb);
0213     ipheth_rx_submit(dev, GFP_ATOMIC);
0214 }
0215 
0216 static void ipheth_sndbulk_callback(struct urb *urb)
0217 {
0218     struct ipheth_device *dev;
0219     int status = urb->status;
0220 
0221     dev = urb->context;
0222     if (dev == NULL)
0223         return;
0224 
0225     if (status != 0 &&
0226         status != -ENOENT &&
0227         status != -ECONNRESET &&
0228         status != -ESHUTDOWN)
0229         dev_err(&dev->intf->dev, "%s: urb status: %d\n",
0230         __func__, status);
0231 
0232     if (status == 0)
0233         netif_wake_queue(dev->net);
0234     else
0235         // on URB error, trigger immediate poll
0236         schedule_delayed_work(&dev->carrier_work, 0);
0237 }
0238 
0239 static int ipheth_carrier_set(struct ipheth_device *dev)
0240 {
0241     struct usb_device *udev;
0242     int retval;
0243 
0244     if (!dev->confirmed_pairing)
0245         return 0;
0246 
0247     udev = dev->udev;
0248     retval = usb_control_msg(udev,
0249             usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
0250             IPHETH_CMD_CARRIER_CHECK, /* request */
0251             0xc0, /* request type */
0252             0x00, /* value */
0253             0x02, /* index */
0254             dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE,
0255             IPHETH_CTRL_TIMEOUT);
0256     if (retval < 0) {
0257         dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
0258             __func__, retval);
0259         return retval;
0260     }
0261 
0262     if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) {
0263         netif_carrier_on(dev->net);
0264         if (dev->tx_urb->status != -EINPROGRESS)
0265             netif_wake_queue(dev->net);
0266     } else {
0267         netif_carrier_off(dev->net);
0268         netif_stop_queue(dev->net);
0269     }
0270     return 0;
0271 }
0272 
0273 static void ipheth_carrier_check_work(struct work_struct *work)
0274 {
0275     struct ipheth_device *dev = container_of(work, struct ipheth_device,
0276                          carrier_work.work);
0277 
0278     ipheth_carrier_set(dev);
0279     schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
0280 }
0281 
0282 static int ipheth_get_macaddr(struct ipheth_device *dev)
0283 {
0284     struct usb_device *udev = dev->udev;
0285     struct net_device *net = dev->net;
0286     int retval;
0287 
0288     retval = usb_control_msg(udev,
0289                  usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
0290                  IPHETH_CMD_GET_MACADDR, /* request */
0291                  0xc0, /* request type */
0292                  0x00, /* value */
0293                  0x02, /* index */
0294                  dev->ctrl_buf,
0295                  IPHETH_CTRL_BUF_SIZE,
0296                  IPHETH_CTRL_TIMEOUT);
0297     if (retval < 0) {
0298         dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
0299             __func__, retval);
0300     } else if (retval < ETH_ALEN) {
0301         dev_err(&dev->intf->dev,
0302             "%s: usb_control_msg: short packet: %d bytes\n",
0303             __func__, retval);
0304         retval = -EINVAL;
0305     } else {
0306         eth_hw_addr_set(net, dev->ctrl_buf);
0307         retval = 0;
0308     }
0309 
0310     return retval;
0311 }
0312 
0313 static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
0314 {
0315     struct usb_device *udev = dev->udev;
0316     int retval;
0317 
0318     usb_fill_bulk_urb(dev->rx_urb, udev,
0319               usb_rcvbulkpipe(udev, dev->bulk_in),
0320               dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
0321               ipheth_rcvbulk_callback,
0322               dev);
0323     dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
0324 
0325     retval = usb_submit_urb(dev->rx_urb, mem_flags);
0326     if (retval)
0327         dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
0328             __func__, retval);
0329     return retval;
0330 }
0331 
0332 static int ipheth_open(struct net_device *net)
0333 {
0334     struct ipheth_device *dev = netdev_priv(net);
0335     struct usb_device *udev = dev->udev;
0336     int retval = 0;
0337 
0338     usb_set_interface(udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM);
0339 
0340     retval = ipheth_carrier_set(dev);
0341     if (retval)
0342         return retval;
0343 
0344     retval = ipheth_rx_submit(dev, GFP_KERNEL);
0345     if (retval)
0346         return retval;
0347 
0348     schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
0349     return retval;
0350 }
0351 
0352 static int ipheth_close(struct net_device *net)
0353 {
0354     struct ipheth_device *dev = netdev_priv(net);
0355 
0356     cancel_delayed_work_sync(&dev->carrier_work);
0357     netif_stop_queue(net);
0358     return 0;
0359 }
0360 
0361 static netdev_tx_t ipheth_tx(struct sk_buff *skb, struct net_device *net)
0362 {
0363     struct ipheth_device *dev = netdev_priv(net);
0364     struct usb_device *udev = dev->udev;
0365     int retval;
0366 
0367     /* Paranoid */
0368     if (skb->len > IPHETH_BUF_SIZE) {
0369         WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len);
0370         dev->net->stats.tx_dropped++;
0371         dev_kfree_skb_any(skb);
0372         return NETDEV_TX_OK;
0373     }
0374 
0375     memcpy(dev->tx_buf, skb->data, skb->len);
0376     if (skb->len < IPHETH_BUF_SIZE)
0377         memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len);
0378 
0379     usb_fill_bulk_urb(dev->tx_urb, udev,
0380               usb_sndbulkpipe(udev, dev->bulk_out),
0381               dev->tx_buf, IPHETH_BUF_SIZE,
0382               ipheth_sndbulk_callback,
0383               dev);
0384     dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
0385 
0386     netif_stop_queue(net);
0387     retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC);
0388     if (retval) {
0389         dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
0390             __func__, retval);
0391         dev->net->stats.tx_errors++;
0392         dev_kfree_skb_any(skb);
0393         netif_wake_queue(net);
0394     } else {
0395         dev->net->stats.tx_packets++;
0396         dev->net->stats.tx_bytes += skb->len;
0397         dev_consume_skb_any(skb);
0398     }
0399 
0400     return NETDEV_TX_OK;
0401 }
0402 
0403 static void ipheth_tx_timeout(struct net_device *net, unsigned int txqueue)
0404 {
0405     struct ipheth_device *dev = netdev_priv(net);
0406 
0407     dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__);
0408     dev->net->stats.tx_errors++;
0409     usb_unlink_urb(dev->tx_urb);
0410 }
0411 
0412 static u32 ipheth_ethtool_op_get_link(struct net_device *net)
0413 {
0414     struct ipheth_device *dev = netdev_priv(net);
0415     return netif_carrier_ok(dev->net);
0416 }
0417 
0418 static const struct ethtool_ops ops = {
0419     .get_link = ipheth_ethtool_op_get_link
0420 };
0421 
0422 static const struct net_device_ops ipheth_netdev_ops = {
0423     .ndo_open = ipheth_open,
0424     .ndo_stop = ipheth_close,
0425     .ndo_start_xmit = ipheth_tx,
0426     .ndo_tx_timeout = ipheth_tx_timeout,
0427 };
0428 
0429 static int ipheth_probe(struct usb_interface *intf,
0430             const struct usb_device_id *id)
0431 {
0432     struct usb_device *udev = interface_to_usbdev(intf);
0433     struct usb_host_interface *hintf;
0434     struct usb_endpoint_descriptor *endp;
0435     struct ipheth_device *dev;
0436     struct net_device *netdev;
0437     int i;
0438     int retval;
0439 
0440     netdev = alloc_etherdev(sizeof(struct ipheth_device));
0441     if (!netdev)
0442         return -ENOMEM;
0443 
0444     netdev->netdev_ops = &ipheth_netdev_ops;
0445     netdev->watchdog_timeo = IPHETH_TX_TIMEOUT;
0446     strscpy(netdev->name, "eth%d", sizeof(netdev->name));
0447 
0448     dev = netdev_priv(netdev);
0449     dev->udev = udev;
0450     dev->net = netdev;
0451     dev->intf = intf;
0452     dev->confirmed_pairing = false;
0453     /* Set up endpoints */
0454     hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
0455     if (hintf == NULL) {
0456         retval = -ENODEV;
0457         dev_err(&intf->dev, "Unable to find alternate settings interface\n");
0458         goto err_endpoints;
0459     }
0460 
0461     for (i = 0; i < hintf->desc.bNumEndpoints; i++) {
0462         endp = &hintf->endpoint[i].desc;
0463         if (usb_endpoint_is_bulk_in(endp))
0464             dev->bulk_in = endp->bEndpointAddress;
0465         else if (usb_endpoint_is_bulk_out(endp))
0466             dev->bulk_out = endp->bEndpointAddress;
0467     }
0468     if (!(dev->bulk_in && dev->bulk_out)) {
0469         retval = -ENODEV;
0470         dev_err(&intf->dev, "Unable to find endpoints\n");
0471         goto err_endpoints;
0472     }
0473 
0474     dev->ctrl_buf = kmalloc(IPHETH_CTRL_BUF_SIZE, GFP_KERNEL);
0475     if (dev->ctrl_buf == NULL) {
0476         retval = -ENOMEM;
0477         goto err_alloc_ctrl_buf;
0478     }
0479 
0480     retval = ipheth_get_macaddr(dev);
0481     if (retval)
0482         goto err_get_macaddr;
0483 
0484     INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work);
0485 
0486     retval = ipheth_alloc_urbs(dev);
0487     if (retval) {
0488         dev_err(&intf->dev, "error allocating urbs: %d\n", retval);
0489         goto err_alloc_urbs;
0490     }
0491 
0492     usb_set_intfdata(intf, dev);
0493 
0494     SET_NETDEV_DEV(netdev, &intf->dev);
0495     netdev->ethtool_ops = &ops;
0496 
0497     retval = register_netdev(netdev);
0498     if (retval) {
0499         dev_err(&intf->dev, "error registering netdev: %d\n", retval);
0500         retval = -EIO;
0501         goto err_register_netdev;
0502     }
0503     // carrier down and transmit queues stopped until packet from device
0504     netif_carrier_off(netdev);
0505     netif_tx_stop_all_queues(netdev);
0506     dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n");
0507     return 0;
0508 
0509 err_register_netdev:
0510     ipheth_free_urbs(dev);
0511 err_alloc_urbs:
0512 err_get_macaddr:
0513 err_alloc_ctrl_buf:
0514     kfree(dev->ctrl_buf);
0515 err_endpoints:
0516     free_netdev(netdev);
0517     return retval;
0518 }
0519 
0520 static void ipheth_disconnect(struct usb_interface *intf)
0521 {
0522     struct ipheth_device *dev;
0523 
0524     dev = usb_get_intfdata(intf);
0525     if (dev != NULL) {
0526         unregister_netdev(dev->net);
0527         ipheth_kill_urbs(dev);
0528         ipheth_free_urbs(dev);
0529         kfree(dev->ctrl_buf);
0530         free_netdev(dev->net);
0531     }
0532     usb_set_intfdata(intf, NULL);
0533     dev_info(&intf->dev, "Apple iPhone USB Ethernet now disconnected\n");
0534 }
0535 
0536 static struct usb_driver ipheth_driver = {
0537     .name =     "ipheth",
0538     .probe =    ipheth_probe,
0539     .disconnect =   ipheth_disconnect,
0540     .id_table = ipheth_table,
0541     .disable_hub_initiated_lpm = 1,
0542 };
0543 
0544 module_usb_driver(ipheth_driver);
0545 
0546 MODULE_AUTHOR("Diego Giagio <diego@giagio.com>");
0547 MODULE_DESCRIPTION("Apple iPhone USB Ethernet driver");
0548 MODULE_LICENSE("Dual BSD/GPL");