/* USB::Interface#settings */ static VALUE rusb_interface_settings(VALUE v) { struct usb_interface *p = get_usb_interface(v); int i; VALUE altsetting = rb_ary_new2(p->num_altsetting); for (i = 0; i < p->num_altsetting; i++) rb_ary_store(altsetting, i, rusb_interface_descriptor_make(&p->altsetting[i], v)); return altsetting; }
netdev_tx_t gobi_usbnet_start_xmit_3_0_6 (struct sk_buff *skb, struct net_device *net) { struct usbnet *dev = netdev_priv(net); int length; struct urb *urb = NULL; struct skb_data *entry; struct driver_info *info = dev->driver_info; unsigned long flags; int retval; #ifdef TX_URB_MONITOR unsigned char b_usb_if_num = 0; int iRet = -1; #endif //#ifdef TX_URB_MONITOR // some devices want funky USB-level framing, for // win32 driver (usually) and/or hardware quirks if (info->tx_fixup) { skb = info->tx_fixup (dev, skb, GFP_ATOMIC); if (!skb) { if (netif_msg_tx_err(dev)) { netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n"); goto drop; } else { /* cdc_ncm collected packet; waits for more */ goto not_drop; } } } length = skb->len; if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { netif_dbg(dev, tx_err, dev->net, "no urb\n"); goto drop; } entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; entry->state = tx_start; entry->length = length; usb_fill_bulk_urb (urb, dev->udev, dev->out, skb->data, skb->len, tx_complete, skb); /* don't assume the hardware handles USB_ZERO_PACKET * NOTE: strictly conforming cdc-ether devices should expect * the ZLP here, but ignore the one-byte packet. * NOTE2: CDC NCM specification is different from CDC ECM when * handling ZLP/short packets, so cdc_ncm driver will make short * packet itself if needed. */ if (length % dev->maxpacket == 0) { if (!(info->flags & FLAG_SEND_ZLP)) { if (!(info->flags & FLAG_MULTI_PACKET)) { urb->transfer_buffer_length++; if (skb_tailroom(skb)) { skb->data[skb->len] = 0; __skb_put(skb, 1); } } } else urb->transfer_flags |= URB_ZERO_PACKET; } spin_lock_irqsave(&dev->txq.lock, flags); retval = usb_autopm_get_interface_async(dev->intf); if (retval < 0) { spin_unlock_irqrestore(&dev->txq.lock, flags); goto drop; } #ifdef CONFIG_PM /* if this triggers the device is still a sleep */ if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { /* transmission will be done in resume */ usb_anchor_urb(urb, &dev->deferred); /* no use to process more packets */ netif_stop_queue(net); spin_unlock_irqrestore(&dev->txq.lock, flags); netdev_dbg(dev->net, "Delaying transmission for resumption\n"); goto deferred; } #endif #ifdef TX_URB_MONITOR iRet = get_usb_interface(urb, &b_usb_if_num); #endif //#ifdef TX_URB_MONITOR switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { case -EPIPE: netif_stop_queue (net); usbnet_defer_kevent (dev, EVENT_TX_HALT); usb_autopm_put_interface_async(dev->intf); break; default: usb_autopm_put_interface_async(dev->intf); netif_dbg(dev, tx_err, dev->net, "tx: submit urb err %d\n", retval); break; case 0: net->trans_start = jiffies; __skb_queue_tail (&dev->txq, skb); if (dev->txq.qlen >= TX_QLEN (dev)) netif_stop_queue (net); } #ifdef TX_URB_MONITOR /* * This can be called from here or from inside the * case 0 in the above switch. There will be one less * condition to check */ /* * Call URB_monitor() with true as the URB has been successfully * submitted to the txq. */ if ((URB_monitor) && (0==iRet) && (0==retval)) { URB_monitor(true, b_usb_if_num); } #endif //#ifdef TX_URB_MONITOR spin_unlock_irqrestore (&dev->txq.lock, flags); if (retval) { netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval); drop: dev->net->stats.tx_dropped++; not_drop: if (skb) dev_kfree_skb_any (skb); usb_free_urb (urb); } else netif_dbg(dev, tx_queued, dev->net, "> tx, len %d, type 0x%x\n", length, skb->protocol); #ifdef CONFIG_PM deferred: #endif return NETDEV_TX_OK; }
static void tx_complete (struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; struct usbnet *dev = entry->dev; #ifdef TX_URB_MONITOR unsigned char b_usb_if_num = 0; int iRet = get_usb_interface(urb, &b_usb_if_num); #endif //#ifdef TX_URB_MONITOR if (urb->status == 0) { if (!(dev->driver_info->flags & FLAG_MULTI_PACKET)) dev->net->stats.tx_packets++; dev->net->stats.tx_bytes += entry->length; } else { dev->net->stats.tx_errors++; switch (urb->status) { case -EPIPE: usbnet_defer_kevent (dev, EVENT_TX_HALT); break; /* software-driven interface shutdown */ case -ECONNRESET: // async unlink case -ESHUTDOWN: // hardware gone break; // like rx, tx gets controller i/o faults during khubd delays // and so it uses the same throttling mechanism. case -EPROTO: case -ETIME: case -EILSEQ: if (!timer_pending (&dev->delay)) { mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); if (netif_msg_link (dev)) #if (LINUX_VERSION_CODE != KERNEL_VERSION( 3,0,6 )) devdbg (dev, "tx throttle %d", urb->status); #else netif_dbg(dev, link, dev->net, "tx throttle %d\n", urb->status); #endif } netif_stop_queue (dev->net); break; default: if (netif_msg_tx_err (dev)) #if (LINUX_VERSION_CODE != KERNEL_VERSION( 3,0,6 )) devdbg (dev, "tx err %d", entry->urb->status); #else netif_dbg(dev, tx_err, dev->net, "tx err %d\n", entry->urb->status); #endif break; } } usb_autopm_put_interface_async(dev->intf); urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); #ifdef TX_URB_MONITOR if ((URB_monitor) && (0==iRet)) { URB_monitor(false, b_usb_if_num); } #endif //#ifdef TX_URB_MONITOR }
/* USB::Interface#num_altsetting */ static VALUE rusb_interface_num_altsetting(VALUE v) { return INT2FIX(get_usb_interface(v)->num_altsetting); }