162306a36Sopenharmony_ci/*======================================================================
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci    Aironet driver for 4500 and 4800 series cards
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci    This code is released under both the GPL version 2 and BSD licenses.
662306a36Sopenharmony_ci    Either license may be used.  The respective licenses are found at
762306a36Sopenharmony_ci    the end of this file.
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci    This code was developed by Benjamin Reed <breed@users.sourceforge.net>
1062306a36Sopenharmony_ci    including portions of which come from the Aironet PC4500
1162306a36Sopenharmony_ci    Developer's Reference Manual and used with permission.  Copyright
1262306a36Sopenharmony_ci    (C) 1999 Benjamin Reed.  All Rights Reserved.  Permission to use
1362306a36Sopenharmony_ci    code in the Developer's manual was granted for this driver by
1462306a36Sopenharmony_ci    Aironet.
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci    In addition this module was derived from dummy_cs.
1762306a36Sopenharmony_ci    The initial developer of dummy_cs is David A. Hinds
1862306a36Sopenharmony_ci    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
1962306a36Sopenharmony_ci    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci======================================================================*/
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#ifdef __IN_PCMCIA_PACKAGE__
2462306a36Sopenharmony_ci#include <pcmcia/k_compat.h>
2562306a36Sopenharmony_ci#endif
2662306a36Sopenharmony_ci#include <linux/kernel.h>
2762306a36Sopenharmony_ci#include <linux/module.h>
2862306a36Sopenharmony_ci#include <linux/ptrace.h>
2962306a36Sopenharmony_ci#include <linux/slab.h>
3062306a36Sopenharmony_ci#include <linux/string.h>
3162306a36Sopenharmony_ci#include <linux/timer.h>
3262306a36Sopenharmony_ci#include <linux/netdevice.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <pcmcia/cistpl.h>
3562306a36Sopenharmony_ci#include <pcmcia/cisreg.h>
3662306a36Sopenharmony_ci#include <pcmcia/ds.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include <linux/io.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include "airo.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/*====================================================================*/
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciMODULE_AUTHOR("Benjamin Reed");
4662306a36Sopenharmony_ciMODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet "
4762306a36Sopenharmony_ci		   "cards.  This is the module that links the PCMCIA card "
4862306a36Sopenharmony_ci		   "with the airo module.");
4962306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/*====================================================================*/
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int airo_config(struct pcmcia_device *link);
5462306a36Sopenharmony_cistatic void airo_release(struct pcmcia_device *link);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic void airo_detach(struct pcmcia_device *p_dev);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct local_info {
5962306a36Sopenharmony_ci	struct net_device *eth_dev;
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int airo_probe(struct pcmcia_device *p_dev)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct local_info *local;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	dev_dbg(&p_dev->dev, "airo_attach()\n");
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* Allocate space for private device-specific data */
6962306a36Sopenharmony_ci	local = kzalloc(sizeof(*local), GFP_KERNEL);
7062306a36Sopenharmony_ci	if (!local)
7162306a36Sopenharmony_ci		return -ENOMEM;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	p_dev->priv = local;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return airo_config(p_dev);
7662306a36Sopenharmony_ci} /* airo_attach */
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void airo_detach(struct pcmcia_device *link)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	dev_dbg(&link->dev, "airo_detach\n");
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	airo_release(link);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (((struct local_info *)link->priv)->eth_dev) {
8562306a36Sopenharmony_ci		stop_airo_card(((struct local_info *)link->priv)->eth_dev,
8662306a36Sopenharmony_ci			       0);
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci	((struct local_info *)link->priv)->eth_dev = NULL;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	kfree(link->priv);
9162306a36Sopenharmony_ci} /* airo_detach */
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int airo_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	if (p_dev->config_index == 0)
9662306a36Sopenharmony_ci		return -EINVAL;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return pcmcia_request_io(p_dev);
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int airo_config(struct pcmcia_device *link)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	int ret;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	dev_dbg(&link->dev, "airo_config\n");
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
10962306a36Sopenharmony_ci		CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	ret = pcmcia_loop_config(link, airo_cs_config_check, NULL);
11262306a36Sopenharmony_ci	if (ret)
11362306a36Sopenharmony_ci		goto failed;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (!link->irq)
11662306a36Sopenharmony_ci		goto failed;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	ret = pcmcia_enable_device(link);
11962306a36Sopenharmony_ci	if (ret)
12062306a36Sopenharmony_ci		goto failed;
12162306a36Sopenharmony_ci	((struct local_info *)link->priv)->eth_dev =
12262306a36Sopenharmony_ci		init_airo_card(link->irq,
12362306a36Sopenharmony_ci			       link->resource[0]->start, 1, &link->dev);
12462306a36Sopenharmony_ci	if (!((struct local_info *)link->priv)->eth_dev)
12562306a36Sopenharmony_ci		goto failed;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return 0;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci failed:
13062306a36Sopenharmony_ci	airo_release(link);
13162306a36Sopenharmony_ci	return -ENODEV;
13262306a36Sopenharmony_ci} /* airo_config */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void airo_release(struct pcmcia_device *link)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	dev_dbg(&link->dev, "airo_release\n");
13762306a36Sopenharmony_ci	pcmcia_disable_device(link);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int airo_suspend(struct pcmcia_device *link)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct local_info *local = link->priv;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	netif_device_detach(local->eth_dev);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return 0;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int airo_resume(struct pcmcia_device *link)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct local_info *local = link->priv;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (link->open) {
15462306a36Sopenharmony_ci		reset_airo_card(local->eth_dev);
15562306a36Sopenharmony_ci		netif_device_attach(local->eth_dev);
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return 0;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic const struct pcmcia_device_id airo_ids[] = {
16262306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a),
16362306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005),
16462306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007),
16562306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007),
16662306a36Sopenharmony_ci	PCMCIA_DEVICE_NULL,
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, airo_ids);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic struct pcmcia_driver airo_driver = {
17162306a36Sopenharmony_ci	.owner		= THIS_MODULE,
17262306a36Sopenharmony_ci	.name		= "airo_cs",
17362306a36Sopenharmony_ci	.probe		= airo_probe,
17462306a36Sopenharmony_ci	.remove		= airo_detach,
17562306a36Sopenharmony_ci	.id_table       = airo_ids,
17662306a36Sopenharmony_ci	.suspend	= airo_suspend,
17762306a36Sopenharmony_ci	.resume		= airo_resume,
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_cimodule_pcmcia_driver(airo_driver);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci/*
18262306a36Sopenharmony_ci    This program is free software; you can redistribute it and/or
18362306a36Sopenharmony_ci    modify it under the terms of the GNU General Public License
18462306a36Sopenharmony_ci    as published by the Free Software Foundation; either version 2
18562306a36Sopenharmony_ci    of the License, or (at your option) any later version.
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci    This program is distributed in the hope that it will be useful,
18862306a36Sopenharmony_ci    but WITHOUT ANY WARRANTY; without even the implied warranty of
18962306a36Sopenharmony_ci    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19062306a36Sopenharmony_ci    GNU General Public License for more details.
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci    In addition:
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci    Redistribution and use in source and binary forms, with or without
19562306a36Sopenharmony_ci    modification, are permitted provided that the following conditions
19662306a36Sopenharmony_ci    are met:
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci    1. Redistributions of source code must retain the above copyright
19962306a36Sopenharmony_ci       notice, this list of conditions and the following disclaimer.
20062306a36Sopenharmony_ci    2. Redistributions in binary form must reproduce the above copyright
20162306a36Sopenharmony_ci       notice, this list of conditions and the following disclaimer in the
20262306a36Sopenharmony_ci       documentation and/or other materials provided with the distribution.
20362306a36Sopenharmony_ci    3. The name of the author may not be used to endorse or promote
20462306a36Sopenharmony_ci       products derived from this software without specific prior written
20562306a36Sopenharmony_ci       permission.
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20862306a36Sopenharmony_ci    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20962306a36Sopenharmony_ci    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21062306a36Sopenharmony_ci    ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21162306a36Sopenharmony_ci    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21262306a36Sopenharmony_ci    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21362306a36Sopenharmony_ci    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21462306a36Sopenharmony_ci    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21562306a36Sopenharmony_ci    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
21662306a36Sopenharmony_ci    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21762306a36Sopenharmony_ci    POSSIBILITY OF SUCH DAMAGE.
21862306a36Sopenharmony_ci*/
219