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

📄 bcm43xx_pio.c

📁 无线网卡驱动,有很好的参考价值,在linux_2.6.21下可以直接使用,如果在其他平台,可以参考移植
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  Broadcom BCM43xx wireless driver  PIO Transmission  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>  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; see the file COPYING.  If not, write to  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,  Boston, MA 02110-1301, USA.*/#include "bcm43xx.h"#include "bcm43xx_pio.h"#include "bcm43xx_main.h"#include "bcm43xx_xmit.h"#include "bcm43xx_power.h"#include <linux/delay.h>static void tx_start(struct bcm43xx_pioqueue *queue){	bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,			  BCM43xx_PIO_TXCTL_INIT);}static void tx_octet(struct bcm43xx_pioqueue *queue,		     u8 octet){	if (queue->need_workarounds) {		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,				  octet);		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,				  BCM43xx_PIO_TXCTL_WRITELO);	} else {		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,				  BCM43xx_PIO_TXCTL_WRITELO);		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,				  octet);	}}static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr,			    const u8 *packet,			    unsigned int *pos){	const u8 *source;	unsigned int i = *pos;	u16 ret;	if (i < sizeof(*txhdr)) {		source = (const u8 *)txhdr;	} else {		source = packet;		i -= sizeof(*txhdr);	}	ret = le16_to_cpu( *((u16 *)(source + i)) );	*pos += 2;	return ret;}static void tx_data(struct bcm43xx_pioqueue *queue,		    struct bcm43xx_txhdr *txhdr,		    const u8 *packet,		    unsigned int octets){	u16 data;	unsigned int i = 0;	if (queue->need_workarounds) {		data = tx_get_next_word(txhdr, packet, &i);		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);	}	bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,			  BCM43xx_PIO_TXCTL_WRITELO |			  BCM43xx_PIO_TXCTL_WRITEHI);	while (i < octets - 1) {		data = tx_get_next_word(txhdr, packet, &i);		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);	}	if (octets % 2)		tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]);}static void tx_complete(struct bcm43xx_pioqueue *queue,			struct sk_buff *skb){	if (queue->need_workarounds) {		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,				  skb->data[skb->len - 1]);		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,				  BCM43xx_PIO_TXCTL_WRITELO |				  BCM43xx_PIO_TXCTL_COMPLETE);	} else {		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,				  BCM43xx_PIO_TXCTL_COMPLETE);	}}static u16 generate_cookie(struct bcm43xx_pioqueue *queue,			   struct bcm43xx_pio_txpacket *packet){	u16 cookie = 0x0000;	int packetindex;	/* We use the upper 4 bits for the PIO	 * controller ID and the lower 12 bits	 * for the packet index (in the cache).	 */	switch (queue->mmio_base) {	case BCM43xx_MMIO_PIO1_BASE:		break;	case BCM43xx_MMIO_PIO2_BASE:		cookie = 0x1000;		break;	case BCM43xx_MMIO_PIO3_BASE:		cookie = 0x2000;		break;	case BCM43xx_MMIO_PIO4_BASE:		cookie = 0x3000;		break;	default:		assert(0);	}	packetindex = pio_txpacket_getindex(packet);	assert(((u16)packetindex & 0xF000) == 0x0000);	cookie |= (u16)packetindex;	return cookie;}staticstruct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm,				       u16 cookie,				       struct bcm43xx_pio_txpacket **packet){	struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm);	struct bcm43xx_pioqueue *queue = NULL;	int packetindex;	switch (cookie & 0xF000) {	case 0x0000:		queue = pio->queue0;		break;	case 0x1000:		queue = pio->queue1;		break;	case 0x2000:		queue = pio->queue2;		break;	case 0x3000:		queue = pio->queue3;		break;	default:		assert(0);	}	packetindex = (cookie & 0x0FFF);	assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS);	*packet = &(queue->tx_packets_cache[packetindex]);	return queue;}static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue,				  struct sk_buff *skb,				  struct bcm43xx_pio_txpacket *packet){	struct bcm43xx_txhdr txhdr;	unsigned int octets;	assert(skb_shinfo(skb)->nr_frags == 0);	bcm43xx_generate_txhdr(queue->bcm,			       &txhdr, skb->data, skb->len,			       (packet->xmitted_frags == 0),			       generate_cookie(queue, packet));	tx_start(queue);	octets = skb->len + sizeof(txhdr);	if (queue->need_workarounds)		octets--;	tx_data(queue, &txhdr, (u8 *)skb->data, octets);	tx_complete(queue, skb);}static void free_txpacket(struct bcm43xx_pio_txpacket *packet,			  int irq_context){	struct bcm43xx_pioqueue *queue = packet->queue;	ieee80211_txb_free(packet->txb);	list_move(&packet->list, &queue->txfree);	queue->nr_txfree++;	assert(queue->tx_devq_used >= packet->xmitted_octets);	assert(queue->tx_devq_packets >= packet->xmitted_frags);	queue->tx_devq_used -= packet->xmitted_octets;	queue->tx_devq_packets -= packet->xmitted_frags;}static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet){	struct bcm43xx_pioqueue *queue = packet->queue;	struct ieee80211_txb *txb = packet->txb;	struct sk_buff *skb;	u16 octets;	int i;	for (i = packet->xmitted_frags; i < txb->nr_frags; i++) {		skb = txb->fragments[i];		octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr);		assert(queue->tx_devq_size >= octets);		assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS);		assert(queue->tx_devq_used <= queue->tx_devq_size);		/* Check if there is sufficient free space on the device		 * TX queue. If not, return and let the TX tasklet		 * retry later.		 */		if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS)			return -EBUSY;		if (queue->tx_devq_used + octets > queue->tx_devq_size)			return -EBUSY;		/* Now poke the device. */		pio_tx_write_fragment(queue, skb, packet);		/* Account for the packet size.		 * (We must not overflow the device TX queue)		 */		queue->tx_devq_packets++;		queue->tx_devq_used += octets;		assert(packet->xmitted_frags < packet->txb->nr_frags);		packet->xmitted_frags++;		packet->xmitted_octets += octets;	}	list_move_tail(&packet->list, &queue->txrunning);	return 0;}static void tx_tasklet(unsigned long d){	struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d;	struct bcm43xx_private *bcm = queue->bcm;	unsigned long flags;	struct bcm43xx_pio_txpacket *packet, *tmp_packet;	int err;	u16 txctl;	spin_lock_irqsave(&bcm->irq_lock, flags);	if (queue->tx_frozen)		goto out_unlock;	txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);	if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)		goto out_unlock;	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {		assert(packet->xmitted_frags < packet->txb->nr_frags);		if (packet->xmitted_frags == 0) {			int i;			struct sk_buff *skb;			/* Check if the device queue is big			 * enough for every fragment. If not, drop the			 * whole packet.			 */			for (i = 0; i < packet->txb->nr_frags; i++) {				skb = packet->txb->fragments[i];				if (unlikely(skb->len > queue->tx_devq_size)) {					dprintkl(KERN_ERR PFX "PIO TX device queue too small. "							      "Dropping packet.\n");					free_txpacket(packet, 1);					goto next_packet;				}			}		}		/* Try to transmit the packet.		 * This may not completely succeed.		 */		err = pio_tx_packet(packet);		if (err)			break;	next_packet:		continue;	}out_unlock:	spin_unlock_irqrestore(&bcm->irq_lock, flags);}static void setup_txqueues(struct bcm43xx_pioqueue *queue){	struct bcm43xx_pio_txpacket *packet;	int i;	queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS;	for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) {		packet = &(queue->tx_packets_cache[i]);		packet->queue = queue;		INIT_LIST_HEAD(&packet->list);		list_add(&packet->list, &queue->txfree);	}}staticstruct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm,						 u16 pio_mmio_base){	struct bcm43xx_pioqueue *queue;	u32 value;	u16 qsize;	queue = kzalloc(sizeof(*queue), GFP_KERNEL);	if (!queue)		goto out;	queue->bcm = bcm;	queue->mmio_base = pio_mmio_base;	queue->need_workarounds = (bcm->current_core->rev < 3);	INIT_LIST_HEAD(&queue->txfree);

⌨️ 快捷键说明

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