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

📄 cdcether.c

📁 S3C2440ARM9开发板的USB驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
// Standard routines for kernel Ethernet Device ////////////////////////////////////////////////////////////////////////////////////////////////////////////static struct net_device_stats *CDCEther_netdev_stats( struct net_device *net ){	// Easy enough!	return &((ether_dev_t *)net->priv)->stats;}static int CDCEther_open(struct net_device *net){	ether_dev_t *ether_dev = (ether_dev_t *)net->priv;	int	res;	// Turn on the USB and let the packets flow!!!	if ( (res = enable_net_traffic( ether_dev )) ) {		err("%s can't enable_net_traffic() - %d", __FUNCTION__, res );		return -EIO;	}	/* Prep a receive URB */	FILL_BULK_URB( &ether_dev->rx_urb, ether_dev->usb,			usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),			ether_dev->rx_buff, ether_dev->wMaxSegmentSize,			read_bulk_callback, ether_dev );	/* Put it out there so the device can send us stuff */	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) ) {		/* Hmm...  Okay... */		warn( "%s failed rx_urb %d", __FUNCTION__, res );	}	if (ether_dev->properties & HAVE_NOTIFICATION_ELEMENT) {		/* Arm and submit the interrupt URB */		FILL_INT_URB( &ether_dev->intr_urb,			ether_dev->usb,			usb_rcvintpipe(ether_dev->usb, ether_dev->comm_ep_in),			ether_dev->intr_buff,			8, /* Transfer buffer length */			intr_callback,			ether_dev,			ether_dev->intr_interval);		if ( (res = usb_submit_urb(&ether_dev->intr_urb)) ) {			warn("%s failed intr_urb %d", __FUNCTION__, res );		}	}	// Tell the kernel we are ready to start receiving from it	netif_start_queue( net );		// We are up and running.	ether_dev->flags |= CDC_ETHER_RUNNING;	// Let's get ready to move frames!!!	return 0;}static int CDCEther_close( struct net_device *net ){	ether_dev_t	*ether_dev = net->priv;	// We are no longer running.	ether_dev->flags &= ~CDC_ETHER_RUNNING;		// Tell the kernel to stop sending us stuff	netif_stop_queue( net );		// If we are not already unplugged, turn off USB	// traffic	if ( !(ether_dev->flags & CDC_ETHER_UNPLUG) ) {		disable_net_traffic( ether_dev );	}	// We don't need the URBs anymore.	usb_unlink_urb( &ether_dev->rx_urb );	usb_unlink_urb( &ether_dev->tx_urb );	usb_unlink_urb( &ether_dev->intr_urb );	usb_unlink_urb( &ether_dev->ctrl_urb );	// That's it.  I'm done.	return 0;}static int netdev_ethtool_ioctl(struct net_device *netdev, void *useraddr){	ether_dev_t *ether_dev = netdev->priv;	u32 cmd;	char tmp[40];	if (get_user(cmd, (u32 *)useraddr))		return -EFAULT;	switch (cmd) {	/* get driver info */	case ETHTOOL_GDRVINFO: {	struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};		strncpy(info.driver, SHORT_DRIVER_DESC, ETHTOOL_BUSINFO_LEN);		strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);		sprintf(tmp, "usb%d:%d", ether_dev->usb->bus->busnum, ether_dev->usb->devnum);		strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);		sprintf(tmp, "CDC %x.%x", ((ether_dev->bcdCDC & 0xff00)>>8), (ether_dev->bcdCDC & 0x00ff) );		strncpy(info.fw_version, tmp, ETHTOOL_BUSINFO_LEN);		if (copy_to_user(useraddr, &info, sizeof(info)))			return -EFAULT;		return 0;	}	/* get link status */	case ETHTOOL_GLINK: {		struct ethtool_value edata = {ETHTOOL_GLINK};		edata.data = netif_carrier_ok(netdev);		if (copy_to_user(useraddr, &edata, sizeof(edata)))			return -EFAULT;		return 0;	}	}	dbg("Got unsupported ioctl: %x", cmd);	return -EOPNOTSUPP; /* the ethtool user space tool relies on this */}static int CDCEther_ioctl( struct net_device *net, struct ifreq *rq, int cmd ){	switch(cmd) {	case SIOCETHTOOL:		return netdev_ethtool_ioctl(net, (void *) rq->ifr_data);	default:		return -ENOTTY; /* per ioctl man page */	}}/* Multicast routines */static void CDC_SetEthernetPacketFilter (ether_dev_t *ether_dev){#if 0	struct usb_ctrlrequest *dr = &ether_dev->ctrl_dr;	int res;	dr->bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;	dr->bRequest = SET_ETHERNET_PACKET_FILTER;	dr->wValue = cpu_to_le16(ether_dev->mode_flags);	dr->wIndex = cpu_to_le16((u16)ether_dev->comm_interface);	dr->wLength = 0;	FILL_CONTROL_URB(&ether_dev->ctrl_urb,			ether_dev->usb,			usb_sndctrlpipe(ether_dev->usb, 0),			dr,			NULL,			NULL,			setpktfilter_done,			ether_dev);	if ( (res = usb_submit_urb(&ether_dev->ctrl_urb)) ) {		warn("%s failed submit ctrl_urb %d", __FUNCTION__, res);	}#endif}static void CDCEther_set_multicast( struct net_device *net ){	ether_dev_t *ether_dev = net->priv;	int i;	__u8 *buff;	// Tell the kernel to stop sending us frames while we get this	// all set up.	netif_stop_queue(net);	/* Note: do not reorder, GCC is clever about common statements. */	if (net->flags & IFF_PROMISC) {		/* Unconditionally log net taps. */		dbg( "%s: Promiscuous mode enabled", net->name);		ether_dev->mode_flags = MODE_FLAG_PROMISCUOUS |			MODE_FLAG_ALL_MULTICAST |			MODE_FLAG_DIRECTED |			MODE_FLAG_BROADCAST |			MODE_FLAG_MULTICAST;	} else if (net->mc_count > ether_dev->wNumberMCFilters) {		/* Too many to filter perfectly -- accept all multicasts. */		dbg("%s: too many MC filters for hardware, using allmulti", net->name);		ether_dev->mode_flags = MODE_FLAG_ALL_MULTICAST |			MODE_FLAG_DIRECTED |			MODE_FLAG_BROADCAST |			MODE_FLAG_MULTICAST;	} else if (net->flags & IFF_ALLMULTI) {		/* Filter in software */		dbg("%s: using allmulti", net->name);		ether_dev->mode_flags = MODE_FLAG_ALL_MULTICAST |			MODE_FLAG_DIRECTED |			MODE_FLAG_BROADCAST |			MODE_FLAG_MULTICAST;	} else {		/* do multicast filtering in hardware */		struct dev_mc_list *mclist;		dbg("%s: set multicast filters", net->name);		ether_dev->mode_flags = MODE_FLAG_ALL_MULTICAST |			MODE_FLAG_DIRECTED |			MODE_FLAG_BROADCAST |			MODE_FLAG_MULTICAST;		buff = kmalloc(6 * net->mc_count, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);		for (i = 0, mclist = net->mc_list;			mclist && i < net->mc_count;			i++, mclist = mclist->next) {				memcpy(&mclist->dmi_addr, &buff[i * 6], 6);		}#if 0		usb_control_msg(ether_dev->usb,				usb_sndctrlpipe(ether_dev->usb, 0),				SET_ETHERNET_MULTICAST_FILTER, /* request */				USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, /* request type */				cpu_to_le16(net->mc_count), /* value */				cpu_to_le16((u16)ether_dev->comm_interface), /* index */				buff,				(6* net->mc_count), /* size */				HZ); /* timeout */#endif		kfree(buff);	}	CDC_SetEthernetPacketFilter(ether_dev);	/* Tell the kernel to start giving frames to us again. */	netif_wake_queue(net);}//////////////////////////////////////////////////////////////////////////////// Routines used to parse out the Functional Descriptors ////////////////////////////////////////////////////////////////////////////////////////////////////* Header Descriptor - CDC Spec 5.2.3.1, Table 26 */static int parse_header_functional_descriptor( int *bFunctionLength,                                               int bDescriptorType,                                               int bDescriptorSubtype,                                               unsigned char *data,                                               ether_dev_t *ether_dev,                                               int *requirements ){	/* Check to make sure we haven't seen one of these already. */	if ( (~*requirements) & REQ_HDR_FUNC_DESCR ) {		err( "Multiple Header Functional Descriptors found." );		return -1;	}	/* Check for appropriate length */	if (*bFunctionLength != HEADER_FUNC_DESC_LEN) {		dbg( "Invalid length in Header Functional Descriptor, working around it." );		/* This is a hack to get around a particular device (NO NAMES)		 * It has this function length set to the length of the		 * whole class-specific descriptor */		*bFunctionLength = HEADER_FUNC_DESC_LEN;	}		/* Nothing extremely useful here */	/* We'll keep it for posterity */	ether_dev->bcdCDC = data[0] + (data[1] << 8);	dbg( "Found Header descriptor, CDC version %x.", ether_dev->bcdCDC);	/* We've seen one of these */	*requirements &= ~REQ_HDR_FUNC_DESCR;	/* Success */	return 0;}/* Union Descriptor - CDC Spec 5.2.3.8, Table 33 */static int parse_union_functional_descriptor( int *bFunctionLength,                                               int bDescriptorType,                                               int bDescriptorSubtype,                                              unsigned char *data,                                              ether_dev_t *ether_dev,                                              int *requirements ){	/* Check to make sure we haven't seen one of these already. */	if ( (~*requirements) & REQ_UNION_FUNC_DESCR ) {		err( "Multiple Union Functional Descriptors found." );		return -1;	}	/* Check for appropriate length */	if (*bFunctionLength != UNION_FUNC_DESC_LEN) {		// It is NOT the size we expected.		err( "Invalid length in Union Functional Descriptor." );		return -1;	}		/* Sanity check of sorts */	if (ether_dev->comm_interface != data[0]) {		/* This tells us that we are chasing the wrong comm		 * interface or we are crazy or something else weird. */		if (ether_dev->comm_interface == data[1]) {			dbg( "Probably broken Union descriptor, fudging data interface." );			/* We'll need this in a few microseconds,			 * so if the comm interface was the first slave,			 * then probably the master interface is the data one			 * Just hope for the best */			ether_dev->data_interface = data[0];		} else {			err( "Union Functional Descriptor is broken beyond repair." );			return -1;		}	} else{ /* Descriptor is OK */		ether_dev->data_interface = data[1];	}	/* We've seen one of these */	*requirements &= ~REQ_UNION_FUNC_DESCR;	/* Success */	return 0;}/* Ethernet Descriptor - CDC Spec 5.2.3.16, Table 41 */static int parse_ethernet_functional_descriptor( int *bFunctionLength,                                                 int bDescriptorType,                                                  int bDescriptorSubtype,                                                 unsigned char *data,                                                 ether_dev_t *ether_dev,                                                 int *requirements ){	//* Check to make sure we haven't seen one of these already. */	if ( (~*requirements) & REQ_ETH_FUNC_DESCR ) {		err( "Multiple Ethernet Functional Descriptors found." );		return -1;	}		/* Check for appropriate length */	if (*bFunctionLength != ETHERNET_FUNC_DESC_LEN) {		err( "Invalid length in Ethernet Networking Functional Descriptor." );		return -1;	}	/* Lots of goodies from this one.  They are all important. */	ether_dev->iMACAddress = data[0];	ether_dev->bmEthernetStatistics = data[1] + (data[2] << 8) + (data[3] << 16) + (data[4] << 24);	ether_dev->wMaxSegmentSize = data[5] + (data[6] << 8);	ether_dev->wNumberMCFilters = (data[7] + (data[8] << 8));	if (ether_dev->wNumberMCFilters & (1 << 15)) {		ether_dev->properties |= PERFECT_FILTERING;		dbg("Perfect filtering support");	} else {		dbg("Imperfect filtering support - need sw hashing");	}	if (0 == (ether_dev->wNumberMCFilters & (0x7f))) {		ether_dev->properties |= NO_SET_MULTICAST;		dbg("Can't use SetEthernetMulticastFilters request");	}	if (ether_dev->wNumberMCFilters > multicast_filter_limit) {		ether_dev->wNumberMCFilters = multicast_filter_limit;	}	ether_dev->bNumberPowerFilters = data[9];		/* We've seen one of these */	*requirements &= ~REQ_ETH_FUNC_DESCR;	/* Success */	return 0;}static int parse_protocol_unit_functional_descriptor( int *bFunctionLength,                                                       int bDescriptorType,                                                       int bDescriptorSubtype,                                                      unsigned char *data,                                                      ether_dev_t *ether_dev,                                                      int *requirements ){	/* There should only be one type if we are sane */	if (bDescriptorType != CS_INTERFACE) {

⌨️ 快捷键说明

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