wl3501_cs.c

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

C
2,165
字号
			   union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	int i;	char *current_ev = extra;	struct iw_event iwe;	for (i = 0; i < this->bss_cnt; ++i) {		iwe.cmd			= SIOCGIWAP;		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;		memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].bssid, ETH_ALEN);		current_ev = iwe_stream_add_event(current_ev,						  extra + IW_SCAN_MAX_DATA,						  &iwe, IW_EV_ADDR_LEN);		iwe.cmd		  = SIOCGIWESSID;		iwe.u.data.flags  = 1;		iwe.u.data.length = this->bss_set[i].ssid.el.len;		current_ev = iwe_stream_add_point(current_ev,						  extra + IW_SCAN_MAX_DATA,						  &iwe,						  this->bss_set[i].ssid.essid);		iwe.cmd	   = SIOCGIWMODE;		iwe.u.mode = this->bss_set[i].bss_type;		current_ev = iwe_stream_add_event(current_ev,						  extra + IW_SCAN_MAX_DATA,						  &iwe, IW_EV_UINT_LEN);		iwe.cmd = SIOCGIWFREQ;		iwe.u.freq.m = this->bss_set[i].ds_pset.chan;		iwe.u.freq.e = 0;		current_ev = iwe_stream_add_event(current_ev,						  extra + IW_SCAN_MAX_DATA,						  &iwe, IW_EV_FREQ_LEN);		iwe.cmd = SIOCGIWENCODE;		if (this->bss_set[i].cap_info & WL3501_MGMT_CAPABILITY_PRIVACY)			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;		else			iwe.u.data.flags = IW_ENCODE_DISABLED;		iwe.u.data.length = 0;		current_ev = iwe_stream_add_point(current_ev,						  extra + IW_SCAN_MAX_DATA,						  &iwe, NULL);	}	/* Length of data */	wrqu->data.length = (current_ev - extra);	wrqu->data.flags = 0; /* FIXME: set properly these flags */	return 0;}static int wl3501_set_essid(struct net_device *dev,			    struct iw_request_info *info,			    union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	if (wrqu->data.flags) {		iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,					 &this->essid.el,					 extra, wrqu->data.length);	} else { /* We accept any ESSID */		iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,					 &this->essid.el, "ANY", 3);	}	return wl3501_reset(dev);}static int wl3501_get_essid(struct net_device *dev,			    struct iw_request_info *info,			    union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	unsigned long flags;	spin_lock_irqsave(&this->lock, flags);	wrqu->essid.flags  = 1;	wrqu->essid.length = this->essid.el.len;	memcpy(extra, this->essid.essid, this->essid.el.len);	spin_unlock_irqrestore(&this->lock, flags);	return 0;}static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	if (wrqu->data.length > sizeof(this->nick))		return -E2BIG;	strlcpy(this->nick, extra, wrqu->data.length);	return 0;}static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	struct wl3501_card *this = dev->priv;	strlcpy(extra, this->nick, 32);	wrqu->data.length = strlen(extra);	return 0;}static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	/*	 * FIXME: have to see from where to get this info, perhaps this card	 * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most	 * common with the Planet Access Points. -acme	 */	wrqu->bitrate.value = 2000000;	wrqu->bitrate.fixed = 1;	return 0;}static int wl3501_get_rts_threshold(struct net_device *dev,				    struct iw_request_info *info,				    union iwreq_data *wrqu, char *extra){	u16 threshold; /* size checked: it is u16 */	struct wl3501_card *this = dev->priv;	int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD,				      &threshold, sizeof(threshold));	if (!rc) {		wrqu->rts.value = threshold;		wrqu->rts.disabled = threshold >= 2347;		wrqu->rts.fixed = 1;	}	return rc;}static int wl3501_get_frag_threshold(struct net_device *dev,				     struct iw_request_info *info,				     union iwreq_data *wrqu, char *extra){	u16 threshold; /* size checked: it is u16 */	struct wl3501_card *this = dev->priv;	int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD,				      &threshold, sizeof(threshold));	if (!rc) {		wrqu->frag.value = threshold;		wrqu->frag.disabled = threshold >= 2346;		wrqu->frag.fixed = 1;	}	return rc;}static int wl3501_get_txpow(struct net_device *dev,			    struct iw_request_info *info,			    union iwreq_data *wrqu, char *extra){	u16 txpow;	struct wl3501_card *this = dev->priv;	int rc = wl3501_get_mib_value(this,				      WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL,				      &txpow, sizeof(txpow));	if (!rc) {		wrqu->txpower.value = txpow;		wrqu->txpower.disabled = 0;		/*		 * From the MIB values I think this can be configurable,		 * as it lists several tx power levels -acme		 */		wrqu->txpower.fixed = 0;		wrqu->txpower.flags = IW_TXPOW_MWATT;	}	return rc;}static int wl3501_get_retry(struct net_device *dev,			    struct iw_request_info *info,			    union iwreq_data *wrqu, char *extra){	u8 retry; /* size checked: it is u8 */	struct wl3501_card *this = dev->priv;	int rc = wl3501_get_mib_value(this,				      WL3501_MIB_ATTR_LONG_RETRY_LIMIT,				      &retry, sizeof(retry));	if (rc)		goto out;	if (wrqu->retry.flags & IW_RETRY_MAX) {		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;		goto set_value;	}	rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT,				  &retry, sizeof(retry));	if (rc)		goto out;	wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;set_value:	wrqu->retry.value = retry;	wrqu->retry.disabled = 0;out:	return rc;}static int wl3501_get_encode(struct net_device *dev,			     struct iw_request_info *info,			     union iwreq_data *wrqu, char *extra){	u8 implemented, restricted, keys[100], len_keys, tocopy;	struct wl3501_card *this = dev->priv;	int rc = wl3501_get_mib_value(this,				      WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED,				      &implemented, sizeof(implemented));	if (rc)		goto out;	if (!implemented) {		wrqu->encoding.flags = IW_ENCODE_DISABLED;		goto out;	}	rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED,				  &restricted, sizeof(restricted));	if (rc)		goto out;	wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED :					    IW_ENCODE_OPEN;	rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN,				  &len_keys, sizeof(len_keys));	if (rc)		goto out;	rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS,				  keys, len_keys);	if (rc)		goto out;	tocopy = min_t(u8, len_keys, wrqu->encoding.length);	tocopy = min_t(u8, tocopy, 100);	wrqu->encoding.length = tocopy;	memset(extra, 0, tocopy);	memcpy(extra, keys, tocopy);out:	return rc;}static int wl3501_get_power(struct net_device *dev,			    struct iw_request_info *info,			    union iwreq_data *wrqu, char *extra){	u8 pwr_state;	struct wl3501_card *this = dev->priv;	int rc = wl3501_get_mib_value(this,				      WL3501_MIB_ATTR_CURRENT_PWR_STATE,				      &pwr_state, sizeof(pwr_state));	if (rc)		goto out;	wrqu->power.disabled = !pwr_state;	wrqu->power.flags = IW_POWER_ON;out:	return rc;}static const iw_handler	wl3501_handler[] = {	[SIOCGIWNAME	- SIOCIWFIRST] = wl3501_get_name,	[SIOCSIWFREQ	- SIOCIWFIRST] = wl3501_set_freq,	[SIOCGIWFREQ	- SIOCIWFIRST] = wl3501_get_freq,	[SIOCSIWMODE	- SIOCIWFIRST] = wl3501_set_mode,	[SIOCGIWMODE	- SIOCIWFIRST] = wl3501_get_mode,	[SIOCGIWSENS	- SIOCIWFIRST] = wl3501_get_sens,	[SIOCGIWRANGE	- SIOCIWFIRST] = wl3501_get_range,	[SIOCSIWSPY	- SIOCIWFIRST] = iw_handler_set_spy,	[SIOCGIWSPY	- SIOCIWFIRST] = iw_handler_get_spy,	[SIOCSIWTHRSPY	- SIOCIWFIRST] = iw_handler_set_thrspy,	[SIOCGIWTHRSPY	- SIOCIWFIRST] = iw_handler_get_thrspy,	[SIOCSIWAP	- SIOCIWFIRST] = wl3501_set_wap,	[SIOCGIWAP	- SIOCIWFIRST] = wl3501_get_wap,	[SIOCSIWSCAN	- SIOCIWFIRST] = wl3501_set_scan,	[SIOCGIWSCAN	- SIOCIWFIRST] = wl3501_get_scan,	[SIOCSIWESSID	- SIOCIWFIRST] = wl3501_set_essid,	[SIOCGIWESSID	- SIOCIWFIRST] = wl3501_get_essid,	[SIOCSIWNICKN	- SIOCIWFIRST] = wl3501_set_nick,	[SIOCGIWNICKN	- SIOCIWFIRST] = wl3501_get_nick,	[SIOCGIWRATE	- SIOCIWFIRST] = wl3501_get_rate,	[SIOCGIWRTS	- SIOCIWFIRST] = wl3501_get_rts_threshold,	[SIOCGIWFRAG	- SIOCIWFIRST] = wl3501_get_frag_threshold,	[SIOCGIWTXPOW	- SIOCIWFIRST] = wl3501_get_txpow,	[SIOCGIWRETRY	- SIOCIWFIRST] = wl3501_get_retry,	[SIOCGIWENCODE	- SIOCIWFIRST] = wl3501_get_encode,	[SIOCGIWPOWER	- SIOCIWFIRST] = wl3501_get_power,};static const struct iw_handler_def wl3501_handler_def = {	.num_standard	= sizeof(wl3501_handler) / sizeof(iw_handler),	.standard	= (iw_handler *)wl3501_handler,	.get_wireless_stats = wl3501_get_wireless_stats,};/** * wl3501_attach - creates an "instance" of the driver * * Creates an "instance" of the driver, allocating local data structures for * one device.  The device is registered with Card Services. * * The dev_link structure is initialized, but we don't actually configure the * card at this point -- we wait until we receive a card insertion event. */static int wl3501_probe(struct pcmcia_device *p_dev){	struct net_device *dev;	struct wl3501_card *this;	/* The io structure describes IO port mapping */	p_dev->io.NumPorts1	= 16;	p_dev->io.Attributes1	= IO_DATA_PATH_WIDTH_8;	p_dev->io.IOAddrLines	= 5;	/* Interrupt setup */	p_dev->irq.Attributes	= IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;	p_dev->irq.IRQInfo1	= IRQ_LEVEL_ID;	p_dev->irq.Handler = wl3501_interrupt;	/* General socket configuration */	p_dev->conf.Attributes	= CONF_ENABLE_IRQ;	p_dev->conf.IntType	= INT_MEMORY_AND_IO;	p_dev->conf.ConfigIndex	= 1;	p_dev->conf.Present	= PRESENT_OPTION;	dev = alloc_etherdev(sizeof(struct wl3501_card));	if (!dev)		goto out_link;	dev->open		= wl3501_open;	dev->stop		= wl3501_close;	dev->hard_start_xmit	= wl3501_hard_start_xmit;	dev->tx_timeout		= wl3501_tx_timeout;	dev->watchdog_timeo	= 5 * HZ;	dev->get_stats		= wl3501_get_stats;	this = dev->priv;	this->wireless_data.spy_data = &this->spy_data;	this->p_dev = p_dev;	dev->wireless_data	= &this->wireless_data;	dev->wireless_handlers	= (struct iw_handler_def *)&wl3501_handler_def;	SET_ETHTOOL_OPS(dev, &ops);	netif_stop_queue(dev);	p_dev->priv = p_dev->irq.Instance = dev;	return wl3501_config(p_dev);out_link:	return -ENOMEM;}#define CS_CHECK(fn, ret) \do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)/** * wl3501_config - configure the PCMCIA socket and make eth device available * @link - FILL_IN * * wl3501_config() is scheduled to run after a CARD_INSERTION event is * received, to configure the PCMCIA socket, and to make the ethernet device * available to the system. */static int wl3501_config(struct pcmcia_device *link){	tuple_t tuple;	cisparse_t parse;	struct net_device *dev = link->priv;	int i = 0, j, last_fn, last_ret;	unsigned char bf[64];	struct wl3501_card *this;	/* This reads the card's CONFIG tuple to find its config registers. */	tuple.Attributes	= 0;	tuple.DesiredTuple	= CISTPL_CONFIG;	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));	tuple.TupleData		= bf;	tuple.TupleDataMax	= sizeof(bf);	tuple.TupleOffset	= 0;	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));	link->conf.ConfigBase	= parse.config.base;	link->conf.Present	= parse.config.rmask[0];	/* Try allocating IO ports.  This tries a few fixed addresses.  If you	 * want, you can also read the card's config table to pick addresses --	 * see the serial driver for an example. */	for (j = 0x280; j < 0x400; j += 0x20) {		/* The '^0x300' is so that we probe 0x300-0x3ff first, then		 * 0x200-0x2ff, and so on, because this seems safer */		link->io.BasePort1 = j;		link->io.BasePort2 = link->io.BasePort1 + 0x10;		i = pcmcia_request_io(link, &link->io);		if (i == CS_SUCCESS)			break;	}	if (i != CS_SUCCESS) {		cs_error(link, RequestIO, i);		goto failed;	}	/* Now allocate an interrupt line. Note that this does not actually	 * assign a handler to the interrupt. */	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));	/* This actually configures the PCMCIA socket -- setting up the I/O	 * windows and the interrupt mapping.  */	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));	dev->irq = link->irq.AssignedIRQ;	dev->base_addr = link->io.BasePort1;	SET_NETDEV_DEV(dev, &handle_to_dev(link));	if (register_netdev(dev)) {		printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n");		goto failed;	}	SET_MODULE_OWNER(dev);	this = dev->priv;	/*	 * At this point, the dev_node_t structure(s) should be initialized and	 * arranged in a linked list at link->dev_node.	 */	link->dev_node = &this->node;	this->base_addr = dev->base_addr;	if (!wl3501_get_flash_mac_addr(this)) {		printk(KERN_WARNING "%s: Cant read MAC addr in flash ROM?\n",		       dev->name);		goto failed;	}	strcpy(this->node.dev_name, dev->name);	/* print probe information */	printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, MAC addr in flash ROM:",	       dev->name, this->base_addr, (int)dev->irq);	for (i = 0; i < 6; i++) {		dev->dev_addr[i] = ((char *)&this->mac_addr)[i];		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);	}	printk("\n");	/*	 * Initialize card parameters - added by jss	 */	this->net_type		= IW_MODE_INFRA;	this->bss_cnt		= 0;	this->join_sta_bss	= 0;	this->adhoc_times	= 0;	iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el,				 "ANY", 3);	this->card_name[0]	= '\0';	this->firmware_date[0]	= '\0';	this->rssi		= 255;	this->chan		= iw_default_channel(this->reg_domain);	strlcpy(this->nick, "Planet WL3501", sizeof(this->nick));	spin_lock_init(&this->lock);	init_waitqueue_head(&this->wait);	netif_start_queue(dev);	return 0;cs_failed:	cs_error(link, last_fn, last_ret);failed:	wl3501_release(link);	return -ENODEV;}/** * wl3501_release - unregister the net, release PCMCIA configuration * @arg - link * * After a card is removed, wl3501_release() will unregister the net device, * and release the PCMCIA configuration.  If the device is still open, this * will be postponed until it is closed. */static void wl3501_release(struct pcmcia_device *link){	struct net_device *dev = link->priv;	/* Unlink the device chain */	if (link->dev_node)		unregister_netdev(dev);	pcmcia_disable_device(link);}static int wl3501_suspend(struct pcmcia_device *link){	struct net_device *dev = link->priv;	wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND);	if (link->open)		netif_device_detach(dev);	return 0;}static int wl3501_resume(struct pcmcia_device *link){	struct net_device *dev = link->priv;	wl3501_pwr_mgmt(dev->priv, WL3501_RESUME);	if (link->open) {		wl3501_reset(dev);		netif_device_attach(dev);	}	return 0;}static struct pcmcia_device_id wl3501_ids[] = {	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),	PCMCIA_DEVICE_NULL};MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);static struct pcmcia_driver wl3501_driver = {	.owner		= THIS_MODULE,	.drv		= {		.name	= "wl3501_cs",	},	.probe		= wl3501_probe,	.remove		= wl3501_detach,	.id_table	= wl3501_ids,	.suspend	= wl3501_suspend,	.resume		= wl3501_resume,};static int __init wl3501_init_module(void){	return pcmcia_register_driver(&wl3501_driver);}static void __exit wl3501_exit_module(void){	pcmcia_unregister_driver(&wl3501_driver);}module_init(wl3501_init_module);module_exit(wl3501_exit_module);MODULE_AUTHOR("Fox Chen <mhchen@golf.ccl.itri.org.tw>, "	      "Arnaldo Carvalho de Melo <acme@conectiva.com.br>,"	      "Gustavo Niemeyer <niemeyer@conectiva.com>");MODULE_DESCRIPTION("Planet wl3501 wireless driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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