wl_linux.c

来自「wi-fi sources for asus wl138g v2 pci car」· C语言 代码 · 共 1,790 行 · 第 1/3 页

C
1,790
字号
	while (wl->callbacks > 0)		schedule();	/* free timers */	for (t = wl->timers; t; t = next) {		next = t->next;		MFREE(wl->osh, t, sizeof(wl_timer_t));	}	/* free monitor */	if (wl->monitor) {		unregister_netdev(wl->monitor);		MFREE(wl->osh, wl->monitor, sizeof(struct net_device));		wl->monitor = NULL;	}	osh = wl->osh;	/*	 * unregister_netdev() calls get_stats() which may read chip registers	 * so we cannot unmap the chip registers until after calling unregister_netdev() .	 */	if (wl->regsva)		iounmap((void*)wl->regsva);	wl->regsva = NULL;	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)	/* un register the TKIP module...if any */	if (wl->tkipmodops != NULL) {		if (wl->tkip_ucast_data) {			wl->tkipmodops->deinit(wl->tkip_ucast_data);			wl->tkip_ucast_data = NULL;		}		if (wl->tkip_bcast_data) {			wl->tkipmodops->deinit(wl->tkip_bcast_data);			wl->tkip_bcast_data = NULL;		}	}#endif	MFREE(osh, wl, sizeof(wl_info_t));	if (MALLOCED(osh)) {		printf("Memory leak of bytes %d\n", MALLOCED(osh));		ASSERT(0);	}	osl_detach(osh);}static intwl_open(struct net_device *dev){	wl_info_t *wl;	int error;	wl = WL_INFO(dev);	WL_TRACE(("wl%d: wl_open\n", wl->pub->unit));	WL_LOCK(wl);	error = wl_up(wl);	if (!error) {		WL_ERROR(("about to set the promisc bit %d\n", error));		error = wlc_set(wl->wlc, WLC_SET_PROMISC, (dev->flags & IFF_PROMISC));		WL_ERROR(("after the set to the promisc bit %d\n", error));	}	WL_UNLOCK(wl);	if (!error)		OLD_MOD_INC_USE_COUNT;	return (error? -ENODEV: 0);}static intwl_close(struct net_device *dev){	wl_info_t *wl;	wl = WL_INFO(dev);	WL_TRACE(("wl%d: wl_close\n", wl->pub->unit));	WL_LOCK(wl);	wl_down(wl);	WL_UNLOCK(wl);	OLD_MOD_DEC_USE_COUNT;	return (0);}/* transmit a packet */static intwl_start(struct sk_buff *skb, struct net_device *dev){	wl_info_t *wl;	wl_if_t *wlif;	void *pkt;	wlif = WL_DEV_IF(dev);	wl = wlif->wl;	WL_TRACE(("wl%d: wl_start: len %d\n", wl->pub->unit, skb->len));	/* Convert the packet. Mainly attach a pkttag */	if ((pkt = PKTFRMNATIVE(wl->osh, skb)) == NULL) {		dev_kfree_skb_any(skb);		return -ENOMEM;	}	WL_LOCK(wl);	wlc_sendpkt(wl->wlc, pkt, wlif->wlcif);	WL_UNLOCK(wl);	return (0);}voidwl_txflowcontrol(wl_info_t *wl, bool state){	wl_if_t *wlif;	for (wlif = wl->if_list; wlif != NULL; wlif = wlif->next) {		if (state == ON)			netif_stop_queue(wlif->dev);		else			netif_wake_queue(wlif->dev);	}}/* Schedule a completion handler to run at safe time */static intwl_schedule_task(wl_info_t *wl, void (*fn)(struct wl_task *task), void *context){	wl_task_t *task;	WL_TRACE(("wl%d: wl_schedule_task\n", wl->pub->unit));	if (!(task = MALLOC(wl->osh, sizeof(wl_task_t)))) {		WL_ERROR(("wl%d: wl_schedule_task: out of memory, malloced %d bytes\n",			wl->pub->unit, MALLOCED(wl->osh)));		return -ENOMEM;	}	INIT_WORK(&task->work, (void (*)(void *)) fn, task);	task->context = context;	if (!schedule_work(&task->work)) {		WL_ERROR(("wl%d: schedule_work() failed\n", wl->pub->unit));		MFREE(wl->osh, task, sizeof(wl_task_t));		return -ENOMEM;	}	wl->callbacks++;	return 0;}struct wl_if *wl_alloc_if(wl_info_t *wl, int iftype, uint subunit, struct wlc_if* wlcif){	struct net_device *dev;	wl_if_t *wlif;	wl_if_t *p;	if (!(wlif = MALLOC(wl->osh, sizeof(wl_if_t) + sizeof(struct net_device)))) {		WL_ERROR(("wl%d: wl_alloc_if: out of memory, malloced %d bytes\n",		          (wl->pub)?wl->pub->unit:subunit, MALLOCED(wl->osh)));		return NULL;	}	bzero(wlif, sizeof(wl_if_t) + sizeof(struct net_device));	dev = (struct net_device *) &wlif[1];	wlif->type = iftype;	wlif->dev = dev;	wlif->wl = wl;	wlif->wlcif = wlcif;	wlif->subunit = subunit;	ether_setup(dev);	DEV_WLPTR(dev) = wl;	DEV_WLIFPTR(dev) = wlif;	/* match current flow control state */	if (wl->dev && netif_queue_stopped(wl->dev))		netif_stop_queue(dev);	/* add the interface to the interface linked list */	if (wl->if_list == NULL)		wl->if_list = wlif;	else {		p = wl->if_list;		while (p->next != NULL)			p = p->next;		p->next = wlif;	}	return wlif;}static voidwl_free_if(wl_info_t *wl, wl_if_t *wlif){	wl_if_t *p;	/* remove the interface from the interface linked list */	p = wl->if_list;	if (p == wlif)		wl->if_list = p->next;	else {		while (p != NULL && p->next != wlif)			p = p->next;		if (p != NULL)			p->next = p->next->next;	}	DEV_WLIFPTR(wlif->dev) = NULL;	unregister_netdev(wlif->dev);	MFREE(wl->osh, wlif, sizeof(wl_if_t) + sizeof(struct net_device));}/* Return pointer to interface name */char *wl_ifname(wl_info_t *wl, wl_if_t *wlif){	if (wlif)		return wlif->dev->name;	else		return wl->dev->name;}voidwl_init(wl_info_t *wl){	WL_TRACE(("wl%d: wl_init\n", wl->pub->unit));	wl_reset(wl);	wlc_init(wl->wlc);}uintwl_reset(wl_info_t *wl){	WL_TRACE(("wl%d: wl_reset\n", wl->pub->unit));	wlc_reset(wl->wlc);	return (0);}/* * These are interrupt on/off entry points. * Since the wl_isr is serialized with other driver entries using a spinlock, * they are SMP safe, just call common routine directly, */voidwl_intrson(wl_info_t *wl){	wlc_intrson(wl->wlc);}uint32wl_intrsoff(wl_info_t *wl){	return wlc_intrsoff(wl->wlc);}voidwl_intrsrestore(wl_info_t *wl, uint32 macintmask){	wlc_intrsrestore(wl->wlc, macintmask);}intwl_up(wl_info_t *wl){	int error = 0;	WL_TRACE(("wl%d: wl_up\n", wl->pub->unit));	if (wl->pub->up)		return (0);	error = wlc_up(wl->wlc);	/* wake (not just start) all interfaces */	if (!error)		wl_txflowcontrol(wl, OFF);	return (error);}voidwl_down(wl_info_t *wl){	wl_if_t *wlif;	uint callbacks, ret_val;	WL_TRACE(("wl%d: wl_down\n", wl->pub->unit));	for (wlif = wl->if_list; wlif != NULL; wlif = wlif->next) {		netif_down(wlif->dev);		netif_stop_queue(wlif->dev);	}	/* call common down function */	ret_val  = wlc_down(wl->wlc);	callbacks = wl->callbacks - ret_val;	/* wait for down callbacks to complete */	WL_UNLOCK(wl);	SPINWAIT((wl->callbacks > callbacks), 100 * 1000);	ASSERT(wl->callbacks == callbacks);	WL_LOCK(wl);}#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)static intwl_ethtool(wl_info_t *wl, void *uaddr){	struct ethtool_drvinfo info;	uint32 cmd;	if (copy_from_user(&cmd, uaddr, sizeof(uint32)))		return (-EFAULT);	switch (cmd) {	case ETHTOOL_GDRVINFO:		bzero(&info, sizeof(info));		info.cmd = cmd;		sprintf(info.driver, "wl%d", wl->pub->unit);		strcpy(info.version, EPI_VERSION_STR);		if (copy_to_user(uaddr, &info, sizeof(info)))			return (-EFAULT);		return (0);	}	return (-EOPNOTSUPP);}#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */intwl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	wl_info_t *wl;	wl_if_t *wlif;	void *buf = NULL;	wl_ioctl_t ioc;	int bcmerror;	int status;	wl = WL_INFO(dev);	wlif = WL_DEV_IF(dev);	bcmerror = 0;	status = 0;	WL_TRACE(("wl%d: wl_ioctl: cmd 0x%x\n", wl->pub->unit, cmd));#ifdef CONFIG_NET_RADIO	/* linux wireless extensions */	if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {		/* may recurse, do NOT lock */		return wl_iw_ioctl(dev, ifr, cmd);	}#endif /* CONFIG_NET_RADIO */#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)	if (cmd == SIOCETHTOOL)		return (wl_ethtool(wl, (void*)ifr->ifr_data));#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */	if (cmd != SIOCDEVPRIVATE) {		bcmerror = BCME_UNSUPPORTED;		goto done2;	}	if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {		bcmerror = BCME_BADADDR;		goto done2;	}	/* optimization for direct ioctl calls from kernel */	if (segment_eq(get_fs(), KERNEL_DS))		buf = ioc.buf;	else if (ioc.buf) {		if (!(buf = (void *) MALLOC(wl->osh, MAX(ioc.len, WLC_IOCTL_MAXLEN)))) {			bcmerror = BCME_NORESOURCE;			goto done2;		}		if (copy_from_user(buf, ioc.buf, ioc.len)) {			bcmerror = BCME_BADADDR;			goto done1;		}	}	WL_LOCK(wl);	if (!capable(CAP_NET_ADMIN))		bcmerror = BCME_EPERM;	else {		bcmerror = wlc_ioctl(wl->wlc, ioc.cmd, buf, ioc.len, wlif->wlcif);	}	WL_UNLOCK(wl);done1:	if (ioc.buf && (ioc.buf != buf)) {		if (copy_to_user(ioc.buf, buf, ioc.len))			bcmerror = BCME_BADADDR;		MFREE(wl->osh, buf, MAX(ioc.len, WLC_IOCTL_MAXLEN));	}	if (status)		return status;done2:	ASSERT(VALID_BCMERROR(bcmerror));	if (bcmerror != 0)		wl->pub->bcmerror = bcmerror;	return (OSL_ERROR(bcmerror));}static struct net_device_stats*wl_get_stats(struct net_device *dev){	struct net_device_stats *stats;	wl_info_t *wl = WL_INFO(dev);	WL_TRACE(("wl%d: wl_get_stats\n", wl->pub->unit));	stats = &wl->stats;	WL_LOCK(wl);	/* refresh stats */	if (wl->pub->up)		wlc_statsupd(wl->wlc);	stats->rx_packets = WLCNTVAL(wl->pub->_cnt.rxframe);	stats->tx_packets = WLCNTVAL(wl->pub->_cnt.txframe);	stats->rx_bytes = WLCNTVAL(wl->pub->_cnt.rxbyte);	stats->tx_bytes = WLCNTVAL(wl->pub->_cnt.txbyte);	stats->rx_errors = WLCNTVAL(wl->pub->_cnt.rxerror);	stats->tx_errors = WLCNTVAL(wl->pub->_cnt.txerror);	stats->collisions = 0;	stats->rx_length_errors = 0;	stats->rx_over_errors = WLCNTVAL(wl->pub->_cnt.rxoflo);	stats->rx_crc_errors = WLCNTVAL(wl->pub->_cnt.rxcrc);	stats->rx_frame_errors = 0;	stats->rx_fifo_errors = WLCNTVAL(wl->pub->_cnt.rxoflo);	stats->rx_missed_errors = 0;	stats->tx_fifo_errors = WLCNTVAL(wl->pub->_cnt.txuflo);	WL_UNLOCK(wl);	return (stats);}#ifdef CONFIG_NET_RADIOstatic struct iw_statistics *wl_get_wireless_stats(struct net_device *dev){	int res;	wl_info_t *wl;	wl_if_t *wlif;	struct iw_statistics *wstats;	int phy_noise, rssi;	wl = WL_INFO(dev);	wlif = WL_DEV_IF(dev);	wstats = &wl->iw.wstats;	WL_TRACE(("wl%d: wl_get_wireless_stats\n", wl->pub->unit));	WL_LOCK(wl);	if ((res = wlc_get(wl->wlc, WLC_GET_PHY_NOISE, &phy_noise)))		goto done;	{		scb_val_t scb;		if ((res = wlc_ioctl(wl->wlc, WLC_GET_RSSI, &scb, sizeof(scb), wlif->wlcif)))			goto done;		rssi = scb.val;	}	if (rssi <= WLC_RSSI_NO_SIGNAL)		wstats->qual.qual = 0;	else if (rssi <= WLC_RSSI_VERY_LOW)		wstats->qual.qual = 1;	else if (rssi <= WLC_RSSI_LOW)		wstats->qual.qual = 2;	else if (rssi <= WLC_RSSI_GOOD)		wstats->qual.qual = 3;	else if (rssi <= WLC_RSSI_VERY_GOOD)		wstats->qual.qual = 4;	else		wstats->qual.qual = 5;	/* Wraps to 0 if RSSI is 0 */	wstats->qual.level = 0x100 + rssi;	wstats->qual.noise = 0x100 + phy_noise;	wstats->qual.updated |= 7;#if WIRELESS_EXT > 11	wstats->discard.nwid = 0; 	wstats->discard.code = WLCNTVAL(wl->pub->_cnt.rxundec);	wstats->discard.fragment = WLCNTVAL(wl->pub->_cnt.rxfragerr);	wstats->discard.retries = WLCNTVAL(wl->pub->_cnt.txfail);	wstats->discard.misc = WLCNTVAL(wl->pub->_cnt.rxrunt) + WLCNTVAL(wl->pub->_cnt.rxgiant);	wstats->miss.beacon = 0; #endif /* WIRELESS_EXT > 11 */done:	WL_UNLOCK(wl);	if (res == 0)		return wstats;	else		return NULL;}#endif /* CONFIG_NET_RADIO */static intwl_set_mac_address(struct net_device *dev, void *addr){	wl_info_t *wl;	struct sockaddr *sa = (struct sockaddr *) addr;	wl = WL_INFO(dev);	WL_TRACE(("wl%d: wl_set_mac_address\n", wl->pub->unit));	bcopy(sa->sa_data, dev->dev_addr, ETHER_ADDR_LEN);	if (wlc_iovar_op(wl->wlc, "cur_etheraddr", NULL, 0, sa->sa_data, ETHER_ADDR_LEN,		IOV_SET, (WL_DEV_IF(dev))->wlcif))		WL_ERROR(("wl%d: wl_set_mac_address: error setting MAC addr override\n",			wl->pub->unit));	return 0;}static voidwl_set_multicast_list(struct net_device *dev){	wl_info_t *wl;	struct dev_mc_list *mclist;	int i;	wl = WL_INFO(dev);	WL_TRACE(("wl%d: wl_set_multicast_list\n", wl->pub->unit));	WL_LOCK(wl);	if (wl->pub->up) {		wl->pub->allmulti = (dev->flags & IFF_ALLMULTI)? TRUE: FALSE;		/* copy the list of multicasts into our private table */		for (i = 0, mclist = dev->mc_list; mclist && (i < dev->mc_count);			i++, mclist = mclist->next) {			if (i >= MAXMULTILIST) {				wl->pub->allmulti = TRUE;				i = 0;				break;			}			wl->pub->multicast[i] = *((struct ether_addr*) mclist->dmi_addr);		}		wl->pub->nmulticast = i;		wlc_set(wl->wlc, WLC_SET_PROMISC, (dev->flags & IFF_PROMISC));	}	WL_UNLOCK(wl);}irqreturn_twl_isr(int irq, void *dev_id, struct pt_regs *ptregs){	wl_info_t *wl;	bool ours, wantdpc;	wl = (wl_info_t*) dev_id;	spin_lock(&wl->lock);

⌨️ 快捷键说明

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