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

📄 xmit.c

📁 Airgo agn1000系列 无线网卡驱动源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/** * Airgo MIMO wireless driver * * Copyright (c) 2007-2008 Li YanBo <dreamfly281@gmail.com> * Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer  * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin  * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as  * published by the Free Software Foundation. */#include <linux/pci.h>#include <linux/delay.h>#include "agnx.h"#include "debug.h"#include "phy.h"static inline void disable_rx_engine(struct agnx_priv *priv){	void __iomem *ctl = priv->ctl;	iowrite32(0x100, ctl + AGNX_CIR_RXCTL);	/* Wait for RX Control to have the Disable Rx Interrupt (0x100) set */	ioread32(ctl + AGNX_CIR_RXCTL);}static inline void enable_rx_engine(struct agnx_priv *priv){	void __iomem *ctl = priv->ctl;	iowrite32(0x80, ctl + AGNX_CIR_RXCTL);	ioread32(ctl + AGNX_CIR_RXCTL);}inline void disable_rx_interrupt(struct agnx_priv *priv){	void __iomem *ctl = priv->ctl;	u32 reg;	disable_rx_engine(priv);	reg = ioread32(ctl + AGNX_CIR_RXCFG);	reg &= ~0x20;	iowrite32(reg, ctl + AGNX_CIR_RXCFG);	ioread32(ctl + AGNX_CIR_RXCFG);}inline void enable_rx_interrupt(struct agnx_priv *priv){	void __iomem *ctl = priv->ctl;	u32 reg;	reg = ioread32(ctl + AGNX_CIR_RXCFG);	reg |= 0x20;	iowrite32(reg, ctl + AGNX_CIR_RXCFG);	ioread32(ctl + AGNX_CIR_RXCFG);	enable_rx_engine(priv);}static inline void rx_desc_init(struct agnx_priv *priv, unsigned int idx){	struct agnx_desc *desc = priv->rx.desc + idx;	struct agnx_info *info = priv->rx.info + idx;	memset(info, 0, sizeof(*info));	info->dma_len = IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct agnx_hdr);	info->skb = dev_alloc_skb(info->dma_len);	if (info->skb == NULL)		agnx_bug("refill err");	info->mapping = pci_map_single(priv->pdev, skb_tail_pointer(info->skb),				       info->dma_len, PCI_DMA_FROMDEVICE);	memset(desc, 0, sizeof(*desc));	desc->dma_addr = cpu_to_be32(info->mapping);	/* Set the owner to the card */	desc->frag = cpu_to_be32(be32_to_cpu(desc->frag) | OWNER);}static inline void rx_desc_reinit(struct agnx_priv *priv, unsigned int idx){	struct agnx_info *info = priv->rx.info + idx;	/* Cause ieee80211 will free the skb buffer, so we needn't to free it again?! */	pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_FROMDEVICE);	rx_desc_init(priv, idx);}static inline void rx_desc_reusing(struct agnx_priv *priv, unsigned int idx){	struct agnx_desc *desc = priv->rx.desc + idx;	struct agnx_info *info = priv->rx.info + idx;	memset(desc, 0, sizeof(*desc));	desc->dma_addr = cpu_to_be32(info->mapping);	/* Set the owner to the card */	desc->frag = cpu_to_be32(be32_to_cpu(desc->frag) | OWNER);}static void rx_desc_free(struct agnx_priv *priv, unsigned int idx){	struct agnx_desc *desc = priv->rx.desc + idx;	struct agnx_info *info = priv->rx.info + idx;	BUG_ON(!desc || !info);	if (info->mapping)		pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_FROMDEVICE);	if (info->skb)		dev_kfree_skb(info->skb);	memset(info, 0, sizeof(*info));	memset(desc, 0, sizeof(*desc));}static inline void __tx_desc_free(struct agnx_priv *priv, 				  struct agnx_desc *desc, struct agnx_info *info){	BUG_ON(!desc || !info);	/* TODO make sure mapping, skb and len are consistency */	if (info->mapping) 		pci_unmap_single(priv->pdev, info->mapping, 				 info->dma_len, PCI_DMA_TODEVICE);		if (info->type == PACKET)		dev_kfree_skb(info->skb);	memset(info, 0, sizeof(*info));	memset(desc, 0, sizeof(*desc));}static void txm_desc_free(struct agnx_priv *priv, unsigned int idx){	struct agnx_desc *desc = priv->txm.desc + idx;	struct agnx_info *info = priv->txm.info + idx;	__tx_desc_free(priv, desc, info);}static void txd_desc_free(struct agnx_priv *priv, unsigned int idx){	struct agnx_desc *desc = priv->txd.desc + idx;	struct agnx_info *info = priv->txd.info + idx;	__tx_desc_free(priv, desc, info);}int fill_rings(struct agnx_priv *priv){	void __iomem *ctl = priv->ctl;	unsigned int i;	u32 reg;	AGNX_TRACE;	priv->txd.idx_sent = priv->txm.idx_sent = 0;	priv->rx.idx = priv->txm.idx = priv->txd.idx = 0;	for (i = 0; i < priv->rx.size; i++)		rx_desc_init(priv, i);		for (i = 0; i < priv->txm.size; i++) {		memset(priv->txm.desc + i, 0, sizeof(struct agnx_desc));		memset(priv->txm.info + i, 0, sizeof(struct agnx_info));	}	for (i = 0; i < priv->txd.size; i++) {		memset(priv->txd.desc + i, 0, sizeof(struct agnx_desc));		memset(priv->txd.info + i, 0, sizeof(struct agnx_info));	}	/* FIXME Set the card RX TXM and TXD address */	agnx_write32(ctl, AGNX_CIR_RXCMSTART, priv->rx.dma);	agnx_write32(ctl, AGNX_CIR_RXCMEND, priv->txm.dma);	agnx_write32(ctl, AGNX_CIR_TXMSTART, priv->txm.dma);	agnx_write32(ctl, AGNX_CIR_TXMEND, priv->txd.dma);	agnx_write32(ctl, AGNX_CIR_TXDSTART, priv->txd.dma);	agnx_write32(ctl, AGNX_CIR_TXDEND, priv->txd.dma + 		     sizeof(struct agnx_desc) * priv->txd.size);	/* FIXME Relinquish control of rings to card */	reg = agnx_read32(ctl, AGNX_CIR_BLKCTL);	reg &= ~0x800;	agnx_write32(ctl, AGNX_CIR_BLKCTL, reg);	return 0;} /* fill_rings */void unfill_rings(struct agnx_priv *priv){	unsigned long flags;	unsigned int i;	AGNX_TRACE;	spin_lock_irqsave(&priv->lock, flags);	for (i = 0; i < priv->rx.size; i++)		rx_desc_free(priv, i);	for (i = 0; i < priv->txm.size; i++) 		txm_desc_free(priv, i);		for (i = 0; i < priv->txd.size; i++) 		txd_desc_free(priv, i);	spin_unlock_irqrestore(&priv->lock, flags);}/* Extract the bitrate out of a CCK PLCP header.    copy from bcm43xx driver */static inline u8 agnx_plcp_get_bitrate_cck(__be32 *phyhdr_11b){	/* FIXME */	switch (*(u8 *)phyhdr_11b) {	case 0x0A:		return 0;	case 0x14:		return 1;	case 0x37:		return 2;	case 0x6E:		return 3;	}	agnx_bug("Wrong plcp rate");	return 0;}/* FIXME */static inline u8 agnx_plcp_get_bitrate_ofdm(__be32 *phyhdr_11g){	u8 rate = *(u8 *)phyhdr_11g & 0xF;	printk(PFX "G mode rate is 0x%x\n", rate);	return rate;}/* FIXME */static void get_rx_stats(struct agnx_priv *priv, struct agnx_hdr *hdr,			 struct ieee80211_rx_status *stat){	void __iomem *ctl = priv->ctl;	u8 *rssi;	u32 noise;	/* FIXME just for test */	int snr = 40;		/* signal-to-noise ratio */	memset(stat, 0, sizeof(*stat));	/* RSSI */	rssi = (u8 *)&hdr->phy_stats_lo;//	stat->ssi = (rssi[0] + rssi[1] + rssi[2]) / 3;	/* Noise */	noise = ioread32(ctl + AGNX_GCR_NOISE0);	noise += ioread32(ctl + AGNX_GCR_NOISE1);	noise += ioread32(ctl + AGNX_GCR_NOISE2);	stat->noise = noise / 3;	/* Signal quality */	//snr = stat->ssi - stat->noise;	if (snr >=0 && snr < 40)		stat->signal = 5 * snr / 2; 	else if (snr >= 40)		stat->signal = 100;	else		stat->signal = 0;	if (hdr->_11b0 && !hdr->_11g0) {		stat->rate_idx = agnx_plcp_get_bitrate_cck(&hdr->_11b0);	} else if (!hdr->_11b0 && hdr->_11g0) {		printk(PFX "RX: Found G mode packet\n");		stat->rate_idx = agnx_plcp_get_bitrate_ofdm(&hdr->_11g0);	} else		agnx_bug("Unknown packets type");	stat->band = IEEE80211_BAND_2GHZ;	stat->freq = agnx_2ghz_channels[priv->channel - 1].center_freq;//	stat->antenna = 3;//	stat->mactime = be32_to_cpu(hdr->time_stamp);//	stat->channel = priv->channel;}static inline void combine_hdr_frag(struct ieee80211_hdr *ieeehdr, 				    struct sk_buff *skb){	u16 fctl;	unsigned int hdrlen;	fctl = le16_to_cpu(ieeehdr->frame_control);	hdrlen = ieee80211_hdrlen(fctl);	/* FIXME */	if (hdrlen < (2+2+6)/*minimum hdr*/ || 	    hdrlen > sizeof(struct ieee80211_mgmt)) {		printk(KERN_ERR PFX "hdr len is %d\n", hdrlen);		agnx_bug("Wrong ieee80211 hdr detected");	}	skb_push(skb, hdrlen);	memcpy(skb->data, ieeehdr, hdrlen);} /* combine_hdr_frag */static inline int agnx_packet_check(struct agnx_priv *priv, struct agnx_hdr *agnxhdr,				    unsigned packet_len){	if (agnx_get_bits(CRC_FAIL, CRC_FAIL_SHIFT, be32_to_cpu(agnxhdr->reg1)) == 1){		printk(PFX "RX: CRC check fail\n");		goto drop;	}	if (packet_len > 2048) {		printk(PFX "RX: Too long packet detected\n");		goto drop;	}	/* FIXME Just usable for Promious Mode, for Manage mode exclude FCS *//* 	if (packet_len - sizeof(*agnxhdr) < FCS_LEN) { *//* 		printk(PFX "RX: Too short packet detected\n"); *//* 		goto drop; *//* 	} */	return 0;drop:	priv->stats.dot11FCSErrorCount++;	return -1;}void handle_rx_irq(struct agnx_priv *priv){	struct ieee80211_rx_status status;	unsigned int len;//	AGNX_TRACE;	do {		struct agnx_desc *desc;		u32 frag;		struct agnx_info *info;		struct agnx_hdr *hdr;		struct sk_buff *skb;		unsigned int i = priv->rx.idx % priv->rx.size;		desc = priv->rx.desc + i;		frag = be32_to_cpu(desc->frag);		if (frag & OWNER)			break;	       				info = priv->rx.info + i;		skb = info->skb;		hdr = (struct agnx_hdr *)(skb->data);		len = (frag & PACKET_LEN) >> PACKET_LEN_SHIFT;		if (agnx_packet_check(priv, hdr, len) == -1) { 			rx_desc_reusing(priv, i); 			continue;					}		skb_put(skb, len);		do {			u16 fctl;			fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr)->frame_control);			if ((fctl & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_BEACON)// && !(fctl & IEEE80211_STYPE_BEACON))				dump_ieee80211_hdr((struct ieee80211_hdr *)hdr->mac_hdr, "RX");		} while (0);		if (hdr->_11b0 && !hdr->_11g0) {/* 			int j; *//* 			u16 fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr) *//* 					       ->frame_control); *//* 			if ( (fctl & IEEE80211_FCTL_FTYPE) ==  IEEE80211_FTYPE_DATA) { *//* 				agnx_print_rx_hdr(hdr); */// 				agnx_print_sta(priv, BSSID_STAID); /* 				for (j = 0; j < 8; j++) *//* 					agnx_print_sta_tx_wq(priv, BSSID_STAID, j);		 *//* 			} */			get_rx_stats(priv, hdr, &status);			skb_pull(skb, sizeof(*hdr));			combine_hdr_frag((struct ieee80211_hdr *)hdr->mac_hdr, skb);		} else if (!hdr->_11b0 && hdr->_11g0) {//			int j;			agnx_print_rx_hdr(hdr);			agnx_print_sta(priv, BSSID_STAID);//			for (j = 0; j < 8; j++)			agnx_print_sta_tx_wq(priv, BSSID_STAID, 0);#ifdef CONFIG_AGNX_DEBUG			print_hex_dump_bytes("agnx: RX_PACKET: ", DUMP_PREFIX_NONE,					     skb->data, skb->len + 8);#endif//			if (agnx_plcp_get_bitrate_ofdm(&hdr->_11g0) == 0)							get_rx_stats(priv, hdr, &status);			skb_pull(skb, sizeof(*hdr));			combine_hdr_frag((struct ieee80211_hdr *)					 ((void *)&hdr->mac_hdr), skb);//			dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G");		} else			agnx_bug("Unknown packets type");		ieee80211_rx_irqsafe(priv->hw, skb, &status);		rx_desc_reinit(priv, i);	} while ( priv->rx.idx++ );} /* handle_rx_irq */static inline void handle_tx_irq(struct agnx_priv *priv, struct agnx_ring *ring){	struct agnx_desc *desc;	struct agnx_info *info;	unsigned int idx;	for (idx = ring->idx_sent; idx < ring->idx; idx++) {		unsigned int i = idx % ring->size;		u32  frag;		desc = ring->desc + i;		info = ring->info + i;				frag = be32_to_cpu(desc->frag);		if (frag & OWNER) {			if (info->type == HEADER)

⌨️ 快捷键说明

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