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 + -
显示快捷键?