📄 wl3501_cs.c
字号:
.sig_id = WL3501_SIG_ASSOC_REQ, .timeout = 1000, .listen_interval = 5, .cap_info = this->cap_info, }; dprintk(3, "entry"); memcpy(sig.mac_addr, this->bssid, ETH_ALEN); return wl3501_esbq_exec(this, &sig, sizeof(sig));}static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr){ struct wl3501_card *this = dev->priv; struct wl3501_join_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) { if (this->net_type == IW_MODE_INFRA) { if (this->join_sta_bss < this->bss_cnt) { const int i = this->join_sta_bss; memcpy(this->bssid, this->bss_set[i].bssid, ETH_ALEN); this->chan = this->bss_set[i].ds_pset.chan; iw_copy_mgmt_info_element(&this->keep_essid.el, &this->bss_set[i].ssid.el); wl3501_mgmt_auth(this); } } else { const int i = this->join_sta_bss; memcpy(&this->bssid, &this->bss_set[i].bssid, ETH_ALEN); this->chan = this->bss_set[i].ds_pset.chan; iw_copy_mgmt_info_element(&this->keep_essid.el, &this->bss_set[i].ssid.el); wl3501_online(dev); } } else { int i; this->join_sta_bss++; for (i = this->join_sta_bss; i < this->bss_cnt; i++) if (!wl3501_mgmt_join(this, i)) break; this->join_sta_bss = i; if (this->join_sta_bss == this->bss_cnt) { if (this->net_type == IW_MODE_INFRA) wl3501_mgmt_scan(this, 100); else { this->adhoc_times++; if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) wl3501_mgmt_start(this); else wl3501_mgmt_scan(this, 100); } } }}static inline void wl3501_alarm_interrupt(struct net_device *dev, struct wl3501_card *this){ if (this->net_type == IW_MODE_INFRA) { printk(KERN_INFO "Wireless LAN offline\n"); netif_stop_queue(dev); wl3501_mgmt_resync(this); }}static inline void wl3501_md_confirm_interrupt(struct net_device *dev, struct wl3501_card *this, u16 addr){ struct wl3501_md_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); wl3501_free_tx_buffer(this, sig.data); if (netif_queue_stopped(dev)) netif_wake_queue(dev);}static inline void wl3501_md_ind_interrupt(struct net_device *dev, struct wl3501_card *this, u16 addr){ struct wl3501_md_ind sig; struct sk_buff *skb; u8 rssi, addr4[ETH_ALEN]; u16 pkt_len; wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); this->start_seg = sig.data; wl3501_get_from_wla(this, sig.data + offsetof(struct wl3501_rx_hdr, rssi), &rssi, sizeof(rssi)); this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255; wl3501_get_from_wla(this, sig.data + offsetof(struct wl3501_rx_hdr, addr4), &addr4, sizeof(addr4)); if (!(addr4[0] == 0xAA && addr4[1] == 0xAA && addr4[2] == 0x03 && addr4[4] == 0x00)) { printk(KERN_INFO "Insupported packet type!\n"); return; } pkt_len = sig.size + 12 - 24 - 4 - 6; skb = dev_alloc_skb(pkt_len + 5); if (!skb) { printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n", dev->name, pkt_len); this->stats.rx_dropped++; } else { skb->dev = dev; skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */ eth_copy_and_sum(skb, (unsigned char *)&sig.daddr, 12, 0); wl3501_receive(this, skb->data, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); dev->last_rx = jiffies; this->stats.rx_packets++; this->stats.rx_bytes += skb->len; netif_rx(skb); }}static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this, u16 addr, void *sig, int size){ dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &this->sig_get_confirm, sizeof(this->sig_get_confirm)); wake_up(&this->wait);}static inline void wl3501_start_confirm_interrupt(struct net_device *dev, struct wl3501_card *this, u16 addr){ struct wl3501_start_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) netif_wake_queue(dev);}static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, u16 addr){ struct wl3501_card *this = dev->priv; struct wl3501_assoc_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) wl3501_online(dev);}static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this, u16 addr){ struct wl3501_auth_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) wl3501_mgmt_association(this); else wl3501_mgmt_resync(this);}static inline void wl3501_rx_interrupt(struct net_device *dev){ int morepkts; u16 addr; u8 sig_id; struct wl3501_card *this = dev->priv; dprintk(3, "entry");loop: morepkts = 0; if (!wl3501_esbq_confirm(this)) goto free; wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr)); wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id)); switch (sig_id) { case WL3501_SIG_DEAUTH_IND: case WL3501_SIG_DISASSOC_IND: case WL3501_SIG_ALARM: wl3501_alarm_interrupt(dev, this); break; case WL3501_SIG_MD_CONFIRM: wl3501_md_confirm_interrupt(dev, this, addr); break; case WL3501_SIG_MD_IND: wl3501_md_ind_interrupt(dev, this, addr); break; case WL3501_SIG_GET_CONFIRM: wl3501_get_confirm_interrupt(this, addr, &this->sig_get_confirm, sizeof(this->sig_get_confirm)); break; case WL3501_SIG_PWR_MGMT_CONFIRM: wl3501_get_confirm_interrupt(this, addr, &this->sig_pwr_mgmt_confirm, sizeof(this->sig_pwr_mgmt_confirm)); break; case WL3501_SIG_START_CONFIRM: wl3501_start_confirm_interrupt(dev, this, addr); break; case WL3501_SIG_SCAN_CONFIRM: wl3501_mgmt_scan_confirm(this, addr); break; case WL3501_SIG_JOIN_CONFIRM: wl3501_mgmt_join_confirm(dev, addr); break; case WL3501_SIG_ASSOC_CONFIRM: wl3501_assoc_confirm_interrupt(dev, addr); break; case WL3501_SIG_AUTH_CONFIRM: wl3501_auth_confirm_interrupt(this, addr); break; case WL3501_SIG_RESYNC_CONFIRM: wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */ break; } wl3501_esbq_confirm_done(this); morepkts = 1; /* free request if necessary */free: wl3501_esbq_req_free(this); if (morepkts) goto loop;}static inline void wl3501_ack_interrupt(struct wl3501_card *this){ wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR);}/** * wl3501_interrupt - Hardware interrupt from card. * @irq - Interrupt number * @dev_id - net_device * @regs - registers * * We must acknowledge the interrupt as soon as possible, and block the * interrupt from the same card immediately to prevent re-entry. * * Before accessing the Control_Status_Block, we must lock SUTRO first. * On the other hand, to prevent SUTRO from malfunctioning, we must * unlock the SUTRO as soon as possible. */static irqreturn_t wl3501_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *)dev_id; struct wl3501_card *this; int handled = 1; if (!dev) goto unknown; this = dev->priv; spin_lock(&this->lock); wl3501_ack_interrupt(this); wl3501_block_interrupt(this); wl3501_rx_interrupt(dev); wl3501_unblock_interrupt(this); spin_unlock(&this->lock);out: return IRQ_RETVAL(handled);unknown: handled = 0; printk(KERN_ERR "%s: irq %d for unknown device.\n", __FUNCTION__, irq); goto out;}static int wl3501_reset_board(struct wl3501_card *this){ u8 tmp = 0; int i, rc = 0; /* Coreset */ wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); /* Reset SRAM 0x480 to zero */ wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); /* Start up */ wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); WL3501_NOPLOOP(1024 * 50); wl3501_unblock_interrupt(this); /* acme: was commented */ /* Polling Self_Test_Status */ for (i = 0; i < 10000; i++) { wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp)); if (tmp == 'W') { /* firmware complete all test successfully */ tmp = 'A'; wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); goto out; } WL3501_NOPLOOP(10); } printk(KERN_WARNING "%s: failed to reset the board!\n", __FUNCTION__); rc = -ENODEV;out: return rc;}static int wl3501_init_firmware(struct wl3501_card *this){ u16 ptr, next; int rc = wl3501_reset_board(this); if (rc) goto fail; this->card_name[0] = '\0'; wl3501_get_from_wla(this, 0x1a00, this->card_name, sizeof(this->card_name)); this->card_name[sizeof(this->card_name) - 1] = '\0'; this->firmware_date[0] = '\0'; wl3501_get_from_wla(this, 0x1a40, this->firmware_date, sizeof(this->firmware_date)); this->firmware_date[sizeof(this->firmware_date) - 1] = '\0'; /* Switch to SRAM Page 0 */ wl3501_switch_page(this, WL3501_BSS_SPAGE0); /* Read parameter from card */ wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2); wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2); wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2); wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2); wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2); wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2); this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start; this->esbq_req_end += this->esbq_req_start; this->esbq_confirm = this->esbq_confirm_start; this->esbq_confirm_end += this->esbq_confirm_start; /* Initial Tx Buffer */ this->tx_buffer_cnt = 1; ptr = this->tx_buffer_head; next = ptr + WL3501_BLKSZ; while ((next - this->tx_buffer_head) < this->tx_buffer_size) { this->tx_buffer_cnt++; wl3501_set_to_wla(this, ptr, &next, sizeof(next)); ptr = next; next = ptr + WL3501_BLKSZ; } rc = 0; next = 0; wl3501_set_to_wla(this, ptr, &next, sizeof(next)); this->tx_buffer_tail = ptr;out: return rc;fail: printk(KERN_WARNING "%s: failed!\n", __FUNCTION__); goto out;}static int wl3501_close(struct net_device *dev){ struct wl3501_card *this = dev->priv; int rc = -ENODEV; unsigned long flags; dev_link_t *link; spin_lock_irqsave(&this->lock, flags); /* Check if the device is in wl3501_dev_list */ for (link = wl3501_dev_list; link; link = link->next) if (link->priv == dev) break; if (!link) goto out; link->open--; /* Stop wl3501_hard_start_xmit() from now on */ netif_stop_queue(dev); wl3501_ack_interrupt(this); /* Mask interrupts from the SUTRO */ wl3501_block_interrupt(this); rc = 0; printk(KERN_INFO "%s: WL3501 closed\n", dev->name);out: spin_unlock_irqrestore(&this->lock, flags); return rc;}/** * wl3501_reset - Reset the SUTRO. * @dev - network device * * It is almost the same as wl3501_open(). In fact, we may just wl3501_close() * and wl3501_open() again, but I wouldn't like to free_irq() when the driver * is running. It seems to be dangerous. */static int wl3501_reset(struct net_device *dev){ struct wl3501_card *this = dev->priv; int rc = -ENODEV; wl3501_block_interrupt(this); if (wl3501_init_firmware(this)) { printk(KERN_WARNING "%s: Can't initialize Firmware!\n", dev->name); /* Free IRQ, and mark IRQ as unused */ free_irq(dev->irq, dev); goto out; } /* * Queue has to be started only when the Card is Started */ netif_stop_queue(dev); this->adhoc_times = 0; wl3501_ack_interrupt(this); wl3501_unblock_interrupt(this); wl3501_mgmt_scan(this, 100); dprintk(1, "%s: device reset", dev->name); rc = 0;out: return rc;}static void wl3501_tx_timeout(struct net_device *dev){ struct wl3501_card *this = dev->priv; struct net_device_stats *stats = &this->stats; unsigned long flags; int rc; stats->tx_errors++; spin_lock_irqsave(&this->lock, flags); rc = wl3501_reset(dev); spin_unlock_irqrestore(&this->lock, flags); if (rc) printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", dev->name, rc); else { dev->trans_start = jiffies; netif_wake_queue(dev); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -