wl3501_cs.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,165 行 · 第 1/4 页

C
2,165
字号
	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;	struct pcmcia_device *link;	link = this->p_dev;	spin_lock_irqsave(&this->lock, flags);	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);	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);	}}/* * Return : 0 - OK *	    1 - Could not transmit (dev_queue_xmit will queue it) *		and try to sent it later */static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){	int enabled, rc;	struct wl3501_card *this = dev->priv;	unsigned long flags;	spin_lock_irqsave(&this->lock, flags);	enabled = wl3501_block_interrupt(this);	dev->trans_start = jiffies;	rc = wl3501_send_pkt(this, skb->data, skb->len);	if (enabled)		wl3501_unblock_interrupt(this);	if (rc) {		++this->stats.tx_dropped;		netif_stop_queue(dev);	} else {		++this->stats.tx_packets;		this->stats.tx_bytes += skb->len;		kfree_skb(skb);		if (this->tx_buffer_cnt < 2)			netif_stop_queue(dev);	}	spin_unlock_irqrestore(&this->lock, flags);	return rc;}static int wl3501_open(struct net_device *dev){	int rc = -ENODEV;	struct wl3501_card *this = dev->priv;	unsigned long flags;	struct pcmcia_device *link;	link = this->p_dev;	spin_lock_irqsave(&this->lock, flags);	if (!pcmcia_dev_present(link))		goto out;	netif_device_attach(dev);	link->open++;	/* Initial WL3501 firmware */	dprintk(1, "%s: Initialize WL3501 firmware...", dev->name);	if (wl3501_init_firmware(this))		goto fail;	/* Initial device variables */	this->adhoc_times = 0;	/* Acknowledge Interrupt, for cleaning last state */	wl3501_ack_interrupt(this);	/* Enable interrupt from card after all */	wl3501_unblock_interrupt(this);	wl3501_mgmt_scan(this, 100);	rc = 0;	dprintk(1, "%s: WL3501 opened", dev->name);	printk(KERN_INFO "%s: Card Name: %s\n"			 "%s: Firmware Date: %s\n",			 dev->name, this->card_name,			 dev->name, this->firmware_date);out:	spin_unlock_irqrestore(&this->lock, flags);	return rc;fail:	printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name);	goto out;}static struct net_device_stats *wl3501_get_stats(struct net_device *dev){	struct wl3501_card *this = dev->priv;	return &this->stats;}static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev){	struct wl3501_card *this = dev->priv;	struct iw_statistics *wstats = &this->wstats;	u32 value; /* size checked: it is u32 */	memset(wstats, 0, sizeof(*wstats));	wstats->status = netif_running(dev);	if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT,				  &value, sizeof(value)))		wstats->discard.code += value;	if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT,				  &value, sizeof(value)))		wstats->discard.code += value;	if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT,				  &value, sizeof(value)))		wstats->discard.code += value;	if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT,				  &value, sizeof(value)))		wstats->discard.retries	= value;	if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT,				  &value, sizeof(value)))		wstats->discard.misc += value;	if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT,				  &value, sizeof(value)))		wstats->discard.misc += value;	if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT,				  &value, sizeof(value)))		wstats->discard.misc += value;	if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT,				  &value, sizeof(value)))		wstats->discard.misc += value;	return wstats;}static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){	strlcpy(info->driver, wl3501_dev_info, sizeof(info->driver));}static struct ethtool_ops ops = {	.get_drvinfo = wl3501_get_drvinfo};/** * wl3501_detach - deletes a driver "instance" * @link - FILL_IN * * This deletes a driver "instance". The device is de-registered with Card * Services. If it has been released, all local data structures are freed. * Otherwise, the structures will be freed when the device is released. */static void wl3501_detach(struct pcmcia_device *link){	struct net_device *dev = link->priv;	/* If the device is currently configured and active, we won't actually	 * delete it yet.  Instead, it is marked so that when the release()	 * function is called, that will trigger a proper detach(). */	while (link->open > 0)		wl3501_close(dev);	netif_device_detach(dev);	wl3501_release(link);	if (link->priv)		free_netdev(link->priv);	return;}static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	strlcpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name));	return 0;}static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	int channel = wrqu->freq.m;	int rc = -EINVAL;	if (iw_valid_channel(this->reg_domain, channel)) {		this->chan = channel;		rc = wl3501_reset(dev);	}	return rc;}static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000;	wrqu->freq.e = 1;	return 0;}static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	int rc = -EINVAL;	if (wrqu->mode == IW_MODE_INFRA ||	    wrqu->mode == IW_MODE_ADHOC ||	    wrqu->mode == IW_MODE_AUTO) {		struct wl3501_card *this = dev->priv;		this->net_type = wrqu->mode;		rc = wl3501_reset(dev);	}	return rc;}static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	wrqu->mode = this->net_type;	return 0;}static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	wrqu->sens.value = this->rssi;	wrqu->sens.disabled = !wrqu->sens.value;	wrqu->sens.fixed = 1;	return 0;}static int wl3501_get_range(struct net_device *dev,			    struct iw_request_info *info,			    union iwreq_data *wrqu, char *extra){	struct iw_range *range = (struct iw_range *)extra;	/* Set the length (very important for backward compatibility) */	wrqu->data.length = sizeof(*range);	/* Set all the info we don't care or don't know about to zero */	memset(range, 0, sizeof(*range));	/* Set the Wireless Extension versions */	range->we_version_compiled	= WIRELESS_EXT;	range->we_version_source	= 1;	range->throughput		= 2 * 1000 * 1000;     /* ~2 Mb/s */	/* FIXME: study the code to fill in more fields... */	return 0;}static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info,			  union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };	int rc = -EINVAL;	/* FIXME: we support other ARPHRDs...*/	if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)		goto out;	if (!memcmp(bcast, wrqu->ap_addr.sa_data, ETH_ALEN)) {		/* FIXME: rescan? */	} else		memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);		/* FIXME: rescan? deassoc & scan? */	rc = 0;out:	return rc;}static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info,			  union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	wrqu->ap_addr.sa_family = ARPHRD_ETHER;	memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN);	return 0;}static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	/*	 * FIXME: trigger scanning with a reset, yes, I'm lazy	 */	return wl3501_reset(dev);}static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?