⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbnet.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	    case -ESHUTDOWN:		// hardware gone		if (netif_msg_ifdown (dev))			devdbg (dev, "rx shutdown, code %d", urb_status);		goto block;	    // we get controller i/o faults during khubd disconnect() delays.	    // throttle down resubmits, to avoid log floods; just temporarily,	    // so we still recover when the fault isn't a khubd delay.	    case -EPROTO:		// ehci	    case -ETIMEDOUT:		// ohci	    case -EILSEQ:		// uhci		dev->stats.rx_errors++;		if (!timer_pending (&dev->delay)) {			mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);			if (netif_msg_link (dev))				devdbg (dev, "rx throttle %d", urb_status);		}block:		entry->state = rx_cleanup;		entry->urb = urb;		urb = NULL;		break;	    // data overrun ... flush fifo?	    case -EOVERFLOW:		dev->stats.rx_over_errors++;		// FALLTHROUGH	    	    default:		entry->state = rx_cleanup;		dev->stats.rx_errors++;		if (netif_msg_rx_err (dev))			devdbg (dev, "rx status %d", urb_status);		break;	}	defer_bh(dev, skb, &dev->rxq);	if (urb) {		if (netif_running (dev->net)				&& !test_bit (EVENT_RX_HALT, &dev->flags)) {			rx_submit (dev, urb, GFP_ATOMIC);			return;		}		usb_free_urb (urb);	}	if (netif_msg_rx_err (dev))		devdbg (dev, "no read resubmitted");}static void intr_complete (struct urb *urb, struct pt_regs *regs){	struct usbnet	*dev = urb->context;	int		status = urb->status;	switch (status) {	    /* success */	    case 0:		dev->driver_info->status(dev, urb);		break;	    /* software-driven interface shutdown */	    case -ENOENT:		// urb killed	    case -ESHUTDOWN:		// hardware gone		if (netif_msg_ifdown (dev))			devdbg (dev, "intr shutdown, code %d", status);		return;	    /* NOTE:  not throttling like RX/TX, since this endpoint	     * already polls infrequently	     */	    default:		devdbg (dev, "intr status %d", status);		break;	}	if (!netif_running (dev->net))		return;	memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);	status = usb_submit_urb (urb, GFP_ATOMIC);	if (status != 0 && netif_msg_timer (dev))		deverr(dev, "intr resubmit --> %d", status);}/*-------------------------------------------------------------------------*/// unlink pending rx/tx; completion handlers do all other cleanupstatic int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q){	unsigned long		flags;	struct sk_buff		*skb, *skbnext;	int			count = 0;	spin_lock_irqsave (&q->lock, flags);	for (skb = q->next; skb != (struct sk_buff *) q; skb = skbnext) {		struct skb_data		*entry;		struct urb		*urb;		int			retval;		entry = (struct skb_data *) skb->cb;		urb = entry->urb;		skbnext = skb->next;		// during some PM-driven resume scenarios,		// these (async) unlinks complete immediately		retval = usb_unlink_urb (urb);		if (retval != -EINPROGRESS && retval != 0)			devdbg (dev, "unlink urb err, %d", retval);		else			count++;	}	spin_unlock_irqrestore (&q->lock, flags);	return count;}/*-------------------------------------------------------------------------*/// precondition: never called in_interruptstatic int usbnet_stop (struct net_device *net){	struct usbnet		*dev = netdev_priv(net);	int			temp;	DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 	DECLARE_WAITQUEUE (wait, current);	netif_stop_queue (net);	if (netif_msg_ifdown (dev))		devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",			dev->stats.rx_packets, dev->stats.tx_packets, 			dev->stats.rx_errors, dev->stats.tx_errors			);	// ensure there are no more active urbs	add_wait_queue (&unlink_wakeup, &wait);	dev->wait = &unlink_wakeup;	temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq);	// maybe wait for deletions to finish.	while (!skb_queue_empty(&dev->rxq) &&	       !skb_queue_empty(&dev->txq) &&	       !skb_queue_empty(&dev->done)) {		msleep(UNLINK_TIMEOUT_MS);		if (netif_msg_ifdown (dev))			devdbg (dev, "waited for %d urb completions", temp);	}	dev->wait = NULL;	remove_wait_queue (&unlink_wakeup, &wait); 	usb_kill_urb(dev->interrupt);	/* deferred work (task, timer, softirq) must also stop.	 * can't flush_scheduled_work() until we drop rtnl (later),	 * else workers could deadlock; so make workers a NOP.	 */	dev->flags = 0;	del_timer_sync (&dev->delay);	tasklet_kill (&dev->bh);	return 0;}/*-------------------------------------------------------------------------*/// posts reads, and enables write queuing// precondition: never called in_interruptstatic int usbnet_open (struct net_device *net){	struct usbnet		*dev = netdev_priv(net);	int			retval = 0;	struct driver_info	*info = dev->driver_info;	// put into "known safe" state	if (info->reset && (retval = info->reset (dev)) < 0) {		if (netif_msg_ifup (dev))			devinfo (dev,				"open reset fail (%d) usbnet usb-%s-%s, %s",				retval,				dev->udev->bus->bus_name, dev->udev->devpath,			info->description);		goto done;	}	// insist peer be connected	if (info->check_connect && (retval = info->check_connect (dev)) < 0) {		if (netif_msg_ifup (dev))			devdbg (dev, "can't open; %d", retval);		goto done;	}	/* start any status interrupt transfer */	if (dev->interrupt) {		retval = usb_submit_urb (dev->interrupt, GFP_KERNEL);		if (retval < 0) {			if (netif_msg_ifup (dev))				deverr (dev, "intr submit %d", retval);			goto done;		}	}	netif_start_queue (net);	if (netif_msg_ifup (dev)) {		char	*framing;		if (dev->driver_info->flags & FLAG_FRAMING_NC)			framing = "NetChip";		else if (dev->driver_info->flags & FLAG_FRAMING_GL)			framing = "GeneSys";		else if (dev->driver_info->flags & FLAG_FRAMING_Z)			framing = "Zaurus";		else if (dev->driver_info->flags & FLAG_FRAMING_RN)			framing = "RNDIS";		else if (dev->driver_info->flags & FLAG_FRAMING_AX)			framing = "ASIX";		else			framing = "simple";		devinfo (dev, "open: enable queueing "				"(rx %d, tx %d) mtu %d %s framing",			RX_QLEN (dev), TX_QLEN (dev), dev->net->mtu,			framing);	}	// delay posting reads until we're fully open	tasklet_schedule (&dev->bh);done:	return retval;}/*-------------------------------------------------------------------------*//* ethtool methods; minidrivers may need to add some more, but * they'll probably want to use this base set. */void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info){	struct usbnet *dev = netdev_priv(net);	/* REVISIT don't always return "usbnet" */	strncpy (info->driver, driver_name, sizeof info->driver);	strncpy (info->version, DRIVER_VERSION, sizeof info->version);	strncpy (info->fw_version, dev->driver_info->description,		sizeof info->fw_version);	usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);}EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);static u32 usbnet_get_link (struct net_device *net){	struct usbnet *dev = netdev_priv(net);	/* If a check_connect is defined, return its result */	if (dev->driver_info->check_connect)		return dev->driver_info->check_connect (dev) == 0;	/* Otherwise, say we're up (to avoid breaking scripts) */	return 1;}u32 usbnet_get_msglevel (struct net_device *net){	struct usbnet *dev = netdev_priv(net);	return dev->msg_enable;}EXPORT_SYMBOL_GPL(usbnet_get_msglevel);void usbnet_set_msglevel (struct net_device *net, u32 level){	struct usbnet *dev = netdev_priv(net);	dev->msg_enable = level;}EXPORT_SYMBOL_GPL(usbnet_set_msglevel);/* drivers may override default ethtool_ops in their bind() routine */static struct ethtool_ops usbnet_ethtool_ops = {	.get_drvinfo		= usbnet_get_drvinfo,	.get_link		= usbnet_get_link,	.get_msglevel		= usbnet_get_msglevel,	.set_msglevel		= usbnet_set_msglevel,};/*-------------------------------------------------------------------------*//* work that cannot be done in interrupt context uses keventd. * * NOTE:  with 2.5 we could do more of this using completion callbacks, * especially now that control transfers can be queued. */static voidkevent (void *data){	struct usbnet		*dev = data;	int			status;	/* usb_clear_halt() needs a thread context */	if (test_bit (EVENT_TX_HALT, &dev->flags)) {		unlink_urbs (dev, &dev->txq);		status = usb_clear_halt (dev->udev, dev->out);		if (status < 0				&& status != -EPIPE				&& status != -ESHUTDOWN) {			if (netif_msg_tx_err (dev))				deverr (dev, "can't clear tx halt, status %d",					status);		} else {			clear_bit (EVENT_TX_HALT, &dev->flags);			if (status != -ESHUTDOWN)				netif_wake_queue (dev->net);		}	}	if (test_bit (EVENT_RX_HALT, &dev->flags)) {		unlink_urbs (dev, &dev->rxq);		status = usb_clear_halt (dev->udev, dev->in);		if (status < 0				&& status != -EPIPE				&& status != -ESHUTDOWN) {			if (netif_msg_rx_err (dev))				deverr (dev, "can't clear rx halt, status %d",					status);		} else {			clear_bit (EVENT_RX_HALT, &dev->flags);			tasklet_schedule (&dev->bh);		}	}	/* tasklet could resubmit itself forever if memory is tight */	if (test_bit (EVENT_RX_MEMORY, &dev->flags)) {		struct urb	*urb = NULL;		if (netif_running (dev->net))			urb = usb_alloc_urb (0, GFP_KERNEL);		else			clear_bit (EVENT_RX_MEMORY, &dev->flags);		if (urb != NULL) {			clear_bit (EVENT_RX_MEMORY, &dev->flags);			rx_submit (dev, urb, GFP_KERNEL);			tasklet_schedule (&dev->bh);		}	}	if (test_bit (EVENT_LINK_RESET, &dev->flags)) {		struct driver_info 	*info = dev->driver_info;		int			retval = 0;		clear_bit (EVENT_LINK_RESET, &dev->flags);		if(info->link_reset && (retval = info->link_reset(dev)) < 0) {			devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s",				retval,				dev->udev->bus->bus_name, dev->udev->devpath,				info->description);		}	}	if (dev->flags)		devdbg (dev, "kevent done, flags = 0x%lx",			dev->flags);}/*-------------------------------------------------------------------------*/static void tx_complete (struct urb *urb, struct pt_regs *regs){	struct sk_buff		*skb = (struct sk_buff *) urb->context;	struct skb_data		*entry = (struct skb_data *) skb->cb;	struct usbnet		*dev = entry->dev;	if (urb->status == 0) {		dev->stats.tx_packets++;		dev->stats.tx_bytes += entry->length;	} else {		dev->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:		// ehci		case -ETIMEDOUT:	// ohci		case -EILSEQ:		// uhci			if (!timer_pending (&dev->delay)) {				mod_timer (&dev->delay,					jiffies + THROTTLE_JIFFIES);				if (netif_msg_link (dev))					devdbg (dev, "tx throttle %d",							urb->status);			}			netif_stop_queue (dev->net);			break;		default:			if (netif_msg_tx_err (dev))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -