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

📄 cdcether.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
// Portions of this file taken from // Petko Manolov - Petkan (petkan@dce.bg)// from his driver pegasus.c/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/sched.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/usb.h>#include <linux/module.h>#include "CDCEther.h"static const char *version = __FILE__ ": v0.98.5 22 Sep 2001 Brad Hards and another";/* Take any CDC device, and sort it out in probe() */static struct usb_device_id CDCEther_ids[] = {	{ USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },	{ } /* Terminating null entry */};/*  * module parameter that provides an alternate upper limit on the  * number of multicast filters we use, with a default to use all * the filters available to us. Note that the actual number used * is the lesser of this parameter and the number returned in the * descriptor for the particular device. See Table 41 of the CDC * spec for more info on the descriptor limit. */static int multicast_filter_limit = 32767;//////////////////////////////////////////////////////////////////////////////// Callback routines from USB device ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////static void read_bulk_callback( struct urb *urb ){	ether_dev_t *ether_dev = urb->context;	struct net_device *net;	int count = urb->actual_length, res;	struct sk_buff	*skb;	// Sanity check 	if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) {		dbg("BULK IN callback but driver is not active!");		return;	}	net = ether_dev->net;	if ( !netif_device_present(net) ) {		// Somebody killed our network interface...		return;	}	if ( ether_dev->flags & CDC_ETHER_RX_BUSY ) {		// Are we already trying to receive a frame???		ether_dev->stats.rx_errors++;		dbg("ether_dev Rx busy");		return;	}	// We are busy, leave us alone!	ether_dev->flags |= CDC_ETHER_RX_BUSY;	switch ( urb->status ) {		case USB_ST_NOERROR:			break;		case USB_ST_NORESPONSE:			dbg( "no repsonse in BULK IN" );			ether_dev->flags &= ~CDC_ETHER_RX_BUSY;			break;		default:			dbg( "%s: RX status %d", net->name, urb->status );			goto goon;	}	// Check to make sure we got some data...	if ( !count ) {		// We got no data!!!		goto goon;	}	// Tell the kernel we want some memory	if ( !(skb = dev_alloc_skb(count)) ) {		// We got no receive buffer.		goto goon;	}	// Here's where it came from	skb->dev = net;		// Now we copy it over	eth_copy_and_sum(skb, ether_dev->rx_buff, count, 0);		// Not sure	skb_put(skb, count);	// Not sure here either	skb->protocol = eth_type_trans(skb, net);		// Ship it off to the kernel	netif_rx(skb);		// update out statistics	ether_dev->stats.rx_packets++;	ether_dev->stats.rx_bytes += count;goon:	// Prep the USB to wait for another frame	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 );				// Give this to the USB subsystem so it can tell us 	// when more data arrives.	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) ) {		warn( __FUNCTION__ " failed submint rx_urb %d", res);	}		// We are no longer busy, show us the frames!!!	ether_dev->flags &= ~CDC_ETHER_RX_BUSY;}static void write_bulk_callback( struct urb *urb ){	ether_dev_t *ether_dev = urb->context;	// Sanity check	if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) {		// We are insane!!!		err( "write_bulk_callback: device not running" );		return;	}	// Do we still have a valid kernel network device?	if ( !netif_device_present(ether_dev->net) ) {		// Someone killed our network interface.		err( "write_bulk_callback: net device not present" );		return;	}	// Hmm...  What on Earth could have happened???	if ( urb->status ) {		info("%s: TX status %d", ether_dev->net->name, urb->status);	}	// Update the network interface and tell it we are	// ready for another frame	ether_dev->net->trans_start = jiffies;	netif_wake_queue( ether_dev->net );}//static void intr_callback( struct urb *urb )//{//	ether_dev_t *ether_dev = urb->context;//	struct net_device *net;//	__u8	*d;////	if ( !ether_dev )//		return;//		//	switch ( urb->status ) {//		case USB_ST_NOERROR://			break;//		case USB_ST_URB_KILLED://			return;//		default://			info("intr status %d", urb->status);//	}////	d = urb->transfer_buffer;//	net = ether_dev->net;//	if ( d[0] & 0xfc ) {//		ether_dev->stats.tx_errors++;//		if ( d[0] & TX_UNDERRUN )//			ether_dev->stats.tx_fifo_errors++;//		if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )//			ether_dev->stats.tx_aborted_errors++;//		if ( d[0] & LATE_COL )//			ether_dev->stats.tx_window_errors++;//		if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )//			ether_dev->stats.tx_carrier_errors++;//	}//}//////////////////////////////////////////////////////////////////////////////// Routines for turning net traffic on and off on the USB side /////////////////////////////////////////////////////////////////////////////////////////////static inline int enable_net_traffic( ether_dev_t *ether_dev ){	struct usb_device *usb = ether_dev->usb;	// Here would be the time to set the data interface to the configuration where	// it has two endpoints that use a protocol we can understand.	if (usb_set_interface( usb, 	                        ether_dev->data_bInterfaceNumber, 	                        ether_dev->data_bAlternateSetting_with_traffic ) )  {		err("usb_set_interface() failed" );		err("Attempted to set interface %d", ether_dev->data_bInterfaceNumber);		err("To alternate setting       %d", ether_dev->data_bAlternateSetting_with_traffic);		return -1;	}	return 0;}static inline void disable_net_traffic( ether_dev_t *ether_dev ){	// The thing to do is to set the data interface to the alternate setting that has	// no endpoints.  This is what the spec suggests.	if (ether_dev->data_interface_altset_num_without_traffic >= 0 ) {		if (usb_set_interface( ether_dev->usb, 		                        ether_dev->data_bInterfaceNumber, 		                        ether_dev->data_bAlternateSetting_without_traffic ) ) 	{			err("usb_set_interface() failed");		}	} else {		// Some devices just may not support this...		warn("No way to disable net traffic");	}}//////////////////////////////////////////////////////////////////////////////// Callback routines for kernel Ethernet Device ////////////////////////////////////////////////////////////////////////////////////////////////////////////static void CDCEther_tx_timeout( struct net_device *net ){	ether_dev_t *ether_dev = net->priv;	// Sanity check	if ( !ether_dev ) {		// Seems to be a case of insanity here		return;	}	// Tell syslog we are hosed.	warn("%s: Tx timed out.", net->name);		// Tear the waiting frame off the list	ether_dev->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;	usb_unlink_urb( &ether_dev->tx_urb );		// Update statistics	ether_dev->stats.tx_errors++;}static int CDCEther_start_xmit( struct sk_buff *skb, struct net_device *net ){	ether_dev_t	*ether_dev = net->priv;	int 	count;	int 	res;	// If we are told to transmit an ethernet frame that fits EXACTLY 	// into an integer number of USB packets, we force it to send one 	// more byte so the device will get a runt USB packet signalling the 	// end of the ethernet frame	if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) {		// It was not an exact multiple		// no need to add anything extra		count = skb->len;	} else {		// Add one to make it NOT an exact multiple		count = skb->len + 1;	}	// Tell the kernel, "No more frames 'til we are done	// with this one.'	netif_stop_queue( net );	// Copy it from kernel memory to OUR memory	memcpy(ether_dev->tx_buff, skb->data, skb->len);	// Fill in the URB for shipping it out.	FILL_BULK_URB( &ether_dev->tx_urb, ether_dev->usb,			usb_sndbulkpipe(ether_dev->usb, ether_dev->data_ep_out),			ether_dev->tx_buff, ether_dev->wMaxSegmentSize, 			write_bulk_callback, ether_dev );	// Tell the URB how much it will be transporting today	ether_dev->tx_urb.transfer_buffer_length = count;		// Send the URB on its merry way.	if ((res = usb_submit_urb(&ether_dev->tx_urb)))  {		// Hmm...  It didn't go. Tell someone...		warn("failed tx_urb %d", res);		// update some stats...		ether_dev->stats.tx_errors++;		// and tell the kernel to give us another.		// Maybe we'll get it right next time.		netif_start_queue( net );	} else {		// Okay, it went out.		// Update statistics		ether_dev->stats.tx_packets++;		ether_dev->stats.tx_bytes += skb->len;		// And tell the kernel when the last transmit occurred.		net->trans_start = jiffies;	}	// We are done with the kernel's memory	dev_kfree_skb(skb);	// We are done here.	return 0;}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( __FUNCTION__ "can't enable_net_traffic() - %d", 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( __FUNCTION__ " failed rx_urb %d", 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 );		// That's it.  I'm done.	return 0;}static int CDCEther_ioctl( struct net_device *net, struct ifreq *rq, int cmd ){	//__u16 *data = (__u16 *)&rq->ifr_data;	//ether_dev_t	*ether_dev = net->priv;	// No support here yet.	// Do we need support???	switch(cmd) {		case SIOCDEVPRIVATE:			return -EOPNOTSUPP;		case SIOCDEVPRIVATE+1:			return -EOPNOTSUPP;		case SIOCDEVPRIVATE+2:			//return 0;			return -EOPNOTSUPP;		default:			return -EOPNOTSUPP;	}}static void CDC_SetEthernetPacketFilter (ether_dev_t *ether_dev){	usb_control_msg(ether_dev->usb,			usb_sndctrlpipe(ether_dev->usb, 0),			SET_ETHERNET_PACKET_FILTER, /* request */			USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, /* request type */			cpu_to_le16(ether_dev->mode_flags), /* value */			cpu_to_le16((u16)ether_dev->comm_interface), /* index */			NULL,			0, /* size */			HZ); /* timeout */}	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. */                info( "%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) {

⌨️ 快捷键说明

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