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

📄 wl_linux.c

📁 wi-fi sources for asus wl138g v2 pci card
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Linux-specific portion of * Broadcom 802.11abg Networking Device Driver * * Copyright 2005-2006, Broadcom Corporation * All Rights Reserved.                 *                                      * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * * $Id$ */#define __UNDEF_NO_VERSION__#include <wlc_cfg.h>#include <typedefs.h>#include <linux/module.h>#include <linuxver.h>#include <osl.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/proc_fs.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <linux/string.h>#include <linux/ethtool.h>#include <linux/completion.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)#include <net/ieee80211.h>#endif#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/pgtable.h>#include <asm/uaccess.h>#include <asm/unaligned.h>#include <epivers.h>#include <bcmendian.h>#include <proto/ethernet.h>#include <bcmdevs.h>#include <bcmdefs.h>#include <bcmutils.h>#include <pcicfg.h>#include <wlioctl.h>#include <wl_linux.h>#include <wlc_key.h>typedef void wlc_info_t;typedef const struct sb_pub  sb_t;#include <wlc_pub.h>#include <wl_dbg.h>#include <wlc_ethereal.h>/* Linux wireless extension support */#ifdef CONFIG_NET_RADIO#include <wl_iw.h>#endif /* CONFIG_NET_RADIO */#include <wl_export.h>typedef struct wl_timer {	struct timer_list timer;	struct wl_info *wl;	void (*fn)(void *);	uint ms;	bool periodic;	bool set;	struct wl_timer *next;} wl_timer_t;/* contortion to call functions at safe time */typedef struct wl_task {	struct work_struct work;	void *context;} wl_task_t;#define WL_IFTYPE_BSS	1 /* iftype subunit for BSS */typedef struct wl_if {	struct wl_if *next;	struct wl_info *wl;		/* back pointer to main wl_info_t */	struct net_device *dev;		/* virtual netdevice */	int type;			/* interface type: BSS */	struct wlc_if *wlcif;		/* wlc interface handle */	struct ether_addr remote;	/* remote partner */	uint subunit;			/* BSS unit */} wl_if_t;struct wl_info {#ifdef CONFIG_NET_RADIO	wl_iw_t		iw;		/* wireless extensions state (must be first) */#endif /* CONFIG_NET_RADIO */	wlc_pub_t	*pub;		/* pointer to public wlc state */	void		*wlc;		/* pointer to private common os-independent data */	osl_t		*osh;		/* pointer to os handler */	struct net_device *dev;		/* backpoint to device */	spinlock_t	lock;		/* per-device perimeter lock */	uint		bustype;	/* bus type */	bool		piomode;	/* set from insmod argument */	void *regsva;			/* opaque chip registers virtual address */	struct net_device_stats stats;	/* stat counter reporting structure */	wl_if_t *if_list;		/* list of all interfaces */	struct wl_info *next;		/* pointer to next wl_info_t in chain */	volatile uint callbacks;	/* # outstanding callback functions */	struct wl_timer *timers;	/* timer cleanup queue */	struct tasklet_struct tasklet;	/* dpc tasklet */	ulong flags;			/* current irq flags */	struct net_device *monitor;	/* monitor pseudo device */	bool		resched;	/* dpc needs to be and is rescheduled */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)	struct ieee80211_crypto_ops *tkipmodops;	/* external tkip module ops */	struct ieee80211_tkip_data  *tkip_ucast_data;	struct ieee80211_tkip_data  *tkip_bcast_data;#endif};static int wl_found = 0;/* defines */#define	DEV_WLPTR(dev)		dev->priv	/* priv points to wl */#define	DEV_WLIFPTR(dev)	dev->dn_ptr	#define	WL_INFO(dev)	(wl_info_t*)(DEV_WLPTR(dev))#define	WL_DEV_IF(dev)	((wl_if_t*)(DEV_WLIFPTR(dev)))#define WL_LOCK(wl)	do { ulong flags; spin_lock_irqsave(&(wl)->lock, flags); \	(wl)->flags = flags; } while (0)#define WL_UNLOCK(wl)	do { ulong flags; flags = (wl)->flags; \	spin_unlock_irqrestore(&(wl)->lock, flags); } while (0)#define WL_LOCKED(wl)	spin_is_locked(&(wl)->lock)#define WL_TASKLET (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 5))/* local prototypes */static int wl_open(struct net_device *dev);static int wl_close(struct net_device *dev);static int wl_start(struct sk_buff *skb, struct net_device *dev);static struct net_device_stats *wl_get_stats(struct net_device *dev);#ifdef CONFIG_NET_RADIOstatic struct iw_statistics *wl_get_wireless_stats(struct net_device *dev);#endif /* CONFIG_NET_RADIO */static int wl_set_mac_address(struct net_device *dev, void *addr);static void wl_set_multicast_list(struct net_device *dev);#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)static int wl_ethtool(wl_info_t *wl, void *uaddr);#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */#if WL_TASKLETstatic void wl_dpc(ulong data);#endif	/* WL_TASKLET */static void wl_link_up(wl_info_t *wl);static void wl_link_down(wl_info_t *wl);static void wl_tkipmic_error(wl_info_t *wl, struct ether_addr *ea, bool group, bool flush_txq);static int wl_schedule_task(wl_info_t *wl, void (*fn)(struct wl_task *), void *context);#if defined(CONFIG_PROC_FS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0))static int wl_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);#endif /* defined(CONFIG_PROC_FS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)) */struct wl_if *wl_alloc_if(wl_info_t *wl, int iftype, uint unit, struct wlc_if* wlc_if);static void wl_free_if(wl_info_t *wl, wl_if_t *wlif);#ifdef CONFIG_PCI/* recognized PCI IDs */static struct pci_device_id wl_id_table[] __devinitdata = {	{ vendor: PCI_ANY_ID,	device: PCI_ANY_ID,	subvendor: PCI_ANY_ID,	subdevice: PCI_ANY_ID,	class: PCI_CLASS_NETWORK_OTHER << 8,	class_mask: 0xffff00,	driver_data: 0,	},	{ 0, }};MODULE_DEVICE_TABLE(pci, wl_id_table);#endif	/* CONFIG_PCI */static int oneonly = 0;module_param(oneonly, int, 0);static int piomode = 0;module_param(piomode, int, 0);static char name[IFNAMSIZ] = "eth%d";module_param_string(name, name, IFNAMSIZ, 0);/* BCMSLTGT: slow target */#ifndef	SRCBASE#define	SRCBASE "."#endif /* SRCBASE *//**  * attach to the WL device. * * Attach to the WL device identified by vendor and device parameters. * regs is a host accessible memory address pointing to WL device registers. * * wl_attach is not defined as static because in the case where no bus * is defined, wl_attach will never be called, and thus, gcc will issue * a warning that this function is defined but not used if we declare * it as static. */wl_info_t *wl_attach(uint16 vendor, uint16 device, ulong regs, uint bustype, void *btparam, uint irq){	struct net_device *dev;	wl_if_t *wlif;	wl_info_t *wl;#if defined(CONFIG_PROC_FS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0))	char tmp[128];#endif	osl_t *osh;	int unit;	uint err;	unit = wl_found;	if (oneonly && (unit != 0)) {		WL_ERROR(("wl%d: wl_attach: oneonly is set, exiting\n", unit));		return NULL;	}	/* Requires pkttag feature */	osh = osl_attach(btparam, TRUE);	ASSERT(osh);	/* allocate private info */	if ((wl = (wl_info_t*) MALLOC(osh, sizeof(wl_info_t))) == NULL) {		WL_ERROR(("wl%d: malloc wl_info_t, out of memory, malloced %d bytes\n", unit,			MALLOCED(osh)));		osl_detach(osh);		return NULL;	}	bzero(wl, sizeof(wl_info_t));	wl->osh = osh;	wlif = wl_alloc_if(wl, WL_IFTYPE_BSS, unit, NULL);	if (!wlif) {		WL_ERROR(("wl%d: wl_alloc_if failed\n", unit));		MFREE(osh, wl, sizeof(wl_info_t));		osl_detach(osh);		return NULL;	}	dev = wlif->dev;	strncpy(dev->name, name, IFNAMSIZ);	wl->dev = dev;	/* map chip registers (47xx: and sprom) */	dev->base_addr = regs;	if (bustype == PCI_BUS) {		/* piomode can be overwritten by command argument */		wl->piomode = piomode;		WL_TRACE(("PCI/%s\n", wl->piomode ? "PIO" : "DMA"));	}	else {		WL_ERROR(("wl%d: Only PCI BUS devices are supported \n", unit));		goto fail;	}	wl->bustype = bustype;	if ((wl->regsva = ioremap_nocache(dev->base_addr, PCI_BAR0_WINSZ)) == NULL) {		WL_ERROR(("wl%d: ioremap() failed\n", unit));		goto fail;	}	spin_lock_init(&wl->lock);	/* common load-time initialization */	if (!(wl->wlc = wlc_attach((void *) wl, vendor, device, unit, wl->piomode,		osh, wl->regsva, wl->bustype, btparam, &err))) {		printf("%s: %s driver failed with code %d\n", dev->name, EPI_VERSION_STR, err);		goto fail;	}	wl->pub = (wlc_pub_t *)wl->wlc;#if defined(CONFIG_PROC_FS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0))	/* create /proc/net/wl<unit> */	sprintf(tmp, "net/wl%d", wl->pub->unit);	create_proc_read_entry(tmp, 0, 0, wl_read_proc, (void*)wl);#endif /* defined(CONFIG_PROC_FS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)) */	bcopy(&wl->pub->cur_etheraddr, dev->dev_addr, ETHER_ADDR_LEN);#if WL_TASKLET	/* setup the bottom half handler */	tasklet_init(&wl->tasklet, wl_dpc, (ulong)wl);#endif /* WL_TASKLET */	/* register our interrupt handler */	{		if (request_irq(irq, wl_isr, SA_SHIRQ, dev->name, wl)) {			WL_ERROR(("wl%d: request_irq() failed\n", unit));			goto fail;		}		dev->irq = irq;	}	/* lastly, enable our entry points */	dev->open = wl_open;	dev->stop = wl_close;	dev->hard_start_xmit = wl_start;	dev->get_stats = wl_get_stats;	dev->set_mac_address = wl_set_mac_address;	dev->set_multicast_list = wl_set_multicast_list;	dev->do_ioctl = wl_ioctl;#ifdef CONFIG_NET_RADIO	dev->get_wireless_stats = wl_get_wireless_stats;#if WIRELESS_EXT > 12	dev->wireless_handlers = (struct iw_handler_def *) &wl_iw_handler_def;#endif /* WIRELESS_EXT > 12 */#endif /* CONFIG_NET_RADIO */	if (register_netdev(dev)) {		WL_ERROR(("wl%d: register_netdev() failed\n", unit));		goto fail;	}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)	/* load the tkip module */	wl->tkipmodops = ieee80211_get_crypto_ops("TKIP");	if (wl->tkipmodops == NULL) {		request_module("ieee80211_crypt_tkip");		wl->tkipmodops = ieee80211_get_crypto_ops("TKIP");	}	WL_ERROR(("TkipModule OPs at 0x%x\n",  (uint)wl->tkipmodops));#endif	wl->iw.wlinfo = (void *)wl;	/* print hello string */	printf("%s: Broadcom BCM%04x 802.11 Wireless Controller " EPI_VERSION_STR,		dev->name, device);	printf("\n");	wl_found++;	return wl;fail:	wl_free(wl);	return NULL;}#if defined(CONFIG_PROC_FS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0))static intwl_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data){	wl_info_t *wl;	int len;	off_t pos;	off_t begin;	len = pos = begin = 0;	wl = (wl_info_t*) data;	len = wl_dump(wl, buffer, WLC_IOCTL_MAXLEN);	pos = begin + len;	if (pos < offset) {		len = 0;		begin = pos;	}	*eof = 1;	*start = buffer + (offset - begin);	len -= (offset - begin);	if (len > length)		len = length;	return (len);}#endif /* defined(CONFIG_PROC_FS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)) */#ifdef CONFIG_PCI/**  * determines if a device is a WL device, and if so, attaches it. * * This function determines if a device pointed to by pdev is a WL device, * and if so, performs a wl_attach() on it. * */int __devinitwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent){	wl_info_t *wl;	WL_TRACE(("wl_pci_probe: bus %d slot %d func %d irq %d\n",		pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->irq));	if (!wlc_chipmatch(pdev->vendor, pdev->device))		return (-ENODEV);	pci_set_master(pdev);	pci_enable_device(pdev);	wl = wl_attach(pdev->vendor, pdev->device, pci_resource_start(pdev, 0), PCI_BUS, pdev,		pdev->irq);	if (!wl)		return -ENODEV;	pci_set_drvdata(pdev, wl);	return 0;}static intwl_suspend(struct pci_dev *pdev, u32 state){	wl_info_t *wl;	WL_TRACE(("wl: wl_suspend\n"));	if ((wl = (wl_info_t *) pci_get_drvdata(pdev))) {		netif_device_detach(wl->dev);		WL_LOCK(wl);		wl_down(wl);		WL_UNLOCK(wl);	}	return 0;}static intwl_resume(struct pci_dev *pdev){	wl_info_t *wl;	int error;	error = 0;	if ((wl = (wl_info_t *) pci_get_drvdata(pdev))) {		WL_LOCK(wl);		error = wl_up(wl);		WL_UNLOCK(wl);		netif_device_attach(wl->dev);	}	return (error);}/* Compatibility routines */#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)static void_wl_suspend(struct pci_dev *pdev){	wl_suspend(pdev, 0);}static void_wl_resume(struct pci_dev *pdev){	wl_resume(pdev);}#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6) */static void __devexitwl_remove(struct pci_dev *pdev){	wl_info_t *wl;	if (!wlc_chipmatch(pdev->vendor, pdev->device)) {		return;	}	if ((wl = (wl_info_t *) pci_get_drvdata(pdev))) {		wl_suspend(pdev, 0);		wl_free(wl);		pci_set_drvdata(pdev, NULL);	}}static struct pci_driver wl_pci_driver = {	name:		"wl",	probe:		wl_pci_probe,#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)	suspend:	_wl_suspend,	resume:		_wl_resume,#else	suspend:	wl_suspend,	resume:		wl_resume,#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6) */	remove:		__devexit_p(wl_remove),	id_table:	wl_id_table,	};#endif	/* CONFIG_PCI *//**  * This is the main entry point for the WL driver. * * This function determines if a device pointed to by pdev is a WL device, * and if so, performs a wl_attach() on it. * */static int __initwl_module_init(void){	int error = -ENODEV;#ifdef CONFIG_PCI	if (!(error = pci_module_init(&wl_pci_driver)))		return (0);#endif	/* CONFIG_PCI */	return (error);}/**  * This function unloads the WL driver from the system. * * This function unconditionally unloads the WL driver module from the * system. * */static void __exitwl_module_exit(void){#ifdef CONFIG_PCI	pci_unregister_driver(&wl_pci_driver);#endif	/* CONFIG_PCI */}module_init(wl_module_init);module_exit(wl_module_exit);/**  * This function frees the WL per-device resources. * * This function frees resources owned by the WL device pointed to * by the wl parameter. * */voidwl_free(wl_info_t *wl){	wl_timer_t *t, *next;	osl_t *osh;	WL_TRACE(("wl: wl_free\n"));	{		if (wl->dev && wl->dev->irq)			free_irq(wl->dev->irq, wl);	}	if (wl->dev) {		wl_free_if(wl, WL_DEV_IF(wl->dev));		wl->dev = NULL;	}#if WL_TASKLET	/* kill dpc */	tasklet_kill(&wl->tasklet);#endif /* WL_TASKLET */	/* free common resources */	if (wl->wlc) {#if defined(CONFIG_PROC_FS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0))		char tmp[128];		/* remove /proc/net/wl<unit> */		sprintf(tmp, "net/wl%d", wl->pub->unit);		remove_proc_entry(tmp, 0);#endif /* defined(CONFIG_PROC_FS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)) */		wlc_detach(wl->wlc);		wl->wlc = NULL;		wl->pub = NULL;	}	/* virtual interface deletion is deferred so we cannot spinwait */	/* wait for all pending callbacks to complete */

⌨️ 快捷键说明

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