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

📄 cdcether.c

📁 S3C2440ARM9开发板的USB驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
// 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/module.h>#include <linux/ethtool.h>#include <asm/uaccess.h>#define DEBUG#include <linux/usb.h>#include "CDCEther.h"#define SHORT_DRIVER_DESC "CDC Ethernet Class"#define DRIVER_VERSION "0.98.6"static const char *version = __FILE__ ": " DRIVER_VERSION " 7 Jan 2002 Brad Hards and another";// We only try to claim CDC Ethernet model devices */static struct usb_device_id CDCEther_ids[] = {	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 6, 0) },	{ }};/* * 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;	switch ( urb->status ) {		case USB_ST_NOERROR:			break;		case USB_ST_URB_KILLED:			return;		default:			dbg("rx status %d", urb->status);	}	// 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("%s failed submit rx_urb %d", __FUNCTION__, 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 ) {		dbg("%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 );}#if 0static void setpktfilter_done( struct urb *urb ){	ether_dev_t *ether_dev = urb->context;	struct net_device *net;	if ( !ether_dev )		return;	dbg("got ctrl callback for setting packet filter");	switch ( urb->status ) {		case USB_ST_NOERROR:			break;		case USB_ST_URB_KILLED:			return;		default:			dbg("intr status %d", urb->status);	}}#endif static void intr_callback( struct urb *urb ){	ether_dev_t *ether_dev = urb->context;	struct net_device *net;	__u8	*d;	if ( !ether_dev )		return;	dbg("got intr callback");	switch ( urb->status ) {		case USB_ST_NOERROR:			break;		case USB_ST_URB_KILLED:			return;		default:			dbg("intr status %d", urb->status);	}	d = urb->transfer_buffer;	dbg("d: %x", d[0]);	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) )			netif_carrier_off(net);	}}//////////////////////////////////////////////////////////////////////////////// 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;}//////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

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