📄 airo.c
字号:
clear_bit(JOB_XMIT11, &priv->flags); clear_bit(FLAG_PENDING_XMIT11, &priv->flags); status = transmit_802_11_packet (priv, fids[fid], skb->data); up(&priv->sem); i = MAX_FIDS / 2; if ( status == SUCCESS ) { dev->trans_start = jiffies; for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); } else { priv->fids[fid] &= 0xffff; priv->stats.tx_window_errors++; } if (i < MAX_FIDS) netif_wake_queue(dev); dev_kfree_skb(skb);}static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { s16 len; int i, j; struct airo_info *priv = dev->priv; u32 *fids = priv->fids; if ( skb == NULL ) { printk( KERN_ERR "airo: skb == NULL!!!\n" ); return 0; } /* Find a vacant FID */ for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ ); for( j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++ ); if ( j >= MAX_FIDS ) { netif_stop_queue(dev); if (i == MAX_FIDS) { priv->stats.tx_fifo_errors++; return 1; } } /* check min length*/ len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* Mark fid as used & save length for later */ fids[i] |= (len << 16); priv->xmit11.skb = skb; priv->xmit11.fid = i; if (down_trylock(&priv->sem) != 0) { set_bit(FLAG_PENDING_XMIT11, &priv->flags); netif_stop_queue(dev); set_bit(JOB_XMIT11, &priv->flags); wake_up_interruptible(&priv->thr_wait); } else airo_end_xmit11(dev); return 0;}static void airo_read_stats(struct airo_info *ai) { StatsRid stats_rid; u32 *vals = stats_rid.vals; clear_bit(JOB_STATS, &ai->flags); readStatsRid(ai, &stats_rid, RID_STATS, 0); up(&ai->sem); ai->stats.rx_packets = vals[43] + vals[44] + vals[45]; ai->stats.tx_packets = vals[39] + vals[40] + vals[41]; ai->stats.rx_bytes = vals[92]; ai->stats.tx_bytes = vals[91]; ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4]; ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors; ai->stats.multicast = vals[43]; ai->stats.collisions = vals[89]; /* detailed rx_errors: */ ai->stats.rx_length_errors = vals[3]; ai->stats.rx_crc_errors = vals[4]; ai->stats.rx_frame_errors = vals[2]; ai->stats.rx_fifo_errors = vals[0];}struct net_device_stats *airo_get_stats(struct net_device *dev){ struct airo_info *local = dev->priv; /* Get stats out of the card if available */ if (down_trylock(&local->sem) != 0) { set_bit(JOB_STATS, &local->flags); wake_up_interruptible(&local->thr_wait); } else airo_read_stats(local); return &local->stats;}static void airo_set_promisc(struct airo_info *ai) { Cmd cmd; Resp rsp; memset(&cmd, 0, sizeof(cmd)); cmd.cmd=CMD_SETMODE; clear_bit(JOB_PROMISC, &ai->flags); cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC; issuecommand(ai, &cmd, &rsp); up(&ai->sem);}static void airo_set_multicast_list(struct net_device *dev) { struct airo_info *ai = dev->priv; if ((dev->flags ^ ai->flags) & IFF_PROMISC) { change_bit(FLAG_PROMISC, &ai->flags); if (down_trylock(&ai->sem) != 0) { set_bit(JOB_PROMISC, &ai->flags); wake_up_interruptible(&ai->thr_wait); } else airo_set_promisc(ai); } if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) { /* Turn on multicast. (Should be already setup...) */ }}static int airo_set_mac_address(struct net_device *dev, void *p){ struct airo_info *ai = dev->priv; struct sockaddr *addr = p; Resp rsp; readConfigRid(ai, 1); memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); ai->need_commit = 1; disable_MAC(ai, 1); writeConfigRid (ai, 1); enable_MAC(ai, &rsp, 1); memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len); if (ai->wifidev) memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len); return 0;}static int airo_change_mtu(struct net_device *dev, int new_mtu){ if ((new_mtu < 68) || (new_mtu > 2400)) return -EINVAL; dev->mtu = new_mtu; return 0;}static int airo_close(struct net_device *dev) { struct airo_info *ai = dev->priv; netif_stop_queue(dev); if (ai->wifidev != dev) {#ifdef POWER_ON_DOWN /* Shut power to the card. The idea is that the user can save * power when he doesn't need the card with "ifconfig down". * That's the method that is most friendly towards the network * stack (i.e. the network stack won't try to broadcast * anything on the interface and routes are gone. Jean II */ set_bit(FLAG_RADIO_DOWN, &ai->flags); disable_MAC(ai, 1);#endif disable_interrupts( ai ); } return 0;}static void del_airo_dev( struct net_device *dev );void stop_airo_card( struct net_device *dev, int freeres ){ struct airo_info *ai = dev->priv; disable_interrupts(ai); free_irq( dev->irq, dev ); takedown_proc_entry( dev, ai ); if (ai->registered) { unregister_netdev( dev ); if (ai->wifidev) { unregister_netdev(ai->wifidev); free_netdev(ai->wifidev); ai->wifidev = 0; } ai->registered = 0; } set_bit(JOB_DIE, &ai->flags); kill_proc(ai->thr_pid, SIGTERM, 1); wait_for_completion(&ai->thr_exited); if (ai->flash) kfree(ai->flash); if (ai->rssi) kfree(ai->rssi); if (freeres) { /* PCMCIA frees this stuff, so only for PCI and ISA */ release_region( dev->base_addr, 64 ); }#ifdef MICSUPPORT if (ai->tfm) crypto_free_tfm(ai->tfm);#endif del_airo_dev( dev ); free_netdev( dev );}EXPORT_SYMBOL(stop_airo_card);static int add_airo_dev( struct net_device *dev );int wll_header_parse(struct sk_buff *skb, unsigned char *haddr){ memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); return ETH_ALEN;}static void wifi_setup(struct net_device *dev, struct net_device *ethdev){ struct airo_info *ai = ethdev->priv; dev->priv = ai; dev->hard_header = 0; dev->rebuild_header = 0; dev->hard_header_cache = 0; dev->header_cache_update= 0; dev->hard_header_parse = wll_header_parse; dev->hard_start_xmit = &airo_start_xmit11; dev->get_stats = &airo_get_stats; dev->set_mac_address = &airo_set_mac_address; dev->do_ioctl = &airo_ioctl;#ifdef WIRELESS_EXT dev->get_wireless_stats = airo_get_wireless_stats;#if WIRELESS_EXT > 12 dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;#endif /* WIRELESS_EXT > 12 */#endif /* WIRELESS_EXT */ dev->change_mtu = &airo_change_mtu; dev->open = &airo_open; dev->stop = &airo_close; dev->irq = ethdev->irq; dev->base_addr = ethdev->base_addr; dev->type = ARPHRD_IEEE80211; dev->hard_header_len = ETH_HLEN; dev->mtu = 2312; dev->addr_len = ETH_ALEN; memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); dev->tx_queue_len = 100; memset(dev->broadcast,0xFF, ETH_ALEN); dev->flags = IFF_BROADCAST|IFF_MULTICAST;}static struct net_device *init_wifidev(struct airo_info *ai, struct net_device *ethdev){ int err; struct net_device *dev = (struct net_device*)kmalloc(sizeof *dev,GFP_KERNEL); if (!dev) return 0; memset(dev, 0, sizeof(*dev)); strcpy(dev->name, "wifi%d"); dev->priv = ai; wifi_setup(dev, ethdev); err = register_netdev(dev); if (err<0) { kfree(dev); return 0; } return dev;}struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ){ struct net_device *dev; struct airo_info *ai; int i, rc; /* Create the network device object. */ dev = alloc_etherdev(sizeof(*ai)); if (!dev) { printk(KERN_ERR "airo: Couldn't alloc_etherdev\n"); return NULL; } if (dev_alloc_name(dev, dev->name) < 0) { printk(KERN_ERR "airo: Couldn't get name!\n"); goto err_out_free; } ai = dev->priv; ai->wifidev = 0; ai->registered = 0; ai->dev = dev; ai->aux_lock = SPIN_LOCK_UNLOCKED; sema_init(&ai->sem, 1); ai->need_commit = 0; ai->config.len = 0; init_waitqueue_head (&ai->thr_wait); init_completion (&ai->thr_exited); ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES); if (ai->thr_pid < 0) goto err_out_free;#ifdef MICSUPPORT ai->tfm = NULL;#endif rc = add_airo_dev( dev ); if (rc) goto err_out_thr; /* The Airo-specific entries in the device structure. */ dev->hard_start_xmit = &airo_start_xmit; dev->get_stats = &airo_get_stats; dev->set_multicast_list = &airo_set_multicast_list; dev->set_mac_address = &airo_set_mac_address; dev->do_ioctl = &airo_ioctl;#ifdef WIRELESS_EXT dev->get_wireless_stats = airo_get_wireless_stats;#if WIRELESS_EXT > 12 dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;#endif /* WIRELESS_EXT > 12 */#endif /* WIRELESS_EXT */ dev->change_mtu = &airo_change_mtu; dev->open = &airo_open; dev->stop = &airo_close; dev->irq = irq; dev->base_addr = port; rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev ); if (rc) { printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc ); goto err_out_unlink; } if (!is_pcmcia) { if (!request_region( dev->base_addr, 64, dev->name )) { rc = -EBUSY; goto err_out_irq; } } if (probe) { if ( setup_card( ai, dev->dev_addr ) != SUCCESS ) { printk( KERN_ERR "airo: MAC could not be enabled\n" ); rc = -EIO; goto err_out_res; } } else { ai->bap_read = fast_bap_read; set_bit(FLAG_FLASHING, &ai->flags); } rc = register_netdev(dev); if (rc) goto err_out_res; ai->wifidev = init_wifidev(ai, dev); ai->registered = 1; printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", dev->name, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); /* Allocate the transmit buffers */ if (probe) for( i = 0; i < MAX_FIDS; i++ ) ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2); setup_proc_entry( dev, dev->priv ); /* XXX check for failure */ netif_start_queue(dev); SET_MODULE_OWNER(dev); return dev;err_out_res: if (!is_pcmcia) release_region( dev->base_addr, 64 );err_out_irq: free_irq(dev->irq, dev);err_out_unlink: del_airo_dev(dev);err_out_thr: set_bit(JOB_DIE, &ai->flags); kill_proc(ai->thr_pid, SIGTERM, 1); wait_for_completion(&ai->thr_exited);err_out_free: kfree(dev); return NULL;}EXPORT_SYMBOL(init_airo_card);static int waitbusy (struct airo_info *ai) { int delay = 0; while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) { udelay (10); if (++delay % 20) OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); } return delay < 10000;}int reset_airo_card( struct net_device *dev ) { int i; struct airo_info *ai = dev->priv; if (down_interruptible(&ai->sem)) return -1; waitbusy (ai); OUT4500(ai,COMMAND,CMD_SOFTRESET); set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout (HZ/5); waitbusy (ai); set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout (HZ/5); if ( setup_card(ai, dev->dev_addr ) != SUCCESS ) { printk( KERN_ERR "airo: MAC could not be enabled\n" ); up(&ai->sem); return -1; } else { printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", dev->name, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); /* Allocate the transmit buffers */ for( i = 0; i < MAX_FIDS; i++ ) ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2); } enable_interrupts( ai ); netif_wake_queue(dev); up(&ai->sem); return 0;}EXPORT_SYMBOL(reset_airo_card);#if WIRELESS_EXT > 13static void airo_send_event(struct net_device *dev) { struct airo_info *ai = dev->priv; union iwreq_data wrqu; StatusRid status_rid; clear_bit(JOB_EVENT, &ai->flags); PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0); up(&ai->sem); wrqu.data.length = 0; wrqu.data.flags = 0; memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);}#endifstatic int airo_thread(void *data) { struct net_device *dev = data; struct airo_info *ai = dev->priv; int locked; daemonize(); reparent_to_init(); spin_lock_irq(¤t->sigmask_lock); sigemptyset(¤t->blocked); recalc_sigpending(current
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -