📄 cdcether.c
字号:
// 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( ðer_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(ðer_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( ðer_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( ðer_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(ðer_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 + -