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

📄 usbnet.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	struct usb_interface	*control;	struct usb_interface	*data;};static struct usb_driver usbnet_driver;/* * probes control interface, claims data interface, collects the bulk * endpoints, activates data interface (if needed), maybe sets MTU. * all pure cdc, except for certain firmware workarounds. */static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf){	u8				*buf = intf->cur_altsetting->extra;	int				len = intf->cur_altsetting->extralen;	struct usb_interface_descriptor	*d;	struct cdc_state		*info = (void *) &dev->data;	int				status;	int				rndis;	if (sizeof dev->data < sizeof *info)		return -EDOM;	/* expect strict spec conformance for the descriptors, but	 * cope with firmware which stores them in the wrong place	 */	if (len == 0 && dev->udev->actconfig->extralen) {		/* Motorola SB4100 (and others: Brad Hards says it's		 * from a Broadcom design) put CDC descriptors here		 */		buf = dev->udev->actconfig->extra;		len = dev->udev->actconfig->extralen;		if (len)			dev_dbg (&intf->dev,				"CDC descriptors on config\n");	}	/* this assumes that if there's a non-RNDIS vendor variant	 * of cdc-acm, it'll fail RNDIS requests cleanly.	 */	rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);	memset (info, 0, sizeof *info);	info->control = intf;	while (len > 3) {		if (buf [1] != USB_DT_CS_INTERFACE)			goto next_desc;		/* use bDescriptorSubType to identify the CDC descriptors.		 * We expect devices with CDC header and union descriptors.		 * For CDC Ethernet we need the ethernet descriptor.		 * For RNDIS, ignore two (pointless) CDC modem descriptors		 * in favor of a complicated OID-based RPC scheme doing what		 * CDC Ethernet achieves with a simple descriptor.		 */		switch (buf [2]) {		case 0x00:		/* Header, mostly useless */			if (info->header) {				dev_dbg (&intf->dev, "extra CDC header\n");				goto bad_desc;			}			info->header = (void *) buf;			if (info->header->bLength != sizeof *info->header) {				dev_dbg (&intf->dev, "CDC header len %u\n",					info->header->bLength);				goto bad_desc;			}			break;		case 0x06:		/* Union (groups interfaces) */			if (info->u) {				dev_dbg (&intf->dev, "extra CDC union\n");				goto bad_desc;			}			info->u = (void *) buf;			if (info->u->bLength != sizeof *info->u) {				dev_dbg (&intf->dev, "CDC union len %u\n",					info->u->bLength);				goto bad_desc;			}			/* we need a master/control interface (what we're			 * probed with) and a slave/data interface; union			 * descriptors sort this all out.			 */			info->control = usb_ifnum_to_if(dev->udev,						info->u->bMasterInterface0);			info->data = usb_ifnum_to_if(dev->udev,						info->u->bSlaveInterface0);			if (!info->control || !info->data) {				dev_dbg (&intf->dev,					"master #%u/%p slave #%u/%p\n",					info->u->bMasterInterface0,					info->control,					info->u->bSlaveInterface0,					info->data);				goto bad_desc;			}			if (info->control != intf) {				dev_dbg (&intf->dev, "bogus CDC Union\n");				/* Ambit USB Cable Modem (and maybe others)				 * interchanges master and slave interface.				 */				if (info->data == intf) {					info->data = info->control;					info->control = intf;				} else					goto bad_desc;			}			/* a data interface altsetting does the real i/o */			d = &info->data->cur_altsetting->desc;			if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {				dev_dbg (&intf->dev, "slave class %u\n",					d->bInterfaceClass);				goto bad_desc;			}			break;		case 0x0F:		/* Ethernet Networking */			if (info->ether) {				dev_dbg (&intf->dev, "extra CDC ether\n");				goto bad_desc;			}			info->ether = (void *) buf;			if (info->ether->bLength != sizeof *info->ether) {				dev_dbg (&intf->dev, "CDC ether len %u\n",					info->u->bLength);				goto bad_desc;			}			dev->net->mtu = le16_to_cpup (						&info->ether->wMaxSegmentSize)					- ETH_HLEN;			/* because of Zaurus, we may be ignoring the host			 * side link address we were given.			 */			break;		}next_desc:		len -= buf [0];	/* bLength */		buf += buf [0];	}	if (!info->header || !info->u || (!rndis && !info->ether)) {		dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n",			info->header ? "" : "header ",			info->u ? "" : "union ",			info->ether ? "" : "ether ");		goto bad_desc;	}	/* claim data interface and set it up ... with side effects.	 * network traffic can't flow until an altsetting is enabled.	 */	status = usb_driver_claim_interface (&usbnet_driver, info->data, dev);	if (status < 0)		return status;	status = get_endpoints (dev, info->data);	if (status < 0) {		/* ensure immediate exit from usbnet_disconnect */		usb_set_intfdata(info->data, NULL);		usb_driver_release_interface (&usbnet_driver, info->data);		return status;	}	return 0;bad_desc:	dev_info (&dev->udev->dev, "bad CDC descriptors\n");	return -ENODEV;}static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf){	struct cdc_state		*info = (void *) &dev->data;	/* disconnect master --> disconnect slave */	if (intf == info->control && info->data) {		/* ensure immediate exit from usbnet_disconnect */		usb_set_intfdata(info->data, NULL);		usb_driver_release_interface (&usbnet_driver, info->data);		info->data = NULL;	}	/* and vice versa (just in case) */	else if (intf == info->data && info->control) {		/* ensure immediate exit from usbnet_disconnect */		usb_set_intfdata(info->control, NULL);		usb_driver_release_interface (&usbnet_driver, info->control);		info->control = NULL;	}}#endif	/* NEED_GENERIC_CDC */#ifdef	CONFIG_USB_CDCETHER#define	HAVE_HARDWARE/*------------------------------------------------------------------------- * * Communications Device Class, Ethernet Control model *  * Takes two interfaces.  The DATA interface is inactive till an altsetting * is selected.  Configuration data includes class descriptors. * * This should interop with whatever the 2.4 "CDCEther.c" driver * (by Brad Hards) talked with. * *-------------------------------------------------------------------------*/#include <linux/ctype.h>static u8 nibble (unsigned char c){	if (likely (isdigit (c)))		return c - '0';	c = toupper (c);	if (likely (isxdigit (c)))		return 10 + c - 'A';	return 0;}static inline intget_ethernet_addr (struct usbnet *dev, struct ether_desc *e){	int 		tmp, i;	unsigned char	buf [13];	tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf);	if (tmp != 12) {		dev_dbg (&dev->udev->dev,			"bad MAC string %d fetch, %d\n", e->iMACAddress, tmp);		if (tmp >= 0)			tmp = -EINVAL;		return tmp;	}	for (i = tmp = 0; i < 6; i++, tmp += 2)		dev->net->dev_addr [i] =			 (nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]);	return 0;}static int cdc_bind (struct usbnet *dev, struct usb_interface *intf){	int				status;	struct cdc_state		*info = (void *) &dev->data;	status = generic_cdc_bind (dev, intf);	if (status < 0)		return status;	status = get_ethernet_addr (dev, info->ether);	if (status < 0) {		usb_set_intfdata(info->data, NULL);		usb_driver_release_interface (&usbnet_driver, info->data);		return status;	}	/* FIXME cdc-ether has some multicast code too, though it complains	 * in routine cases.  info->ether describes the multicast support.	 */	return 0;}static const struct driver_info	cdc_info = {	.description =	"CDC Ethernet Device",	.flags =	FLAG_ETHER,	// .check_connect = cdc_check_connect,	.bind =		cdc_bind,	.unbind =	cdc_unbind,};#endif	/* CONFIG_USB_CDCETHER */#ifdef	CONFIG_USB_EPSON2888#define	HAVE_HARDWARE/*------------------------------------------------------------------------- * * EPSON USB clients * * This is the same idea as Linux PDAs (below) except the firmware in the * device might not be Tux-powered.  Epson provides reference firmware that * implements this interface.  Product developers can reuse or modify that * code, such as by using their own product and vendor codes. * * Support was from Juro Bystricky <bystricky.juro@erd.epson.com> * *-------------------------------------------------------------------------*/static const struct driver_info	epson2888_info = {	.description =	"Epson USB Device",	.check_connect = always_connected,	.in = 4, .out = 3,};#endif	/* CONFIG_USB_EPSON2888 */#ifdef CONFIG_USB_GENESYS#define	HAVE_HARDWARE/*------------------------------------------------------------------------- * * GeneSys GL620USB-A (www.genesyslogic.com.tw) * * ... should partially interop with the Win32 driver for this hardware * The GeneSys docs imply there's some NDIS issue motivating this framing. * * Some info from GeneSys: *  - GL620USB-A is full duplex; GL620USB is only half duplex for bulk. *    (Some cables, like the BAFO-100c, use the half duplex version.) *  - For the full duplex model, the low bit of the version code says *    which side is which ("left/right"). *  - For the half duplex type, a control/interrupt handshake settles *    the transfer direction.  (That's disabled here, partially coded.) *    A control URB would block until other side writes an interrupt. * * Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw> * and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>. * *-------------------------------------------------------------------------*/// control msg write command#define GENELINK_CONNECT_WRITE			0xF0// interrupt pipe index#define GENELINK_INTERRUPT_PIPE			0x03// interrupt read buffer size#define INTERRUPT_BUFSIZE			0x08// interrupt pipe interval value#define GENELINK_INTERRUPT_INTERVAL		0x10// max transmit packet number per transmit#define GL_MAX_TRANSMIT_PACKETS			32// max packet length#define GL_MAX_PACKET_LEN			1514// max receive buffer size #define GL_RCV_BUF_SIZE		\	(((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)struct gl_packet {	u32		packet_length;	char		packet_data [1];};struct gl_header {	u32			packet_count;	struct gl_packet	packets;};#ifdef	GENELINK_ACK// FIXME:  this code is incomplete, not debugged; it doesn't// handle interrupts correctly.  interrupts should be generic// code like all other device I/O, anyway.struct gl_priv { 	struct urb	*irq_urb;	char		irq_buf [INTERRUPT_BUFSIZE];};static inline int gl_control_write (struct usbnet *dev, u8 request, u16 value){	int retval;	retval = usb_control_msg (dev->udev,		      usb_sndctrlpipe (dev->udev, 0),		      request,		      USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,		      value, 		      0,			// index		      0,			// data buffer		      0,			// size		      CONTROL_TIMEOUT_JIFFIES);	return retval;}static void gl_interrupt_complete (struct urb *urb, struct pt_regs *regs){	int status = urb->status;		switch (status) {	case 0:		/* success */		break;	case -ECONNRESET:	case -ENOENT:	case -ESHUTDOWN:		/* this urb is terminated, clean up */		dbg("%s - urb shutting down with status: %d",				__FUNCTION__, status);		return;	default:		dbg("%s - nonzero urb status received: %d",				__FUNCTION__, urb->status);	}	status = usb_submit_urb (urb, GFP_ATOMIC);	if (status)		err ("%s - usb_submit_urb failed with result %d",		     __FUNCTION__, status);}static int gl_interrupt_read (struct usbnet *dev){	struct gl_priv	*priv = dev->priv_data;	int		retval;	// issue usb interrupt read	if (priv && priv->irq_urb) {		// submit urb		if ((retval = usb_submit_urb (priv->irq_urb, GFP_KERNEL)) != 0)			dbg ("gl_interrupt_read: submit fail - %X...", retval);		else			dbg ("gl_interrupt_read: submit success...");	}	return 0;}// check whether another side is connectedstatic int genelink_check_connect (struct usbnet *dev){	int			retval;	dbg ("genelink_check_connect...");	// detect whether another side is connected	if ((retval = gl_control_write (dev, GENELINK_CONNECT_WRITE, 0)) != 0) {		dbg ("%s: genelink_check_connect write fail - %X",			dev->net->name, retval);		return retval;	}	// usb interrupt read to ack another side 	if ((retval = gl_interrupt_read (dev)) != 0) {		dbg ("%s: genelink_check_connect read fail - %X",			dev->net->name, retval);		return retval;	}	dbg ("%s: genelink_check_connect read success", dev->net->name);	return 0;}// allocate and initialize the private data for genelinkstatic int genelink_init (struct usbnet *dev){	struct gl_priv *priv;	// allocate the private data structure	if ((priv = kmalloc (sizeof *priv, GFP_KERNEL)) == 0) {		dbg ("%s: cannot allocate private data per device",			dev->net->name);		return -ENOMEM;	}	// allocate irq urb	if ((priv->irq_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) {		dbg ("%s: cannot allocate private irq urb per device",			dev->net->name);		kfree (priv);		return -ENOMEM;	}	// fill irq urb	usb_fill_int_urb (priv->irq_urb, dev->udev,		usb_rcvintpipe (dev->udev, GENELINK_INTERRUPT_PIPE),		priv->irq_buf, INTERRUPT_BUFSIZE,		gl_interrupt_complete, 0,		GENELINK_INTERRUPT_INTERVAL);	// set private data pointer	dev->priv_data = priv;

⌨️ 快捷键说明

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