天天看點

linux kernel X-tranx-Y : Ethernet-to-Gadget

  今天我們來看看linux kernel driver中的glue:u_ether.c這個檔案把以太網卡裝置轉換成了USB gadget裝置,目的是實作TCP/IP Over USB。該檔案實作的功能框圖如下:

      +-------------+--------------------------+

      |                 |                                 |

      |                 | ethernet device       |

      |                 |                                 |

      | u_ether.c+---------------------------+

      |                 |                                 |

      |                 | gadget device         |  

      |                 |                                 |

      +-------------+--------------------------+

  我們先來看一下struct eth_dev這個結構:

     struct eth_dev {

 52        

 55         spinlock_t              lock;

 56         struct gether           *port_usb;

 57

 58         struct net_device       *net;

 59         struct usb_gadget       *gadget;

 60

 61         spinlock_t              req_lock;      

 62         struct list_head        tx_reqs, rx_reqs;

 63         atomic_t                tx_qlen;

 64

 65         struct sk_buff_head     rx_frames;

 66

 67         unsigned                header_len;

            //以下兩個成員相當重要,調了gadget層的收發,主要是添加或删除標頭。

 68         struct sk_buff          *(*wrap)(struct gether *, struct sk_buff *skb);

 69         int                     (*unwrap)(struct gether *,

 70                                                 struct sk_buff *skb,

 71                                                 struct sk_buff_head *list);

 72

 73         struct work_struct      work;

 74

 75         unsigned long           todo;

 76 #define WORK_RX_MEMORY          0

 77

 78         bool                    zlp;

 79         u8                      host_mac[ETH_ALEN];

 80 };

  在這個結構中,我們可以看到兩個很重要的成員:struct net_device *net;和 struct usb_gadget *gadget;由此可知,這個結構是兩個裝置的樞紐,它是膠水層的主要結構。

  這個結構何時被建立呢? 以下成員函數實作建立和初始化任務:

747

    //這個成員往往由gadget來調用,建立一個網絡裝置(以太網卡)

761 int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],

762                 const char *netname)

763 {

764         struct eth_dev          *dev;

765         struct net_device       *net;

766         int                     status;

767

768         if (the_dev)

769                 return -EBUSY;

770

771         net = alloc_etherdev(sizeof *dev);   //為膠水結構開辟記憶體

772         if (!net)

773                 return -ENOMEM;

774

775         dev = netdev_priv(net);

776         spin_lock_init(&dev->lock);

777         spin_lock_init(&dev->req_lock);

778         INIT_WORK(&dev->work, eth_work);

779         INIT_LIST_HEAD(&dev->tx_reqs);

780         INIT_LIST_HEAD(&dev->rx_reqs);

781

782         skb_queue_head_init(&dev->rx_frames);

783

784        

785         dev->net = net;                      //拉紅線:net device

786         snprintf(net->name, sizeof(net->name), "%s%%d", netname);

787

788         if (get_ether_addr(dev_addr, net->dev_addr))

789                 dev_warn(&g->dev,

790                         "using random %s ethernet address\n", "self");

791         if (get_ether_addr(host_addr, dev->host_mac))

792                 dev_warn(&g->dev,

793                         "using random %s ethernet address\n", "host");

794

795         if (ethaddr)

796                 memcpy(ethaddr, dev->host_mac, ETH_ALEN);

797

798         net->netdev_ops = &eth_netdev_ops;

799

800         SET_ETHTOOL_OPS(net, &ops);

801

802         dev->gadget = g;                   //拉紅線:gadget device

803         SET_NETDEV_DEV(net, &g->dev);

804         SET_NETDEV_DEVTYPE(net, &gadget_type);

805

806         status = register_netdev(net);     //注冊網絡裝置,為IP over USB搭橋

807         if (status < 0) {

808                 dev_dbg(&g->dev, "register_netdev failed, %d\n", status);

809                 free_netdev(net);

810         } else {

811                 INFO(dev, "MAC %pM\n", net->dev_addr);

812                 INFO(dev, "HOST MAC %pM\n", dev->host_mac);

813

814                 the_dev = dev;

815

816                

820                 netif_carrier_off(net);

821         }

822

823         return status;

824 }

  接下來,我們一起來看看IP層到網絡裝置層的寫流程,忽略了協定接口層、網絡裝置抽象層、直接跳到網絡裝置執行個體層:

734 static const struct net_device_ops eth_netdev_ops = {

735         .ndo_open               = eth_open,

736         .ndo_stop               = eth_stop,

737         .ndo_start_xmit         = eth_start_xmit,

738         .ndo_change_mtu         = ueth_change_mtu,

739         .ndo_set_mac_address    = eth_mac_addr,

740         .ndo_validate_addr      = eth_validate_addr,

741 };

484 static netdev_tx_t eth_start_xmit(struct sk_buff *skb,

485                                         struct net_device *net)

486 {

487         struct eth_dev          *dev = netdev_priv(net);

488         int                     length = skb->len;

489         int                     retval;

490         struct usb_request      *req = NULL;

491         unsigned long           flags;

492         struct usb_ep           *in;

493         u16                     cdc_filter;

494

495         spin_lock_irqsave(&dev->lock, flags);

496         if (dev->port_usb) {

497                 in = dev->port_usb->in_ep;

498                 cdc_filter = dev->port_usb->cdc_filter;

499         } else {

500                 in = NULL;

501                 cdc_filter = 0;

502         }

503         spin_unlock_irqrestore(&dev->lock, flags);

504

505         if (!in) {

506                 dev_kfree_skb_any(skb);

507                 return NETDEV_TX_OK;

508         }

509

510        

511         if (!is_promisc(cdc_filter)) {

512                 u8              *dest = skb->data;

513

514                 if (is_multicast_ether_addr(dest)) {

515                         u16     type;

516

517                        

520                         if (is_broadcast_ether_addr(dest))

521                                 type = USB_CDC_PACKET_TYPE_BROADCAST;

522                         else

523                                 type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;

524                         if (!(cdc_filter & type)) {

525                                 dev_kfree_skb_any(skb);

526                                 return NETDEV_TX_OK;

527                         }

528                 }

529                

530         }

531

532         spin_lock_irqsave(&dev->req_lock, flags);

533        

538         if (list_empty(&dev->tx_reqs)) {

539                 spin_unlock_irqrestore(&dev->req_lock, flags);

540                 return NETDEV_TX_BUSY;

541         }

542

543         req = container_of(dev->tx_reqs.next, struct usb_request, list);

544         list_del(&req->list);

545

546        

547         if (list_empty(&dev->tx_reqs))

548                 netif_stop_queue(net);

549         spin_unlock_irqrestore(&dev->req_lock, flags);

550

551        

            //若gadget功能層需要,則添加標頭

555         if (dev->wrap) {

556                 unsigned long   flags;

557

558                 spin_lock_irqsave(&dev->lock, flags);

559                 if (dev->port_usb)

560                         skb = dev->wrap(dev->port_usb, skb);    //

561                 spin_unlock_irqrestore(&dev->lock, flags);

562                 if (!skb)

563                         goto drop;

564

565                 length = skb->len;

566         }

            //沒有gadget功能層標頭的需要就直接發生skb,有需求的話已經在上面的if中添加

567         req->buf = skb->data;

568         req->context = skb;

569         req->complete = tx_complete;

570

571        

572         if (dev->port_usb->is_fixed &&

573             length == dev->port_usb->fixed_in_len &&

574             (length % in->maxpacket) == 0)

575                 req->zero = 0;

576         else

577                 req->zero = 1;

578

579        

583         if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)

584                 length++;

585

586         req->length = length;

587

588        

589         if (gadget_is_dualspeed(dev->gadget))

590                 req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||

591                                      dev->gadget->speed == USB_SPEED_SUPER)

592                         ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)

593                         : 0;

594

            //最終在usb 端點發送,完成實際的發送任務的承擔。也展現了ether over usb。

595         retval = usb_ep_queue(in, req, GFP_ATOMIC);

596         switch (retval) {

597         default:

598                 DBG(dev, "tx queue err %d\n", retval);

599                 break;

600         case 0:

601                 net->trans_start = jiffies;

602                 atomic_inc(&dev->tx_qlen);

603         }

604

605         if (retval) {

606                 dev_kfree_skb_any(skb);

607 drop:

608                 dev->net->stats.tx_dropped++;

609                 spin_lock_irqsave(&dev->req_lock, flags);

610                 if (list_empty(&dev->tx_reqs))

611                         netif_start_queue(net);

612                 list_add(&req->list, &dev->tx_reqs);

613                 spin_unlock_irqrestore(&dev->req_lock, flags);

614         }

615         return NETDEV_TX_OK;

616 }

   接收的過程為此的逆過程,大家可以自行分析。

繼續閱讀