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

📄 usbnet.c

📁 linux下的usb接口驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	// put into "known safe" state	if (info->reset && (retval = info->reset (dev)) < 0) {		devinfo (dev, "open reset fail (%d) usbnet %03d/%03d, %s",			retval,			dev->udev->bus->busnum, dev->udev->devnum,			info->description);		goto done;	}	// insist peer be connected	if (info->check_connect && (retval = info->check_connect (dev)) < 0) {		devdbg (dev, "can't open; %d", retval);		goto done;	}	netif_start_queue (net);	devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %s framing",		RX_QLEN, TX_QLEN, dev->net.mtu,		(info->flags & (FLAG_FRAMING_NC | FLAG_FRAMING_GL))		    ? ((info->flags & FLAG_FRAMING_NC)			? "NetChip"			: "GeneSys")		    : "raw"		);	// delay posting reads until we're fully open	tasklet_schedule (&dev->bh);done:	mutex_unlock (&dev->mutex);	return retval;}/*-------------------------------------------------------------------------*//* usb_clear_halt cannot be called in interrupt context */static voidtx_clear_halt (void *data){	struct usbnet		*dev = data;	usb_clear_halt (dev->udev,		usb_sndbulkpipe (dev->udev, dev->driver_info->out));	netif_wake_queue (&dev->net);}/*-------------------------------------------------------------------------*/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;	if (urb->status == USB_ST_STALL) {		if (dev->ctrl_task.sync == 0) {			dev->ctrl_task.routine = tx_clear_halt;			dev->ctrl_task.data = dev;			schedule_task (&dev->ctrl_task);		} else {			dbg ("Cannot clear TX stall");		}	}	urb->dev = 0;	entry->state = tx_done;	defer_bh (dev, skb);}/*-------------------------------------------------------------------------*/static void usbnet_tx_timeout (struct net_device *net){	struct usbnet		*dev = (struct usbnet *) net->priv;	unlink_urbs (&dev->txq);	tasklet_schedule (&dev->bh);	// FIXME: device recovery -- reset?}/*-------------------------------------------------------------------------*/static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net){	struct usbnet		*dev = (struct usbnet *) net->priv;	int			length = skb->len;	int			retval = NET_XMIT_SUCCESS;	struct urb		*urb = 0;	struct skb_data		*entry;	struct driver_info	*info = dev->driver_info;	unsigned long		flags;#ifdef	CONFIG_USB_NET1080	struct nc_header	*header = 0;	struct nc_trailer	*trailer = 0;#endif	/* CONFIG_USB_NET1080 */	flags = in_interrupt () ? GFP_ATOMIC : GFP_NOIO; /* might be used for nfs */	// 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, flags);		if (!skb) {			dbg ("can't tx_fixup skb");			goto drop;		}	}	if (!(urb = usb_alloc_urb (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;	// FIXME: reorganize a bit, so that fixup() fills out NetChip	// framing too. (Packet ID update needs the spinlock...)#ifdef	CONFIG_USB_NET1080	if (info->flags & FLAG_FRAMING_NC) {		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) = PAD_BYTE;		trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer);	} else#endif	/* CONFIG_USB_NET1080 */	/* don't assume the hardware handles USB_ZERO_PACKET */	if ((length % EP_SIZE (dev)) == 0)		skb->len++;	FILL_BULK_URB (urb, dev->udev,			usb_sndbulkpipe (dev->udev, info->out),			skb->data, skb->len, tx_complete, skb);	urb->transfer_flags |= USB_ASYNC_UNLINK;#ifdef	REALLY_QUEUE	urb->transfer_flags |= USB_QUEUE_BULK;#endif	// FIXME urb->timeout = ... jiffies ... ;	spin_lock_irqsave (&dev->txq.lock, flags);#ifdef	CONFIG_USB_NET1080	if (info->flags & FLAG_FRAMING_NC) {		header->packet_id = cpu_to_le16 (dev->packet_id++);		put_unaligned (header->packet_id, &trailer->packet_id);#if 0		devdbg (dev, "frame >tx h %d p %d id %d",			header->hdr_len, header->packet_len,			header->packet_id);#endif	}#endif	/* CONFIG_USB_NET1080 */	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);	}	spin_unlock_irqrestore (&dev->txq.lock, flags);	if (retval) {		devdbg (dev, "drop, code %d", retval);drop:		retval = NET_XMIT_DROP;		dev->stats.tx_dropped++;		if (skb)			dev_kfree_skb_any (skb);		usb_free_urb (urb);#ifdef	VERBOSE	} else {		devdbg (dev, "> tx, len %d, type 0x%x",			length, skb->protocol);#endif	}	return retval;}/*-------------------------------------------------------------------------*/// tasklet ... work that avoided running in_irq()static void usbnet_bh (unsigned long param){	struct usbnet		*dev = (struct usbnet *) 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:			entry->state = rx_cleanup;			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_running (&dev->net)) {		int	temp = dev->rxq.qlen;		if (temp < RX_QLEN) {			struct urb	*urb;			int		i;			for (i = 0; i < 3 && dev->rxq.qlen < RX_QLEN; i++) {				if ((urb = usb_alloc_urb (0)) != 0)					rx_submit (dev, urb, GFP_ATOMIC);			}			if (temp != dev->rxq.qlen)				devdbg (dev, "rxqlen %d --> %d",						temp, dev->rxq.qlen);			if (dev->rxq.qlen < RX_QLEN)				tasklet_schedule (&dev->bh);		}		if (dev->txq.qlen < TX_QLEN)			netif_wake_queue (&dev->net);	}}/*------------------------------------------------------------------------- * * USB Device Driver support * *-------------------------------------------------------------------------*/ // precondition: never called in_interruptstatic void usbnet_disconnect (struct usb_device *udev, void *ptr){	struct usbnet	*dev = (struct usbnet *) ptr;	devinfo (dev, "unregister usbnet %03d/%03d, %s",		udev->bus->busnum, udev->devnum,		dev->driver_info->description);		unregister_netdev (&dev->net);	mutex_lock (&usbnet_mutex);	mutex_lock (&dev->mutex);	list_del (&dev->dev_list);	mutex_unlock (&usbnet_mutex);	kfree (dev);	usb_dec_dev_use (udev);}/*-------------------------------------------------------------------------*/// precondition: never called in_interruptstatic void *usbnet_probe (struct usb_device *udev, unsigned ifnum,			const struct usb_device_id *prod){	struct usbnet			*dev;	struct net_device 		*net;	struct usb_interface_descriptor	*interface;	struct driver_info		*info;	int				altnum = 0;	info = (struct driver_info *) prod->driver_info;	// sanity check; expect dedicated interface/devices for now.	interface = &udev->actconfig->interface [ifnum].altsetting [altnum];	if (udev->descriptor.bNumConfigurations != 1			|| udev->config[0].bNumInterfaces != 1//			|| interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC			) {		dbg ("Bogus config info");		return 0;	}	// more sanity (unless the device is broken)	if (!(info->flags & FLAG_NO_SETINT)) {		if (usb_set_interface (udev, ifnum, altnum) < 0) {			err ("set_interface failed");			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->driver_info = info;	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 = usbnet_bh;	dev->bh.data = (unsigned long) dev;	// set up network interface records	net = &dev->net;	SET_MODULE_OWNER (net);	net->priv = dev;	strcpy (net->name, "usb%d");	memcpy (net->dev_addr, node_id, sizeof node_id);	// point-to-point link ... we always use Ethernet headers 	// supports win32 interop and the bridge driver.	ether_setup (net);	net->change_mtu = usbnet_change_mtu;	net->get_stats = usbnet_get_stats;	net->hard_start_xmit = usbnet_start_xmit;	net->open = usbnet_open;	net->stop = usbnet_stop;	net->watchdog_timeo = TX_TIMEOUT_JIFFIES;	net->tx_timeout = usbnet_tx_timeout;	register_netdev (&dev->net);	devinfo (dev, "register usbnet %03d/%03d, %s",		udev->bus->busnum, udev->devnum,		dev->driver_info->description);	// ok, it's ready to go.	mutex_lock (&usbnet_mutex);	list_add (&dev->dev_list, &usbnet_list);	mutex_unlock (&dev->mutex);	// start as if the link is up	netif_device_attach (&dev->net);	mutex_unlock (&usbnet_mutex);	return dev;}/*-------------------------------------------------------------------------*//* * chip vendor names won't normally be on the cables, and * may not be on the device. */static const struct usb_device_id	products [] = {#ifdef	CONFIG_USB_AN2720{	USB_DEVICE (0x0547, 0x2720),	// AnchorChips defaults	driver_info:	(unsigned long) &an2720_info,},{	USB_DEVICE (0x0547, 0x2727),	// Xircom PGUNET	driver_info:	(unsigned long) &an2720_info,},#endif#ifdef	CONFIG_USB_BELKIN{	USB_DEVICE (0x050d, 0x0004),	// Belkin	driver_info:	(unsigned long) &belkin_info,}, {	USB_DEVICE (0x056c, 0x8100),	// eTEK	driver_info:	(unsigned long) &belkin_info,}, {	USB_DEVICE (0x0525, 0x9901),	// Advance USBNET (eTEK)	driver_info:	(unsigned long) &belkin_info,},#endif#ifdef	CONFIG_USB_GENESYS{	USB_DEVICE (0x05e3, 0x0502),	// GL620USB-A	driver_info:	(unsigned long) &genelink_info,},#endif#ifdef	CONFIG_USB_LINUXDEV/* * for example, this can be a host side talk-to-PDA driver. * this driver is NOT what runs _inside_ a Linux device !! */{	// 1183 = 0x049F, both used as hex values?	USB_DEVICE (0x049F, 0x505A),	// Compaq "Itsy"	driver_info:	(unsigned long) &linuxdev_info,},#endif#ifdef	CONFIG_USB_NET1080{	USB_DEVICE (0x0525, 0x1080),	// NetChip ref design	driver_info:	(unsigned long) &net1080_info,},{	USB_DEVICE (0x06D0, 0x0622),	// Laplink Gold	driver_info:	(unsigned long) &net1080_info,},#endif#ifdef CONFIG_USB_PL2301{	USB_DEVICE (0x067b, 0x0000),	// PL-2301	driver_info:	(unsigned long) &prolific_info,}, {	USB_DEVICE (0x067b, 0x0001),	// PL-2302	driver_info:	(unsigned long) &prolific_info,},#endif/* KC2190 from www.sepoong.co.kr "InstaNET" */	{ },		// END};MODULE_DEVICE_TABLE (usb, products);static struct usb_driver usbnet_driver = {	name:		"usbnet",	id_table:	products,	probe:		usbnet_probe,	disconnect:	usbnet_disconnect,};/*-------------------------------------------------------------------------*/static int __init usbnet_init (void){	// compiler should optimize this out	if (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data))		BUG ();	get_random_bytes (node_id, sizeof node_id);	node_id [0] &= 0xfe;	// clear multicast bit 	if (usb_register (&usbnet_driver) < 0) 		return -1;	return 0;}module_init (usbnet_init);static void __exit usbnet_exit (void){ 	usb_deregister (&usbnet_driver);}module_exit (usbnet_exit);EXPORT_NO_SYMBOLS;MODULE_AUTHOR ("David Brownell <dbrownell@users.sourceforge.net>");MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (numerous vendors)");MODULE_LICENSE ("GPL");

⌨️ 快捷键说明

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