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

📄 pci.c

📁 Airgo agn1000系列 无线网卡驱动源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/** * Airgo MIMO wireless driver * * Copyright (c) 2007-2008 Li YanBo <dreamfly281@gmail.com> * Modified by C. McPherson * * 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/init.h>#include <linux/etherdevice.h>#include <linux/pci.h>#include <linux/delay.h>#include "agnx.h"#include "debug.h"#include "xmit.h"#include "phy.h"#include "net/mac80211.h"MODULE_AUTHOR("Li YanBo <dreamfly281@gmail.com>");MODULE_DESCRIPTION("Airgo MIMO PCI wireless driver");MODULE_LICENSE("GPL");static struct pci_device_id agnx_pci_id_tbl[] __devinitdata = {	{ PCI_DEVICE(0x17cb, 0x0001) },	/* Beklin F5d8010, Netgear WGM511 etc */	{ PCI_DEVICE(0x17cb, 0x0002) },	/* Netgear Wpnt511 */	{ 0 }};MODULE_DEVICE_TABLE(pci, agnx_pci_id_tbl);static inline void agnx_interrupt_ack(struct agnx_priv *priv, u32 *reason){	void __iomem *ctl = priv->ctl;	u32 reg;	if ( *reason & AGNX_STAT_RX ) {		/* Mark complete RX */		reg = ioread32(ctl + AGNX_CIR_RXCTL);		reg |= 0x4;		iowrite32(reg, ctl + AGNX_CIR_RXCTL);		/* disable Rx interrupt */	}	if ( *reason & AGNX_STAT_TX ) {		reg = ioread32(ctl + AGNX_CIR_TXDCTL);		if (reg & 0x4) {			iowrite32(reg, ctl + AGNX_CIR_TXDCTL);			*reason |= AGNX_STAT_TXD;		} 		reg = ioread32(ctl + AGNX_CIR_TXMCTL);		if (reg & 0x4) {			iowrite32(reg, ctl + AGNX_CIR_TXMCTL);			*reason |= AGNX_STAT_TXM;		}	}	if ( *reason & AGNX_STAT_X ) {/* 		reg = ioread32(ctl + AGNX_INT_STAT); *//* 		iowrite32(reg, ctl + AGNX_INT_STAT); *//* 		/\* FIXME reinit interrupt mask *\/ *//* 		reg = 0xc390bf9 & ~IRQ_TX_BEACON; *//* 		reg &= ~IRQ_TX_DISABLE; *//* 		iowrite32(reg, ctl + AGNX_INT_MASK); *//* 		iowrite32(0x800, ctl + AGNX_CIR_BLKCTL); */	}} /* agnx_interrupt_ack */static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id){	struct ieee80211_hw *dev = dev_id;	struct agnx_priv *priv = dev->priv;	void __iomem *ctl = priv->ctl;	irqreturn_t ret = IRQ_NONE;	u32 irq_reason;	spin_lock(&priv->lock);//	printk(KERN_ERR PFX "Get a interrupt %s\n", __func__);	if (priv->init_status != AGNX_START)		goto out;		/* FiXME  Here has no lock, Is this will lead to race? */	irq_reason = ioread32(ctl + AGNX_CIR_BLKCTL);	if (!(irq_reason & 0x7)) 		goto out;	ret = IRQ_HANDLED;	priv->irq_status = ioread32(ctl + AGNX_INT_STAT);//	printk(PFX "Interrupt reason is 0x%x\n", irq_reason);	/* Make sure the txm and txd flags don't conflict with other unknown	   interrupt flag, maybe is not necessary */	irq_reason &= 0xF;	disable_rx_interrupt(priv);	/* TODO Make sure the card finished initialized */	agnx_interrupt_ack(priv, &irq_reason);	if ( irq_reason & AGNX_STAT_RX ) 		handle_rx_irq(priv);		if ( irq_reason & AGNX_STAT_TXD )		handle_txd_irq(priv);	if ( irq_reason & AGNX_STAT_TXM )		handle_txm_irq(priv);	if ( irq_reason & AGNX_STAT_X ) 		handle_other_irq(priv);		enable_rx_interrupt(priv);out:	spin_unlock(&priv->lock);	return ret;} /* agnx_interrupt_handler *//* FIXME */static int agnx_tx(struct ieee80211_hw *dev, struct sk_buff *skb){	AGNX_TRACE;	return _agnx_tx(dev->priv, skb);} /* agnx_tx */static int agnx_get_mac_address(struct agnx_priv *priv){	void __iomem *ctl = priv->ctl;	u32 reg;	AGNX_TRACE;	/* Attention! directly read the MAC or other date from EEPROM will	 lead to cardbus(WGM511) lock up when write to PM PLL register */	reg = agnx_read32(ctl, 0x3544);	udelay(40);	reg = agnx_read32(ctl, 0x354c);	udelay(50);	/* Get the mac address */	reg = agnx_read32(ctl, 0x3544);	udelay(40);	/* HACK */	reg = cpu_to_le32(reg);	priv->mac_addr[0] = ((u8 *)&reg)[2];	priv->mac_addr[1] = ((u8 *)&reg)[3];	reg = agnx_read32(ctl, 0x3548);	udelay(50);	*((u32 *)(priv->mac_addr + 2)) = cpu_to_le32(reg);	if (!is_valid_ether_addr(priv->mac_addr)) {		DECLARE_MAC_BUF(mbuf);		printk(KERN_WARNING PFX "read mac %s\n", print_mac(mbuf, priv->mac_addr));		printk(KERN_WARNING PFX "Invalid hwaddr! Using random hwaddr\n");		random_ether_addr(priv->mac_addr);	}	return 0;} /* agnx_get_mac_address */static int agnx_alloc_rings(struct agnx_priv *priv){	unsigned int len;	AGNX_TRACE;	/* Allocate RX/TXM/TXD rings info */	priv->rx.size = AGNX_RX_RING_SIZE;	priv->txm.size = AGNX_TXM_RING_SIZE;	priv->txd.size = AGNX_TXD_RING_SIZE;	len = priv->rx.size + priv->txm.size + priv->txd.size;//	priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_KERNEL);	priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_ATOMIC);	if (!priv->rx.info)		return -ENOMEM;	priv->txm.info = priv->rx.info + priv->rx.size;	priv->txd.info = priv->txm.info + priv->txm.size;	/* Allocate RX/TXM/TXD descriptors */	priv->rx.desc = pci_alloc_consistent(priv->pdev, sizeof(struct agnx_desc) * len,					     &priv->rx.dma);	if (!priv->rx.desc) {		kfree(priv->rx.info);		return -ENOMEM;	}	priv->txm.desc = priv->rx.desc + priv->rx.size;	priv->txm.dma = priv->rx.dma + sizeof(struct agnx_desc) * priv->rx.size;	priv->txd.desc = priv->txm.desc + priv->txm.size;	priv->txd.dma = priv->txm.dma + sizeof(struct agnx_desc) * priv->txm.size;	return 0;} /* agnx_alloc_rings */static void rings_free(struct agnx_priv *priv){	unsigned int len = priv->rx.size + priv->txm.size + priv->txd.size;	unsigned long flags;	AGNX_TRACE;	spin_lock_irqsave(&priv->lock, flags);	kfree(priv->rx.info);	pci_free_consistent(priv->pdev, sizeof(struct agnx_desc) * len,			    priv->rx.desc, priv->rx.dma);	spin_unlock_irqrestore(&priv->lock, flags);}#ifdef CONFIG_AGNX_PERIODIC_WORKstatic void agnx_periodic_work_handler(struct work_struct *work){	struct agnx_priv *priv = container_of(work, struct agnx_priv,                                             periodic_work.work);//	unsigned long flags;	unsigned long delay;	/* fixme: using mutex?? *///	spin_lock_irqsave(&priv->lock, flags);	/* TODO Recalibrate*///	calibrate_oscillator(priv);//	antenna_calibrate(priv);//	agnx_send_packet(priv, 997);	/* FIXME *//* 	if (debug == 3) *//*                 delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); *//* 	else */	delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY);//		delay = round_jiffies(HZ * 15);	queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay);//	spin_unlock_irqrestore(&priv->lock, flags);}#endifstatic int agnx_start(struct ieee80211_hw *dev){	struct agnx_priv *priv = dev->priv;	int err = 0;	AGNX_TRACE;	err = agnx_alloc_rings(priv);	if (err) {		printk(KERN_ERR PFX "Can't alloc RX/TXM/TXD rings\n");		goto out;	}	err = request_irq(priv->pdev->irq, &agnx_interrupt_handler,			  IRQF_SHARED, "agnx_pci", dev);	if (err) {		printk(KERN_ERR PFX "Failed to register IRQ handler\n");		rings_free(priv);		goto out;	}//	mdelay(500);	might_sleep();	agnx_hw_init(priv);//	mdelay(500);	might_sleep();	priv->init_status = AGNX_START;/*         INIT_DELAYED_WORK(&priv->periodic_work, agnx_periodic_work_handler); *//* 	delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); *//*         queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay); */out:			   	return err;} /* agnx_start */static void agnx_stop(struct ieee80211_hw *dev){	struct agnx_priv *priv = dev->priv;	AGNX_TRACE;	priv->init_status = AGNX_STOP;	/* make sure hardware will not generate irq */	agnx_hw_reset(priv);	free_irq(priv->pdev->irq, dev);        flush_workqueue(priv->hw->workqueue);	/* cancel_delayed_work_sync(&priv->periodic_work);*/	unfill_rings(priv);	rings_free(priv);}static int agnx_config(struct ieee80211_hw *dev, u32 changed){	struct agnx_priv *priv = dev->priv;	struct ieee80211_conf *conf = &dev->conf;	int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);	AGNX_TRACE;	spin_lock(&priv->lock);	/* FIXME need priv lock? */	if (channel != priv->channel) {	       		priv->channel = channel;		agnx_set_channel(priv, priv->channel);	}	spin_unlock(&priv->lock);	return 0;}static int agnx_config_interface(struct ieee80211_hw *dev, 				 struct ieee80211_vif *vif,				 struct ieee80211_if_conf *conf){	struct agnx_priv *priv = dev->priv;	void __iomem *ctl = priv->ctl;	AGNX_TRACE;	spin_lock(&priv->lock);

⌨️ 快捷键说明

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