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

📄 usbnet.c

📁 S3C2440ARM9开发板的USB驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	return -EOPNOTSUPP;}static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd){	switch (cmd) {	case SIOCETHTOOL:		return usbnet_ethtool_ioctl (net, (void *)rq->ifr_data);	default:		return -EOPNOTSUPP;	}}/*-------------------------------------------------------------------------*//* work that cannot be done in interrupt context uses keventd. * * NOTE:  "uhci" and "usb-uhci" may have trouble with this since they don't * queue control transfers to individual devices, and other threads could * trigger control requests concurrently.  hope that's rare. */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->txq);		status = usb_clear_halt (dev->udev,			usb_sndbulkpipe (dev->udev, dev->driver_info->out));		if (status < 0)			err ("%s: can't clear tx halt, status %d",				dev->net.name, status);		else {			clear_bit (EVENT_TX_HALT, &dev->flags);			netif_wake_queue (&dev->net);		}	}	if (test_bit (EVENT_RX_HALT, &dev->flags)) {		unlink_urbs (&dev->rxq);		status = usb_clear_halt (dev->udev,			usb_rcvbulkpipe (dev->udev, dev->driver_info->in));		if (status < 0)			err ("%s: can't clear rx halt, status %d",				dev->net.name, 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 = 0;		if (netif_running (&dev->net))			urb = ALLOC_URB (0, GFP_KERNEL);		else			clear_bit (EVENT_RX_MEMORY, &dev->flags);		if (urb != 0) {			clear_bit (EVENT_RX_MEMORY, &dev->flags);			rx_submit (dev, urb, GFP_KERNEL);			tasklet_schedule (&dev->bh);		}	}	if (dev->flags)		dbg ("%s: kevent done, flags = 0x%lx",			dev->net.name, dev->flags);}/*-------------------------------------------------------------------------*/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 == -EPIPE)		defer_kevent (dev, EVENT_TX_HALT);	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 */	// 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) {			dbg ("can't tx_fixup skb");			goto drop;		}	}	if (!(urb = ALLOC_URB (0, GFP_ATOMIC))) {		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;	// 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 */	switch ((retval = SUBMIT_URB (urb, GFP_ATOMIC))) {	case -EPIPE:		netif_stop_queue (net);		defer_kevent (dev, EVENT_TX_HALT);		break;	default:		dbg ("%s tx: submit urb err %d", net->name, retval);		break;	case 0:		net->trans_start = jiffies;		__skb_queue_tail (&dev->txq, skb);		if (dev->txq.qlen >= TX_QLEN)			netif_stop_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)			&& !test_bit (EVENT_RX_HALT, &dev->flags)) {		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 = ALLOC_URB (0, GFP_ATOMIC)) != 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 usb-%s-%s, %s",		udev->bus->bus_name, udev->devpath,		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);	// assuming we used keventd, it must quiesce too	flush_scheduled_tasks ();	kfree (dev);	usb_put_dev (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;	struct usb_endpoint_descriptor  *endpoint;	int                             i;	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;		}	}	/* check out the endpoints */	for (i = 0; i < interface->bNumEndpoints; ++i) {		endpoint = &interface->endpoint[i];		if ((endpoint->bEndpointAddress & 0x80) &&		    ((endpoint->bmAttributes & 3) == 0x02)) {			/* we found a bulk in endpoint */			dbg("found bulk in");			info->in=endpoint->bEndpointAddress & 0x7f;		}		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&		    ((endpoint->bmAttributes & 3) == 0x02)) {			/* we found a bulk out endpoint */			dbg("found bulk out");			info->out=endpoint->bEndpointAddress & 0x7f;		}			}	// 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_get_dev (udev);	dev->udev = udev;	dev->driver_info = info;	dev->msg_level = msg_level;	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;	INIT_TQUEUE (&dev->kevent, kevent, 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;	net->do_ioctl = usbnet_ioctl;	register_netdev (&dev->net);	devinfo (dev, "register usbnet usb-%s-%s, %s",		udev->bus->bus_name, udev->devpath,		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_EPSON2888{	USB_DEVICE (0x0525, 0x2888),	// EPSON USB client	driver_info:	(unsigned long) &epson2888_info,},#endif#ifdef	CONFIG_USB_GENESYS{	USB_DEVICE (0x05e3, 0x0502),	// GL620USB-A	.driver_info =	(unsigned long) &genelink_info,},	/* NOT: USB_DEVICE (0x05e3, 0x0501),	// GL620USB	 * that's half duplex, not currently supported	 */#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,}, {	USB_DEVICE (0x0E7E, 0x1001),	// G.Mate "Yopy"	.driver_info =	(unsigned long) &linuxdev_info,},	// NOTE:  the Sharp Zaurus uses a modified version of	// this driver, which is not interoperable with this.#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 =		driver_name,	.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	node_id [0] |= 0x02;    // set local assignment bit (IEEE802) 	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 + -