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

📄 net1080.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
		// netif_device_detach (&dev->net);		// FALLTHROUGH				    // software-driven interface shutdown	    case -ECONNRESET:		entry->state = rx_cleanup;		usb_free_urb (urb);		urb = 0;		dbg ("%s ... shutdown rx (%d)", dev->net.name, urb_status);		break;	    // data overrun ... flush fifo?	    case -EOVERFLOW:		dev->stats.rx_over_errors++;		// FALLTHROUGH	    	    default:		entry->state = rx_cleanup;		dev->stats.rx_errors++;		err ("%s rx: status %d", dev->net.name, urb_status);		break;	}	defer_bh (dev, skb);	if (urb) {		if (!netif_queue_stopped (&dev->net)) {			rx_submit (dev, urb, GFP_ATOMIC);			return;		} else			usb_free_urb (urb);	}#ifdef	VERBOSE	dbg ("no read resubmitted");#endif	VERBOSE}/*-------------------------------------------------------------------------*/// unlink pending rx/tx; completion handlers do all other cleanupstatic int unlink_urbs (struct sk_buff_head *q){	unsigned long		flags;	struct sk_buff		*skb;	struct skb_data		*entry;	int			retval;	int			count = 0;	spin_lock_irqsave (&q->lock, flags);	for (skb = q->next; skb != (struct sk_buff *) q; skb = skb->next) {		entry = (struct skb_data *) skb->cb;		entry->urb->transfer_flags |= USB_ASYNC_UNLINK;		retval = usb_unlink_urb (entry->urb);		if (retval < 0)			dbg ("unlink urb err, %d", retval);		else			count++;	}	spin_unlock_irqrestore (&q->lock, flags);	return count;}/*-------------------------------------------------------------------------*/// precondition: never called in_interruptstatic int net1080_stop (struct net_device *net){	struct net1080		*dev = (struct net1080 *) net->priv;	int			temp;	DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 	DECLARE_WAITQUEUE (wait, current);	mutex_lock (&dev->mutex);		dbg ("%s stop stats: rx/tx %ld/%ld, errs %ld/%ld", net->name,		dev->stats.rx_packets, dev->stats.tx_packets, 		dev->stats.rx_errors, dev->stats.tx_errors		);	netif_stop_queue(net);	// ensure there are no more active urbs	add_wait_queue (&unlink_wakeup, &wait);	dev->wait = &unlink_wakeup;	temp = unlink_urbs (&dev->txq) + unlink_urbs (&dev->rxq);	// maybe wait for deletions to finish.	if (temp) {		current->state = TASK_UNINTERRUPTIBLE;		schedule ();		dbg ("waited for %d urb completions", temp);	}	dev->wait = 0;	current->state = TASK_RUNNING;	remove_wait_queue (&unlink_wakeup, &wait); 	mutex_unlock (&dev->mutex);	MOD_DEC_USE_COUNT;	return 0;}/*-------------------------------------------------------------------------*/// posts a read, and enables write queing// precondition: never called in_interruptstatic int net1080_open (struct net_device *net){	struct net1080		*dev = (struct net1080 *) net->priv;	int			retval;	u16			status;	int			i;	MOD_INC_USE_COUNT;	mutex_lock (&dev->mutex);	// insist peer be connected -- is this the best place?	if ((retval = register_read (dev, REG_STATUS, &status)) != 0) {		dbg ("%s open: status read failed - %d", net->name, retval);		goto done;	}	if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER)  {		retval = -ENOLINK;		dbg ("%s open: peer not connected", net->name);		goto done;	}	MOD_INC_USE_COUNT;	netif_start_queue (net);	for (i = 0; i < RX_QLEN; i++)		rx_submit (dev, usb_alloc_urb (0), GFP_KERNEL);	dbg ("%s open: started queueing (rx %d, tx %d)",		net->name, RX_QLEN, TX_QLEN);done:	mutex_unlock (&dev->mutex);	MOD_DEC_USE_COUNT;	return retval;}/*-------------------------------------------------------------------------*/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 net1080		*dev = entry->dev;	urb->dev = 0;	entry->state = tx_done;	defer_bh (dev, skb);	netif_wake_queue (&dev->net);}/*-------------------------------------------------------------------------*/static struct sk_buff *fixup_skb (struct sk_buff *skb){	int			padlen;	struct sk_buff		*skb2;	padlen = ((skb->len + sizeof (struct nc_header)			+ sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;	if (!skb_cloned (skb)) {		int	headroom = skb_headroom (skb);		int	tailroom = skb_tailroom (skb);		if ((padlen + sizeof (struct nc_trailer)) <= tailroom			    && sizeof (struct nc_header) <= headroom)			return skb;		if ((sizeof (struct nc_header) + padlen					+ sizeof (struct nc_trailer)) <				(headroom + tailroom)) {			skb->data = memmove (skb->head						+ sizeof (struct nc_header),					    skb->data, skb->len);			skb->tail = skb->data + skb->len;			return skb;		}	}	skb2 = skb_copy_expand (skb,				sizeof (struct nc_header),				sizeof (struct nc_trailer) + padlen,				in_interrupt () ? GFP_ATOMIC : GFP_KERNEL);	dev_kfree_skb_any (skb);	return skb2;}/*-------------------------------------------------------------------------*/static int net1080_start_xmit (struct sk_buff *skb, struct net_device *net){	struct net1080		*dev = (struct net1080 *) net->priv;	int			length = skb->len;	int			retval = 0;	struct urb		*urb = 0;	struct skb_data		*entry;	struct nc_header	*header;	struct nc_trailer	*trailer;	unsigned long		flags;	if ((skb = fixup_skb (skb)) == 0) {		dbg ("can't fixup skb");		goto drop;	}	if ((urb = usb_alloc_urb (0)) == 0) {		dbg ("no urb");		goto drop;	}	entry = (struct skb_data *) skb->cb;	entry->urb = urb;	entry->dev = dev;	entry->state = tx_start;	entry->length = length;	header = (struct nc_header *) skb_push (skb, sizeof *header);	header->hdr_len = cpu_to_le16 (sizeof (*header));	header->packet_len = cpu_to_le16 (length);	if (!((skb->len + sizeof *trailer) & 0x01))		*skb_put (skb, 1) = NC_PAD_BYTE;	trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer);	FILL_BULK_URB (urb, dev->udev,			usb_sndbulkpipe (dev->udev, 1),			skb->data, skb->len, tx_complete, skb);	urb->transfer_flags |= USB_QUEUE_BULK;	// FIXME urb->timeout = ...;	spin_lock_irqsave (&dev->txq.lock, flags);	if (!netif_queue_stopped (&dev->net)) {		header->packet_id = cpu_to_le16 (dev->packet_id++);		put_unaligned (header->packet_id, &trailer->packet_id);		netif_stop_queue (net);		if ((retval = usb_submit_urb (urb)) != 0) {			netif_start_queue (net);			dbg ("%s tx: submit urb err %d", net->name, retval);		} else {			net->trans_start = jiffies;			__skb_queue_tail (&dev->txq, skb);			if (dev->txq.qlen < TX_QLEN)				netif_start_queue (net);		}	} else		retval = -ENOLINK;	spin_unlock_irqrestore (&dev->txq.lock, flags);	if (retval) {		dbg ("drop");drop:		dev->stats.tx_dropped++;		dev_kfree_skb_any (skb);		usb_free_urb (urb);#ifdef	VERBOSE	} else {		dbg ("%s: tx %p len %d", net->name, skb, length);#endif	}	return retval;}/*-------------------------------------------------------------------------*/static void rx_process (struct net1080 *dev, struct sk_buff *skb){	struct nc_header	*header;	struct nc_trailer	*trailer;	header = (struct nc_header *) skb->data;	le16_to_cpus (&header->hdr_len);	le16_to_cpus (&header->packet_len);	if (header->packet_len > MAX_PACKET) {		dev->stats.rx_frame_errors++;		dbg ("packet too big, %d", header->packet_len);		goto error;	} else if (header->hdr_len < NC_MIN_HEADER) {		dev->stats.rx_frame_errors++;		dbg ("header too short, %d", header->hdr_len);		goto error;	} else if (header->hdr_len > header->packet_len) {		dev->stats.rx_frame_errors++;		dbg ("header too big, %d packet %d", header->hdr_len, header->packet_len);		goto error;	} else if (header->hdr_len != sizeof *header) {		// out of band data for us?		dbg ("header OOB, %d bytes", header->hdr_len - NC_MIN_HEADER);		// switch (vendor/product ids) { ... }	}	skb_pull (skb, header->hdr_len);	trailer = (struct nc_trailer *)		(skb->data + skb->len - sizeof *trailer);	skb_trim (skb, skb->len - sizeof *trailer);	if ((header->packet_len & 0x01) == 0) {		if (skb->data [header->packet_len] != NC_PAD_BYTE) {			dev->stats.rx_frame_errors++;			dbg ("bad pad");			goto error;		}		skb_trim (skb, skb->len - 1);	}	if (skb->len != header->packet_len) {		dev->stats.rx_length_errors++;		dbg ("bad packet len %d (expected %d)",			skb->len, header->packet_len);		goto error;	}	if (header->packet_id != get_unaligned (&trailer->packet_id)) {		dev->stats.rx_fifo_errors++;		dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",			header->packet_id, trailer->packet_id);		goto error;	}	if (skb->len) {		skb->dev = &dev->net;		skb->protocol = eth_type_trans (skb, &dev->net);		dev->stats.rx_packets++;		dev->stats.rx_bytes += skb->len;#ifdef	VERBOSE		dbg ("%s: rx %p len %d, type 0x%x, id 0x%x",			dev->net.name, skb, skb->len, skb->protocol,			le16_to_cpu (header->packet_id));#endif		netif_rx (skb);	} else {		dbg ("drop");error:		dev->stats.rx_errors++;		dev_kfree_skb (skb);	}}/*-------------------------------------------------------------------------*/// tasklet// We can have a state machine in this tasklet monitor the link state,// using async control messaging and calling attach/detach routines.// But then some listener ought to respond to the changes; do those// network attach/detach notifications get to userland somehow, such// as by calling "ifup usb0" and "ifdown usb0"?static void net1080_bh (unsigned long param){	struct net1080		*dev = (struct net1080 *) param;	struct sk_buff		*skb;	struct skb_data		*entry;	while ((skb = skb_dequeue (&dev->done))) {		entry = (struct skb_data *) skb->cb;		switch (entry->state) {		    case rx_done:			rx_process (dev, skb);			continue;		    case tx_done:			if (entry->urb->status) {				// can this statistic become more specific?				dev->stats.tx_errors++;				dbg ("%s tx: err %d", dev->net.name,					entry->urb->status);			} else {				dev->stats.tx_packets++;				dev->stats.tx_bytes += entry->length;			}			// FALLTHROUGH:		    case rx_cleanup:			usb_free_urb (entry->urb);			dev_kfree_skb (skb);			continue;		    default:			dbg ("%s: bogus skb state %d",				dev->net.name, entry->state);		}	}	// waiting for all pending urbs to complete?	if (dev->wait) {		if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {			wake_up (dev->wait);		}	// or are we maybe short a few urbs?	} else if (!netif_queue_stopped (&dev->net)) {		if (dev->rxq.qlen < TX_QLEN) {			struct urb	*urb;			int		i;			for (i = 0; i < 3 && dev->rxq.qlen < TX_QLEN; i++) {				if ((urb = usb_alloc_urb (0)) != 0)					rx_submit (dev, urb, GFP_ATOMIC);			}			dbg ("%s: rxqlen now %d",				dev->net.name, dev->rxq.qlen);		}	}}/*------------------------------------------------------------------------- * * USB Device Driver support * --------------------------------------------------------------------------*/ // precondition: never called in_interruptstatic void net1080_disconnect (struct usb_device *udev, void *ptr){	struct net1080	*dev = (struct net1080 *) ptr;	info ("%s: USB %d dev %d, %s, disconnected",		dev->net.name,		udev->bus->busnum, udev->devnum,		(char *) dev->prod_info->driver_info);		unregister_netdev (&dev->net);	mutex_lock (&net1080_mutex);	mutex_lock (&dev->mutex);	list_del (&dev->dev_list);	mutex_unlock (&net1080_mutex);#ifdef DEBUG	memset (dev, 0x55, sizeof *dev);#endif	kfree (dev);	usb_dec_dev_use (udev);}/*-------------------------------------------------------------------------*/// precondition: never called in_interruptstatic void *net1080_probe (struct usb_device *udev, unsigned ifnum, const struct usb_device_id *prod){	struct net1080		*dev;	struct net_device 	*net;	struct usb_interface_descriptor	*interface;	int			retval;	// sanity check; expect dedicated interface/devices for now.	interface = &udev->actconfig->interface [ifnum].altsetting[0];	if (udev->descriptor.bNumConfigurations != 1			|| udev->config[0].bNumInterfaces != 1			|| udev->config[0].bNumInterfaces != 1			|| interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC			|| interface->bNumEndpoints != 5			) {		dbg ("Bogus config info");		return 0;	}	// set up our own records	if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) {		dbg ("can't kmalloc dev");		return 0;	}	memset (dev, 0, sizeof *dev);	init_MUTEX_LOCKED (&dev->mutex);	usb_inc_dev_use (udev);	dev->udev = udev;	dev->prod_info = prod;	INIT_LIST_HEAD (&dev->dev_list);	skb_queue_head_init (&dev->rxq);	skb_queue_head_init (&dev->txq);	skb_queue_head_init (&dev->done);	dev->bh.func = net1080_bh;	dev->bh.data = (unsigned long) dev;	// set up network interface records	net = &dev->net;	net->priv = dev;	strcpy (net->name, "usb%d");	memcpy (net->dev_addr, node_id, sizeof node_id);	ether_setup (net);	// net->flags |= IFF_POINTOPOINT;	net->change_mtu = net1080_change_mtu;	net->get_stats = net1080_get_stats;	net->hard_start_xmit = net1080_start_xmit;	net->open = net1080_open;	net->stop = net1080_stop;	register_netdev (&dev->net);	// ... talk to the device	// dump_registers (dev);	if ((retval = net1080_reset (dev)) < 0) {		err ("%s: init reset fail on USB %d dev %d - %d",			dev->net.name, udev->bus->busnum, udev->devnum, retval);		mutex_unlock (&dev->mutex);		net1080_disconnect (udev, dev);		return 0;	}	// ok, it's ready to go.	mutex_lock (&net1080_mutex);	list_add (&dev->dev_list, &net1080_list);	mutex_unlock (&dev->mutex);	// start as if the link is up	netif_device_attach (&dev->net);	mutex_unlock (&net1080_mutex);	return dev;}/*-------------------------------------------------------------------------*/static struct usb_driver net1080_driver = {	name:		"net1080",	id_table:	products,	probe:		net1080_probe,	disconnect:	net1080_disconnect,};/*-------------------------------------------------------------------------*/static int __init net1080_init (void){	// compiler should optimize this out	if (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data))		BUG (); 	if (usb_register (&net1080_driver) < 0) 		return -1;	get_random_bytes (node_id, sizeof node_id);	node_id [0] &= 0x7f;	return 0;}module_init (net1080_init);static void __exit net1080_exit (void){ 	usb_deregister (&net1080_driver);}module_exit (net1080_exit);MODULE_AUTHOR ("David Brownell <dbrownell@users.sourceforge.net>");MODULE_DESCRIPTION ("NetChip 1080 Driver (USB Host-to-Host Link)");

⌨️ 快捷键说明

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