📄 ecos_usbeth.c
字号:
//==========================================================================//// ecos_usbeth.c//// Linux device driver for eCos-based USB ethernet peripherals.////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.//// eCos 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 or (at your option) any later version.//// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN#### //// Author(s): bartv// Contributors: bartv// Date: 2000-11-12////####DESCRIPTIONEND####//==========================================================================#include <linux/module.h>#include <linux/init.h>#include <linux/usb.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#ifdef MODULEMODULE_AUTHOR("Bart Veer <bartv@redhat.com>");MODULE_DESCRIPTION("USB ethernet driver for eCos-based peripherals");#endif// This array identifies specific implementations of eCos USB-ethernet// devices. All implementations should add their vendor and device// details.typedef struct ecos_usbeth_impl { const char* name; __u16 vendor; __u16 id;} ecos_usbeth_impl;const static ecos_usbeth_impl ecos_usbeth_implementations[] = { { "eCos ether", 0x4242, 0x4242 }, { (const char*) 0, 0, 0 }};// Constants. These have to be kept in sync with the target-side// code.#define ECOS_USBETH_MAXTU 1516#define ECOS_USBETH_MAX_CONTROL_TU 8#define ECOS_USBETH_CONTROL_GET_MAC_ADDRESS 0x01#define ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE 0x02// The main data structure. It keeps track of both the USB// and network side of things, and provides buffers for// the various operations.//// NOTE: currently this driver only supports a single// plugged-in device. Theoretically multiple eCos-based// USB ethernet devices could be plugged in to a single// host and each one would require an ecos_usbeth// structure.typedef struct ecos_usbeth { spinlock_t usb_lock; int target_promiscuous; struct usb_device* usb_dev; struct net_device* net_dev; struct net_device_stats stats; struct urb rx_urb; struct urb tx_urb; unsigned char rx_buffer[ECOS_USBETH_MAXTU]; unsigned char tx_buffer[ECOS_USBETH_MAXTU];} ecos_usbeth;// open()// Invoked by the TCP/IP stack when the interface is brought up.// This just starts a receive operation.static intecos_usbeth_open(struct net_device* net){ ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; int res; netif_start_queue(net); res = usb_submit_urb(&(usbeth->rx_urb)); if (0 != res) { printk("ecos_usbeth: failed to start USB receives, %d\n", res); } MOD_INC_USE_COUNT; return 0;}// close()// Invoked by the TCP/IP stack when the interface is taken down.// Any active USB operations need to be cancelled. During// a disconnect this may get called twice, once for the// disconnect and once for the network interface being// brought down.static intecos_usbeth_close(struct net_device* net){ ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; if (0 != netif_running(net)) { netif_stop_queue(net); net->start = 0; if (-EINPROGRESS == usbeth->rx_urb.status) { usb_unlink_urb(&(usbeth->rx_urb)); } if (-EINPROGRESS == usbeth->tx_urb.status) { usb_unlink_urb(&(usbeth->tx_urb)); } MOD_DEC_USE_COUNT; } return 0;}// Reception.// probe() fills in an rx_urb. When the net device is brought up// the urb is activated, and this callback gets run for incoming// data.static voidecos_usbeth_rx_callback(struct urb* urb){ ecos_usbeth* usbeth = (ecos_usbeth*) urb->context; struct net_device* net = usbeth->net_dev; struct sk_buff* skb; int len; int res; if (0 != urb->status) { // This happens numerous times during a disconnect. Do not // issue a warning, but do clear the status field or things // get confused when resubmitting. // // Some host hardware does not distinguish between CRC errors // (very rare) and timeouts (perfectly normal). Do not // increment the error count if it might have been a timeout. if (USB_ST_CRC != urb->status) { usbeth->stats.rx_errors++; } urb->status = 0; } else if (2 > urb->actual_length) { // With some hardware the target may have to send a bogus // first packet. Just ignore those. } else { len = usbeth->rx_buffer[0] + (usbeth->rx_buffer[1] << 8); if (len > (urb->actual_length - 2)) { usbeth->stats.rx_errors++; usbeth->stats.rx_length_errors++; printk("ecos_usbeth: warning, packet size mismatch, got %d bytes, expected %d\n", urb->actual_length, len); } else { skb = dev_alloc_skb(len + 2); if ((struct sk_buff*)0 == skb) { printk("ecos_usbeth: failed to alloc skb, dropping packet\n"); usbeth->stats.rx_dropped++; } else {#if 0 { int i; printk("--------------------------------------------------------------\n"); printk("ecos_usbeth RX: total size %d\n", len); for (i = 0; (i < len) && (i < 128); i+= 8) { printk("rx %x %x %x %x %x %x %x %x\n", usbeth->rx_buffer[i+0], usbeth->rx_buffer[i+1], usbeth->rx_buffer[i+2], usbeth->rx_buffer[i+3], usbeth->rx_buffer[i+4], usbeth->rx_buffer[i+5], usbeth->rx_buffer[i+6], usbeth->rx_buffer[i+7]); } printk("--------------------------------------------------------------\n"); }#endif skb->dev = net; eth_copy_and_sum(skb, &(usbeth->rx_buffer[2]), len, 0); skb_put(skb, len); skb->protocol = eth_type_trans(skb, net); netif_rx(skb); usbeth->stats.rx_packets++; usbeth->stats.rx_bytes += len; } } } if (0 != netif_running(net)) { res = usb_submit_urb(&(usbeth->rx_urb)); if (0 != res) { printk("ecos_usbeth: failed to restart USB receives after packet, %d\n", res); } }}// start_tx().// Transmit a single packet. The relevant USB protocol requires a// 2-byte length field at the start, the incoming buffer has no space// for this, and the URB API does not support any form of// scatter/gather. Therefore unfortunately the whole packet has to be// copied. The callback function is specified when the URB is filled// in by probe().static voidecos_usbeth_tx_callback(struct urb* urb){ ecos_usbeth* usbeth = (ecos_usbeth*) urb->context; spin_lock(&usbeth->usb_lock); if (0 != netif_running(usbeth->net_dev)) { netif_wake_queue(usbeth->net_dev); } spin_unlock(&usbeth->usb_lock);}static intecos_usbeth_start_tx(struct sk_buff* skb, struct net_device* net){ ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; int res; if ((skb->len + 2) > ECOS_USBETH_MAXTU) { printk("ecos_usbeth: oversized packet of %d bytes\n", skb->len); return 0; } if (netif_queue_stopped(net)) { // Another transmission already in progress. // USB bulk operations should complete within 5s. int current_delay = jiffies - net->trans_start; if (current_delay < (5 * HZ)) { return 1; } else { // There has been a timeout. Discard this message. //printk("transmission timed out\n"); usbeth->stats.tx_errors++; dev_kfree_skb(skb); return 0; } } spin_lock(&usbeth->usb_lock); usbeth->tx_buffer[0] = skb->len & 0x00FF; usbeth->tx_buffer[1] = (skb->len >> 8) & 0x00FF; memcpy(&(usbeth->tx_buffer[2]), skb->data, skb->len); usbeth->tx_urb.transfer_buffer_length = skb->len + 2; // Some targets are unhappy about receiving 0-length packets, not // just sending them. if (0 == (usbeth->tx_urb.transfer_buffer_length % 64)) { usbeth->tx_urb.transfer_buffer_length++; }#if 0 { int i; printk("--------------------------------------------------------------\n"); printk("ecos_usbeth start_tx: len %d\n", skb->len + 2); for (i = 0; (i < (skb->len + 2)) && (i < 128); i+= 8) { printk("tx %x %x %x %x %x %x %x %x\n", usbeth->tx_buffer[i], usbeth->tx_buffer[i+1], usbeth->tx_buffer[i+2], usbeth->tx_buffer[i+3],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -