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

📄 islpci_eth.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   *  Copyright (C) 2002 Intersil Americas Inc. *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> *  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 * *  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/module.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/if_arp.h>#include "prismcompat.h"#include "isl_38xx.h"#include "islpci_eth.h"#include "islpci_mgt.h"#include "oid_mgt.h"/******************************************************************************    Network Interface functions******************************************************************************/voidislpci_eth_cleanup_transmit(islpci_private *priv,			    isl38xx_control_block *control_block){	struct sk_buff *skb;	u32 index;	/* compare the control block read pointer with the free pointer */	while (priv->free_data_tx !=	       le32_to_cpu(control_block->			   device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) {		/* read the index of the first fragment to be freed */		index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE;		/* check for holes in the arrays caused by multi fragment frames 		 * searching for the last fragment of a frame */		if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) {			/* entry is the last fragment of a frame			 * free the skb structure and unmap pci memory */			skb = priv->data_low_tx[index];#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING,			      "cleanup skb %p skb->data %p skb->len %u truesize %u\n ",			      skb, skb->data, skb->len, skb->truesize);#endif			pci_unmap_single(priv->pdev,					 priv->pci_map_tx_address[index],					 skb->len, PCI_DMA_TODEVICE);			dev_kfree_skb_irq(skb);			skb = NULL;		}		/* increment the free data low queue pointer */		priv->free_data_tx++;	}}intislpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev){	islpci_private *priv = netdev_priv(ndev);	isl38xx_control_block *cb = priv->control_block;	u32 index;	dma_addr_t pci_map_address;	int frame_size;	isl38xx_fragment *fragment;	int offset;	struct sk_buff *newskb;	int newskb_offset;	unsigned long flags;	unsigned char wds_mac[6];	u32 curr_frag;	int err = 0;#if VERBOSE > SHOW_ERROR_MESSAGES	DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n");#endif	/* lock the driver code */	spin_lock_irqsave(&priv->slock, flags);	/* check whether the destination queue has enough fragments for the frame */	curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]);	if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) {		printk(KERN_ERR "%s: transmit device queue full when awake\n",		       ndev->name);		netif_stop_queue(ndev);		/* trigger the device */		isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE,				  ISL38XX_DEV_INT_REG);		udelay(ISL38XX_WRITEIO_DELAY);		err = -EBUSY;		goto drop_free;	}	/* Check alignment and WDS frame formatting. The start of the packet should	 * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes	 * and add WDS address information */	if (likely(((long) skb->data & 0x03) | init_wds)) {		/* get the number of bytes to add and re-allign */		offset = (4 - (long) skb->data) & 0x03;		offset += init_wds ? 6 : 0;		/* check whether the current skb can be used  */		if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {			unsigned char *src = skb->data;#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset,			      init_wds);#endif			/* align the buffer on 4-byte boundary */			skb_reserve(skb, (4 - (long) skb->data) & 0x03);			if (init_wds) {				/* wds requires an additional address field of 6 bytes */				skb_put(skb, 6);#ifdef ISLPCI_ETH_DEBUG				printk("islpci_eth_transmit:wds_mac\n");#endif				memmove(skb->data + 6, src, skb->len);				memcpy(skb->data, wds_mac, 6);			} else {				memmove(skb->data, src, skb->len);			}#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data,			      src, skb->len);#endif		} else {			newskb =			    dev_alloc_skb(init_wds ? skb->len + 6 : skb->len);			if (unlikely(newskb == NULL)) {				printk(KERN_ERR "%s: Cannot allocate skb\n",				       ndev->name);				err = -ENOMEM;				goto drop_free;			}			newskb_offset = (4 - (long) newskb->data) & 0x03;			/* Check if newskb->data is aligned */			if (newskb_offset)				skb_reserve(newskb, newskb_offset);			skb_put(newskb, init_wds ? skb->len + 6 : skb->len);			if (init_wds) {				memcpy(newskb->data + 6, skb->data, skb->len);				memcpy(newskb->data, wds_mac, 6);#ifdef ISLPCI_ETH_DEBUG				printk("islpci_eth_transmit:wds_mac\n");#endif			} else				memcpy(newskb->data, skb->data, skb->len);#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n",			      newskb->data, skb->data, skb->len, init_wds);#endif			newskb->dev = skb->dev;			dev_kfree_skb(skb);			skb = newskb;		}	}	/* display the buffer contents for debugging */#if VERBOSE > SHOW_ERROR_MESSAGES	DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data);	display_buffer((char *) skb->data, skb->len);#endif	/* map the skb buffer to pci memory for DMA operation */	pci_map_address = pci_map_single(priv->pdev,					 (void *) skb->data, skb->len,					 PCI_DMA_TODEVICE);	if (unlikely(pci_map_address == 0)) {		printk(KERN_WARNING "%s: cannot map buffer to PCI\n",		       ndev->name);		err = -EIO;		goto drop_free;	}	/* Place the fragment in the control block structure. */	index = curr_frag % ISL38XX_CB_TX_QSIZE;	fragment = &cb->tx_data_low[index];	priv->pci_map_tx_address[index] = pci_map_address;	/* store the skb address for future freeing  */	priv->data_low_tx[index] = skb;	/* set the proper fragment start address and size information */	frame_size = skb->len;	fragment->size = cpu_to_le16(frame_size);	fragment->flags = cpu_to_le16(0);	/* set to 1 if more fragments */	fragment->address = cpu_to_le32(pci_map_address);	curr_frag++;	/* The fragment address in the control block must have been	 * written before announcing the frame buffer to device. */	wmb();	cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag);	if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD	    > ISL38XX_CB_TX_QSIZE) {		/* stop sends from upper layers */		netif_stop_queue(ndev);		/* set the full flag for the transmission queue */		priv->data_low_tx_full = 1;	}	/* set the transmission time */	ndev->trans_start = jiffies;	priv->statistics.tx_packets++;	priv->statistics.tx_bytes += skb->len;	/* trigger the device */	islpci_trigger(priv);	/* unlock the driver code */	spin_unlock_irqrestore(&priv->slock, flags);	return 0;      drop_free:	priv->statistics.tx_dropped++;	spin_unlock_irqrestore(&priv->slock, flags);	dev_kfree_skb(skb);	return err;}static inline intislpci_monitor_rx(islpci_private *priv, struct sk_buff **skb){	/* The card reports full 802.11 packets but with a 20 bytes	 * header and without the FCS. But there a is a bit that	 * indicates if the packet is corrupted :-) */	struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data;	if (hdr->flags & 0x01)

⌨️ 快捷键说明

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