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