wl3501_cs.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,330 行 · 第 1/5 页
C
2,330 行
spin_unlock_irqrestore(&this->lock, flags);out: return rc;}static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend){ struct wl3501_pwr_mgmt_req sig = { .sig_id = WL3501_SIG_PWR_MGMT_REQ, .pwr_save = suspend, .wake_up = !suspend, .receive_dtims = 10, }; unsigned long flags; int rc = -EIO; spin_lock_irqsave(&this->lock, flags); if (wl3501_esbq_req_test(this)) { u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); if (ptr) { wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); wl3501_esbq_req(this, &ptr); this->sig_pwr_mgmt_confirm.status = 255; spin_unlock_irqrestore(&this->lock, flags); rc = wait_event_interruptible(this->wait, this->sig_pwr_mgmt_confirm.status != 255); printk(KERN_INFO "%s: %s status=%d\n", __FUNCTION__, suspend ? "suspend" : "resume", this->sig_pwr_mgmt_confirm.status); goto out; } } spin_unlock_irqrestore(&this->lock, flags);out: return rc;}/** * wl3501_send_pkt - Send a packet. * @this - card * * Send a packet. * * data = Ethernet raw frame. (e.g. data[0] - data[5] is Dest MAC Addr, * data[6] - data[11] is Src MAC Addr) * Ref: IEEE 802.11 */static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len){ u16 bf, sig_bf, next, tmplen, pktlen; struct wl3501_md_req sig = { .sig_id = WL3501_SIG_MD_REQ, }; u8 *pdata = (char *)data; int rc = -EIO; if (wl3501_esbq_req_test(this)) { sig_bf = wl3501_get_tx_buffer(this, sizeof(sig)); rc = -ENOMEM; if (!sig_bf) /* No free buffer available */ goto out; bf = wl3501_get_tx_buffer(this, len + 26 + 24); if (!bf) { /* No free buffer available */ wl3501_free_tx_buffer(this, sig_bf); goto out; } rc = 0; memcpy(&sig.daddr[0], pdata, 12); pktlen = len - 12; pdata += 12; sig.data = bf; if (((*pdata) * 256 + (*(pdata + 1))) > 1500) { u8 addr4[ETH_ALEN] = { [0] = 0xAA, [1] = 0xAA, [2] = 0x03, [4] = 0x00, }; wl3501_set_to_wla(this, bf + 2 + offsetof(struct wl3501_tx_hdr, addr4), addr4, sizeof(addr4)); sig.size = pktlen + 24 + 4 + 6; if (pktlen > (254 - sizeof(struct wl3501_tx_hdr))) { tmplen = 254 - sizeof(struct wl3501_tx_hdr); pktlen -= tmplen; } else { tmplen = pktlen; pktlen = 0; } wl3501_set_to_wla(this, bf + 2 + sizeof(struct wl3501_tx_hdr), pdata, tmplen); pdata += tmplen; wl3501_get_from_wla(this, bf, &next, sizeof(next)); bf = next; } else { sig.size = pktlen + 24 + 4 - 2; pdata += 2; pktlen -= 2; if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) { tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6; pktlen -= tmplen; } else { tmplen = pktlen; pktlen = 0; } wl3501_set_to_wla(this, bf + 2 + offsetof(struct wl3501_tx_hdr, addr4), pdata, tmplen); pdata += tmplen; wl3501_get_from_wla(this, bf, &next, sizeof(next)); bf = next; } while (pktlen > 0) { if (pktlen > 254) { tmplen = 254; pktlen -= 254; } else { tmplen = pktlen; pktlen = 0; } wl3501_set_to_wla(this, bf + 2, pdata, tmplen); pdata += tmplen; wl3501_get_from_wla(this, bf, &next, sizeof(next)); bf = next; } wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig)); wl3501_esbq_req(this, &sig_bf); }out: return rc;}static int wl3501_mgmt_resync(struct wl3501_card *this){ struct wl3501_resync_req sig = { .sig_id = WL3501_SIG_RESYNC_REQ, }; return wl3501_esbq_exec(this, &sig, sizeof(sig));}static inline int wl3501_fw_bss_type(struct wl3501_card *this){ return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA : WL3501_NET_TYPE_ADHOC;}static inline int wl3501_fw_cap_info(struct wl3501_card *this){ return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS : WL3501_MGMT_CAPABILITY_IBSS;}static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time){ struct wl3501_scan_req sig = { .sig_id = WL3501_SIG_SCAN_REQ, .scan_type = WL3501_SCAN_TYPE_ACTIVE, .probe_delay = 0x10, .min_chan_time = chan_time, .max_chan_time = chan_time, .bss_type = wl3501_fw_bss_type(this), }; this->bss_cnt = this->join_sta_bss = 0; return wl3501_esbq_exec(this, &sig, sizeof(sig));}static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas){ struct wl3501_join_req sig = { .sig_id = WL3501_SIG_JOIN_REQ, .timeout = 10, .ds_pset = { .el = { .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, .len = 1, }, .chan = this->chan, }, }; memcpy(&sig.beacon_period, &this->bss_set[stas].beacon_period, 72); return wl3501_esbq_exec(this, &sig, sizeof(sig));}static int wl3501_mgmt_start(struct wl3501_card *this){ struct wl3501_start_req sig = { .sig_id = WL3501_SIG_START_REQ, .beacon_period = 400, .dtim_period = 1, .ds_pset = { .el = { .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, .len = 1, }, .chan = this->chan, }, .bss_basic_rset = { .el = { .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, .len = 2, }, .data_rate_labels = { [0] = IW_MGMT_RATE_LABEL_MANDATORY | IW_MGMT_RATE_LABEL_1MBIT, [1] = IW_MGMT_RATE_LABEL_MANDATORY | IW_MGMT_RATE_LABEL_2MBIT, }, }, .operational_rset = { .el = { .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, .len = 2, }, .data_rate_labels = { [0] = IW_MGMT_RATE_LABEL_MANDATORY | IW_MGMT_RATE_LABEL_1MBIT, [1] = IW_MGMT_RATE_LABEL_MANDATORY | IW_MGMT_RATE_LABEL_2MBIT, }, }, .ibss_pset = { .el = { .id = IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, .len = 2, }, .atim_window = 10, }, .bss_type = wl3501_fw_bss_type(this), .cap_info = wl3501_fw_cap_info(this), }; iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el); iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el); return wl3501_esbq_exec(this, &sig, sizeof(sig));}static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr){ u16 i = 0; int matchflag = 0; struct wl3501_scan_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) { dprintk(3, "success"); if ((this->net_type == IW_MODE_INFRA && (sig.cap_info & WL3501_MGMT_CAPABILITY_ESS)) || (this->net_type == IW_MODE_ADHOC && (sig.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) || this->net_type == IW_MODE_AUTO) { if (!this->essid.el.len) matchflag = 1; else if (this->essid.el.len == 3 && !memcmp(this->essid.essid, "ANY", 3)) matchflag = 1; else if (this->essid.el.len != sig.ssid.el.len) matchflag = 0; else if (memcmp(this->essid.essid, sig.ssid.essid, this->essid.el.len)) matchflag = 0; else matchflag = 1; if (matchflag) { for (i = 0; i < this->bss_cnt; i++) { if (!memcmp(this->bss_set[i].bssid, sig.bssid, ETH_ALEN)) { matchflag = 0; break; } } } if (matchflag && (i < 20)) { memcpy(&this->bss_set[i].beacon_period, &sig.beacon_period, 73); this->bss_cnt++; this->rssi = sig.rssi; } } } else if (sig.status == WL3501_STATUS_TIMEOUT) { dprintk(3, "timeout"); this->join_sta_bss = 0; 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); } } }}/** * wl3501_block_interrupt - Mask interrupt from SUTRO * @this - card * * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST) * Return: 1 if interrupt is originally enabled */static int wl3501_block_interrupt(struct wl3501_card *this){ u8 old = inb(this->base_addr + WL3501_NIC_GCR); u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC | WL3501_GCR_ENECINT)); wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); return old & WL3501_GCR_ENECINT;}/** * wl3501_unblock_interrupt - Enable interrupt from SUTRO * @this - card * * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST) * Return: 1 if interrupt is originally enabled */static int wl3501_unblock_interrupt(struct wl3501_card *this){ u8 old = inb(this->base_addr + WL3501_NIC_GCR); u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) | WL3501_GCR_ENECINT; wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); return old & WL3501_GCR_ENECINT;}/** * wl3501_receive - Receive data from Receive Queue. * * Receive data from Receive Queue. * * @this: card * @bf: address of host * @size: size of buffer. */static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size){ u16 next_addr, next_addr1; u8 *data = bf + 12; size -= 12; wl3501_get_from_wla(this, this->start_seg + 2, &next_addr, sizeof(next_addr)); if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) { wl3501_get_from_wla(this, this->start_seg + sizeof(struct wl3501_rx_hdr), data, WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)); size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); } else { wl3501_get_from_wla(this, this->start_seg + sizeof(struct wl3501_rx_hdr), data, size); size = 0; } while (size > 0) { if (size > WL3501_BLKSZ - 5) { wl3501_get_from_wla(this, next_addr + 5, data, WL3501_BLKSZ - 5); size -= WL3501_BLKSZ - 5; data += WL3501_BLKSZ - 5; wl3501_get_from_wla(this, next_addr + 2, &next_addr1, sizeof(next_addr1)); next_addr = next_addr1; } else { wl3501_get_from_wla(this, next_addr + 5, data, size); size = 0; } } return 0;}static void wl3501_esbq_req_free(struct wl3501_card *this){ u8 tmp; u16 addr; if (this->esbq_req_head == this->esbq_req_tail) goto out; wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp)); if (!(tmp & 0x80)) goto out; wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr)); wl3501_free_tx_buffer(this, addr); this->esbq_req_tail += 4; if (this->esbq_req_tail >= this->esbq_req_end) this->esbq_req_tail = this->esbq_req_start;out: return;}static int wl3501_esbq_confirm(struct wl3501_card *this){ u8 tmp; wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); return tmp & 0x80;}static void wl3501_online(struct net_device *dev){ struct wl3501_card *this = dev->priv; printk(KERN_INFO "%s: Wireless LAN online. BSSID: " "%02X %02X %02X %02X %02X %02X\n", dev->name, this->bssid[0], this->bssid[1], this->bssid[2], this->bssid[3], this->bssid[4], this->bssid[5]); netif_wake_queue(dev);}static void wl3501_esbq_confirm_done(struct wl3501_card *this){ u8 tmp = 0; wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); this->esbq_confirm += 4; if (this->esbq_confirm >= this->esbq_confirm_end) this->esbq_confirm = this->esbq_confirm_start;}static int wl3501_mgmt_auth(struct wl3501_card *this){ struct wl3501_auth_req sig = { .sig_id = WL3501_SIG_AUTH_REQ, .type = WL3501_SYS_TYPE_OPEN, .timeout = 1000, }; dprintk(3, "entry"); memcpy(sig.mac_addr, this->bssid, ETH_ALEN); return wl3501_esbq_exec(this, &sig, sizeof(sig));}static int wl3501_mgmt_association(struct wl3501_card *this){ struct wl3501_assoc_req sig = { .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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?