162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#define PRISM2_PCCARD
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/module.h>
562306a36Sopenharmony_ci#include <linux/if.h>
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci#include <linux/wait.h>
862306a36Sopenharmony_ci#include <linux/timer.h>
962306a36Sopenharmony_ci#include <linux/skbuff.h>
1062306a36Sopenharmony_ci#include <linux/netdevice.h>
1162306a36Sopenharmony_ci#include <linux/workqueue.h>
1262306a36Sopenharmony_ci#include <linux/wireless.h>
1362306a36Sopenharmony_ci#include <net/iw_handler.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <pcmcia/cistpl.h>
1662306a36Sopenharmony_ci#include <pcmcia/cisreg.h>
1762306a36Sopenharmony_ci#include <pcmcia/ds.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <asm/io.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "hostap_wlan.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic char *dev_info = "hostap_cs";
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciMODULE_AUTHOR("Jouni Malinen");
2762306a36Sopenharmony_ciMODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
2862306a36Sopenharmony_ci		   "cards (PC Card).");
2962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic int ignore_cis_vcc;
3362306a36Sopenharmony_cimodule_param(ignore_cis_vcc, int, 0444);
3462306a36Sopenharmony_ciMODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry");
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* struct local_info::hw_priv */
3862306a36Sopenharmony_cistruct hostap_cs_priv {
3962306a36Sopenharmony_ci	struct pcmcia_device *link;
4062306a36Sopenharmony_ci	int sandisk_connectplus;
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#ifdef PRISM2_IO_DEBUG
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct hostap_interface *iface;
4962306a36Sopenharmony_ci	local_info_t *local;
5062306a36Sopenharmony_ci	unsigned long flags;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	iface = netdev_priv(dev);
5362306a36Sopenharmony_ci	local = iface->local;
5462306a36Sopenharmony_ci	spin_lock_irqsave(&local->lock, flags);
5562306a36Sopenharmony_ci	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
5662306a36Sopenharmony_ci	outb(v, dev->base_addr + a);
5762306a36Sopenharmony_ci	spin_unlock_irqrestore(&local->lock, flags);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct hostap_interface *iface;
6362306a36Sopenharmony_ci	local_info_t *local;
6462306a36Sopenharmony_ci	unsigned long flags;
6562306a36Sopenharmony_ci	u8 v;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	iface = netdev_priv(dev);
6862306a36Sopenharmony_ci	local = iface->local;
6962306a36Sopenharmony_ci	spin_lock_irqsave(&local->lock, flags);
7062306a36Sopenharmony_ci	v = inb(dev->base_addr + a);
7162306a36Sopenharmony_ci	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
7262306a36Sopenharmony_ci	spin_unlock_irqrestore(&local->lock, flags);
7362306a36Sopenharmony_ci	return v;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct hostap_interface *iface;
7962306a36Sopenharmony_ci	local_info_t *local;
8062306a36Sopenharmony_ci	unsigned long flags;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	iface = netdev_priv(dev);
8362306a36Sopenharmony_ci	local = iface->local;
8462306a36Sopenharmony_ci	spin_lock_irqsave(&local->lock, flags);
8562306a36Sopenharmony_ci	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
8662306a36Sopenharmony_ci	outw(v, dev->base_addr + a);
8762306a36Sopenharmony_ci	spin_unlock_irqrestore(&local->lock, flags);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct hostap_interface *iface;
9362306a36Sopenharmony_ci	local_info_t *local;
9462306a36Sopenharmony_ci	unsigned long flags;
9562306a36Sopenharmony_ci	u16 v;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	iface = netdev_priv(dev);
9862306a36Sopenharmony_ci	local = iface->local;
9962306a36Sopenharmony_ci	spin_lock_irqsave(&local->lock, flags);
10062306a36Sopenharmony_ci	v = inw(dev->base_addr + a);
10162306a36Sopenharmony_ci	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
10262306a36Sopenharmony_ci	spin_unlock_irqrestore(&local->lock, flags);
10362306a36Sopenharmony_ci	return v;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic inline void hfa384x_outsw_debug(struct net_device *dev, int a,
10762306a36Sopenharmony_ci				       u8 *buf, int wc)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct hostap_interface *iface;
11062306a36Sopenharmony_ci	local_info_t *local;
11162306a36Sopenharmony_ci	unsigned long flags;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	iface = netdev_priv(dev);
11462306a36Sopenharmony_ci	local = iface->local;
11562306a36Sopenharmony_ci	spin_lock_irqsave(&local->lock, flags);
11662306a36Sopenharmony_ci	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
11762306a36Sopenharmony_ci	outsw(dev->base_addr + a, buf, wc);
11862306a36Sopenharmony_ci	spin_unlock_irqrestore(&local->lock, flags);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic inline void hfa384x_insw_debug(struct net_device *dev, int a,
12262306a36Sopenharmony_ci				      u8 *buf, int wc)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct hostap_interface *iface;
12562306a36Sopenharmony_ci	local_info_t *local;
12662306a36Sopenharmony_ci	unsigned long flags;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	iface = netdev_priv(dev);
12962306a36Sopenharmony_ci	local = iface->local;
13062306a36Sopenharmony_ci	spin_lock_irqsave(&local->lock, flags);
13162306a36Sopenharmony_ci	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
13262306a36Sopenharmony_ci	insw(dev->base_addr + a, buf, wc);
13362306a36Sopenharmony_ci	spin_unlock_irqrestore(&local->lock, flags);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
13762306a36Sopenharmony_ci#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
13862306a36Sopenharmony_ci#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
13962306a36Sopenharmony_ci#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
14062306a36Sopenharmony_ci#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
14162306a36Sopenharmony_ci#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#else /* PRISM2_IO_DEBUG */
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
14662306a36Sopenharmony_ci#define HFA384X_INB(a) inb(dev->base_addr + (a))
14762306a36Sopenharmony_ci#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
14862306a36Sopenharmony_ci#define HFA384X_INW(a) inw(dev->base_addr + (a))
14962306a36Sopenharmony_ci#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
15062306a36Sopenharmony_ci#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#endif /* PRISM2_IO_DEBUG */
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
15662306a36Sopenharmony_ci			    int len)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	u16 d_off;
15962306a36Sopenharmony_ci	u16 *pos;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
16262306a36Sopenharmony_ci	pos = (u16 *) buf;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (len / 2)
16562306a36Sopenharmony_ci		HFA384X_INSW(d_off, buf, len / 2);
16662306a36Sopenharmony_ci	pos += len / 2;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (len & 1)
16962306a36Sopenharmony_ci		*((char *) pos) = HFA384X_INB(d_off);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return 0;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	u16 d_off;
17862306a36Sopenharmony_ci	u16 *pos;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
18162306a36Sopenharmony_ci	pos = (u16 *) buf;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (len / 2)
18462306a36Sopenharmony_ci		HFA384X_OUTSW(d_off, buf, len / 2);
18562306a36Sopenharmony_ci	pos += len / 2;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (len & 1)
18862306a36Sopenharmony_ci		HFA384X_OUTB(*((char *) pos), d_off);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return 0;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/* FIX: This might change at some point.. */
19562306a36Sopenharmony_ci#include "hostap_hw.c"
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic void prism2_detach(struct pcmcia_device *p_dev);
20062306a36Sopenharmony_cistatic void prism2_release(u_long arg);
20162306a36Sopenharmony_cistatic int prism2_config(struct pcmcia_device *link);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic int prism2_pccard_card_present(local_info_t *local)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct hostap_cs_priv *hw_priv = local->hw_priv;
20762306a36Sopenharmony_ci	if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link))
20862306a36Sopenharmony_ci		return 1;
20962306a36Sopenharmony_ci	return 0;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/*
21462306a36Sopenharmony_ci * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0
21562306a36Sopenharmony_ci * Document No. 20-10-00058, January 2004
21662306a36Sopenharmony_ci * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf
21762306a36Sopenharmony_ci */
21862306a36Sopenharmony_ci#define SANDISK_WLAN_ACTIVATION_OFF 0x40
21962306a36Sopenharmony_ci#define SANDISK_HCR_OFF 0x42
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic void sandisk_set_iobase(local_info_t *local)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int res;
22562306a36Sopenharmony_ci	struct hostap_cs_priv *hw_priv = local->hw_priv;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	res = pcmcia_write_config_byte(hw_priv->link, 0x10,
22862306a36Sopenharmony_ci				hw_priv->link->resource[0]->start & 0x00ff);
22962306a36Sopenharmony_ci	if (res != 0) {
23062306a36Sopenharmony_ci		printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
23162306a36Sopenharmony_ci		       " res=%d\n", res);
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci	udelay(10);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	res = pcmcia_write_config_byte(hw_priv->link, 0x12,
23662306a36Sopenharmony_ci				(hw_priv->link->resource[0]->start >> 8) & 0x00ff);
23762306a36Sopenharmony_ci	if (res != 0) {
23862306a36Sopenharmony_ci		printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
23962306a36Sopenharmony_ci		       " res=%d\n", res);
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic void sandisk_write_hcr(local_info_t *local, int hcr)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct net_device *dev = local->dev;
24762306a36Sopenharmony_ci	int i;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF);
25062306a36Sopenharmony_ci	udelay(50);
25162306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
25262306a36Sopenharmony_ci		HFA384X_OUTB(hcr, SANDISK_HCR_OFF);
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci	udelay(55);
25562306a36Sopenharmony_ci	HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF);
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic int sandisk_enable_wireless(struct net_device *dev)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	int res, ret = 0;
26262306a36Sopenharmony_ci	struct hostap_interface *iface = netdev_priv(dev);
26362306a36Sopenharmony_ci	local_info_t *local = iface->local;
26462306a36Sopenharmony_ci	struct hostap_cs_priv *hw_priv = local->hw_priv;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (resource_size(hw_priv->link->resource[0]) < 0x42) {
26762306a36Sopenharmony_ci		/* Not enough ports to be SanDisk multi-function card */
26862306a36Sopenharmony_ci		ret = -ENODEV;
26962306a36Sopenharmony_ci		goto done;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) {
27362306a36Sopenharmony_ci		/* No SanDisk manfid found */
27462306a36Sopenharmony_ci		ret = -ENODEV;
27562306a36Sopenharmony_ci		goto done;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (hw_priv->link->socket->functions < 2) {
27962306a36Sopenharmony_ci		/* No multi-function links found */
28062306a36Sopenharmony_ci		ret = -ENODEV;
28162306a36Sopenharmony_ci		goto done;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected"
28562306a36Sopenharmony_ci	       " - using vendor-specific initialization\n", dev->name);
28662306a36Sopenharmony_ci	hw_priv->sandisk_connectplus = 1;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
28962306a36Sopenharmony_ci				COR_SOFT_RESET);
29062306a36Sopenharmony_ci	if (res != 0) {
29162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
29262306a36Sopenharmony_ci		       dev->name, res);
29362306a36Sopenharmony_ci		goto done;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci	mdelay(5);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/*
29862306a36Sopenharmony_ci	 * Do not enable interrupts here to avoid some bogus events. Interrupts
29962306a36Sopenharmony_ci	 * will be enabled during the first cor_sreset call.
30062306a36Sopenharmony_ci	 */
30162306a36Sopenharmony_ci	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
30262306a36Sopenharmony_ci				(COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE |
30362306a36Sopenharmony_ci					COR_FUNC_ENA));
30462306a36Sopenharmony_ci	if (res != 0) {
30562306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
30662306a36Sopenharmony_ci		       dev->name, res);
30762306a36Sopenharmony_ci		goto done;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci	mdelay(5);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	sandisk_set_iobase(local);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF);
31462306a36Sopenharmony_ci	udelay(10);
31562306a36Sopenharmony_ci	HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF);
31662306a36Sopenharmony_ci	udelay(10);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cidone:
31962306a36Sopenharmony_ci	return ret;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic void prism2_pccard_cor_sreset(local_info_t *local)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	int res;
32662306a36Sopenharmony_ci	u8 val;
32762306a36Sopenharmony_ci	struct hostap_cs_priv *hw_priv = local->hw_priv;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (!prism2_pccard_card_present(local))
33062306a36Sopenharmony_ci	       return;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val);
33362306a36Sopenharmony_ci	if (res != 0) {
33462306a36Sopenharmony_ci		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
33562306a36Sopenharmony_ci		       res);
33662306a36Sopenharmony_ci		return;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n",
33962306a36Sopenharmony_ci		val);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	val |= COR_SOFT_RESET;
34262306a36Sopenharmony_ci	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
34362306a36Sopenharmony_ci	if (res != 0) {
34462306a36Sopenharmony_ci		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
34562306a36Sopenharmony_ci		       res);
34662306a36Sopenharmony_ci		return;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	val &= ~COR_SOFT_RESET;
35262306a36Sopenharmony_ci	if (hw_priv->sandisk_connectplus)
35362306a36Sopenharmony_ci		val |= COR_IREQ_ENA;
35462306a36Sopenharmony_ci	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
35562306a36Sopenharmony_ci	if (res != 0) {
35662306a36Sopenharmony_ci		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
35762306a36Sopenharmony_ci		       res);
35862306a36Sopenharmony_ci		return;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (hw_priv->sandisk_connectplus)
36462306a36Sopenharmony_ci		sandisk_set_iobase(local);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	int res;
37162306a36Sopenharmony_ci	u8 old_cor;
37262306a36Sopenharmony_ci	struct hostap_cs_priv *hw_priv = local->hw_priv;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (!prism2_pccard_card_present(local))
37562306a36Sopenharmony_ci	       return;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (hw_priv->sandisk_connectplus) {
37862306a36Sopenharmony_ci		sandisk_write_hcr(local, hcr);
37962306a36Sopenharmony_ci		return;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor);
38362306a36Sopenharmony_ci	if (res != 0) {
38462306a36Sopenharmony_ci		printk(KERN_DEBUG "%s failed 1 (%d)\n", __func__, res);
38562306a36Sopenharmony_ci		return;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	printk(KERN_DEBUG "%s: original COR %02x\n", __func__, old_cor);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
39062306a36Sopenharmony_ci				old_cor | COR_SOFT_RESET);
39162306a36Sopenharmony_ci	if (res != 0) {
39262306a36Sopenharmony_ci		printk(KERN_DEBUG "%s failed 2 (%d)\n", __func__, res);
39362306a36Sopenharmony_ci		return;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	mdelay(10);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* Setup Genesis mode */
39962306a36Sopenharmony_ci	res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr);
40062306a36Sopenharmony_ci	if (res != 0) {
40162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s failed 3 (%d)\n", __func__, res);
40262306a36Sopenharmony_ci		return;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci	mdelay(10);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
40762306a36Sopenharmony_ci				old_cor & ~COR_SOFT_RESET);
40862306a36Sopenharmony_ci	if (res != 0) {
40962306a36Sopenharmony_ci		printk(KERN_DEBUG "%s failed 4 (%d)\n", __func__, res);
41062306a36Sopenharmony_ci		return;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	mdelay(10);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic struct prism2_helper_functions prism2_pccard_funcs =
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	.card_present	= prism2_pccard_card_present,
42062306a36Sopenharmony_ci	.cor_sreset	= prism2_pccard_cor_sreset,
42162306a36Sopenharmony_ci	.genesis_reset	= prism2_pccard_genesis_reset,
42262306a36Sopenharmony_ci	.hw_type	= HOSTAP_HW_PCCARD,
42362306a36Sopenharmony_ci};
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci/* allocate local data and register with CardServices
42762306a36Sopenharmony_ci * initialize dev_link structure, but do not configure the card yet */
42862306a36Sopenharmony_cistatic int hostap_cs_probe(struct pcmcia_device *p_dev)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	int ret;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	ret = prism2_config(p_dev);
43562306a36Sopenharmony_ci	if (ret) {
43662306a36Sopenharmony_ci		PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n");
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return ret;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic void prism2_detach(struct pcmcia_device *link)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	PDEBUG(DEBUG_FLOW, "prism2_detach\n");
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	prism2_release((u_long)link);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/* release net devices */
45062306a36Sopenharmony_ci	if (link->priv) {
45162306a36Sopenharmony_ci		struct hostap_cs_priv *hw_priv;
45262306a36Sopenharmony_ci		struct net_device *dev;
45362306a36Sopenharmony_ci		struct hostap_interface *iface;
45462306a36Sopenharmony_ci		dev = link->priv;
45562306a36Sopenharmony_ci		iface = netdev_priv(dev);
45662306a36Sopenharmony_ci		hw_priv = iface->local->hw_priv;
45762306a36Sopenharmony_ci		prism2_free_local_data(dev);
45862306a36Sopenharmony_ci		kfree(hw_priv);
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	if (p_dev->config_index == 0)
46662306a36Sopenharmony_ci		return -EINVAL;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	return pcmcia_request_io(p_dev);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic int prism2_config(struct pcmcia_device *link)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	struct net_device *dev;
47462306a36Sopenharmony_ci	struct hostap_interface *iface;
47562306a36Sopenharmony_ci	local_info_t *local;
47662306a36Sopenharmony_ci	int ret;
47762306a36Sopenharmony_ci	struct hostap_cs_priv *hw_priv;
47862306a36Sopenharmony_ci	unsigned long flags;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	PDEBUG(DEBUG_FLOW, "prism2_config()\n");
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
48362306a36Sopenharmony_ci	if (hw_priv == NULL) {
48462306a36Sopenharmony_ci		ret = -ENOMEM;
48562306a36Sopenharmony_ci		goto failed;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/* Look for an appropriate configuration table entry in the CIS */
48962306a36Sopenharmony_ci	link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO |
49062306a36Sopenharmony_ci		CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
49162306a36Sopenharmony_ci	if (ignore_cis_vcc)
49262306a36Sopenharmony_ci		link->config_flags &= ~CONF_AUTO_CHECK_VCC;
49362306a36Sopenharmony_ci	ret = pcmcia_loop_config(link, prism2_config_check, NULL);
49462306a36Sopenharmony_ci	if (ret) {
49562306a36Sopenharmony_ci		if (!ignore_cis_vcc)
49662306a36Sopenharmony_ci			printk(KERN_ERR "GetNextTuple(): No matching "
49762306a36Sopenharmony_ci			       "CIS configuration.  Maybe you need the "
49862306a36Sopenharmony_ci			       "ignore_cis_vcc=1 parameter.\n");
49962306a36Sopenharmony_ci		goto failed;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	/* Need to allocate net_device before requesting IRQ handler */
50362306a36Sopenharmony_ci	dev = prism2_init_local_data(&prism2_pccard_funcs, 0,
50462306a36Sopenharmony_ci				     &link->dev);
50562306a36Sopenharmony_ci	if (!dev) {
50662306a36Sopenharmony_ci		ret = -ENOMEM;
50762306a36Sopenharmony_ci		goto failed;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci	link->priv = dev;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	iface = netdev_priv(dev);
51262306a36Sopenharmony_ci	local = iface->local;
51362306a36Sopenharmony_ci	local->hw_priv = hw_priv;
51462306a36Sopenharmony_ci	hw_priv->link = link;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/*
51762306a36Sopenharmony_ci	 * We enable IRQ here, but IRQ handler will not proceed
51862306a36Sopenharmony_ci	 * until dev->base_addr is set below. This protect us from
51962306a36Sopenharmony_ci	 * receive interrupts when driver is not initialized.
52062306a36Sopenharmony_ci	 */
52162306a36Sopenharmony_ci	ret = pcmcia_request_irq(link, prism2_interrupt);
52262306a36Sopenharmony_ci	if (ret)
52362306a36Sopenharmony_ci		goto failed;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	ret = pcmcia_enable_device(link);
52662306a36Sopenharmony_ci	if (ret)
52762306a36Sopenharmony_ci		goto failed;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	spin_lock_irqsave(&local->irq_init_lock, flags);
53062306a36Sopenharmony_ci	dev->irq = link->irq;
53162306a36Sopenharmony_ci	dev->base_addr = link->resource[0]->start;
53262306a36Sopenharmony_ci	spin_unlock_irqrestore(&local->irq_init_lock, flags);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	local->shutdown = 0;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	sandisk_enable_wireless(dev);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	ret = prism2_hw_config(dev, 1);
53962306a36Sopenharmony_ci	if (!ret)
54062306a36Sopenharmony_ci		ret = hostap_hw_ready(dev);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	return ret;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci failed:
54562306a36Sopenharmony_ci	kfree(hw_priv);
54662306a36Sopenharmony_ci	prism2_release((u_long)link);
54762306a36Sopenharmony_ci	return ret;
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic void prism2_release(u_long arg)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct pcmcia_device *link = (struct pcmcia_device *)arg;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	PDEBUG(DEBUG_FLOW, "prism2_release\n");
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (link->priv) {
55862306a36Sopenharmony_ci		struct net_device *dev = link->priv;
55962306a36Sopenharmony_ci		struct hostap_interface *iface;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		iface = netdev_priv(dev);
56262306a36Sopenharmony_ci		prism2_hw_shutdown(dev, 0);
56362306a36Sopenharmony_ci		iface->local->shutdown = 1;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	pcmcia_disable_device(link);
56762306a36Sopenharmony_ci	PDEBUG(DEBUG_FLOW, "release - done\n");
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic int hostap_cs_suspend(struct pcmcia_device *link)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	struct net_device *dev = (struct net_device *) link->priv;
57362306a36Sopenharmony_ci	int dev_open = 0;
57462306a36Sopenharmony_ci	struct hostap_interface *iface = NULL;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (!dev)
57762306a36Sopenharmony_ci		return -ENODEV;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	iface = netdev_priv(dev);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
58262306a36Sopenharmony_ci	if (iface && iface->local)
58362306a36Sopenharmony_ci		dev_open = iface->local->num_dev_open > 0;
58462306a36Sopenharmony_ci	if (dev_open) {
58562306a36Sopenharmony_ci		netif_stop_queue(dev);
58662306a36Sopenharmony_ci		netif_device_detach(dev);
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci	prism2_suspend(dev);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	return 0;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic int hostap_cs_resume(struct pcmcia_device *link)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	struct net_device *dev = (struct net_device *) link->priv;
59662306a36Sopenharmony_ci	int dev_open = 0;
59762306a36Sopenharmony_ci	struct hostap_interface *iface = NULL;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (!dev)
60062306a36Sopenharmony_ci		return -ENODEV;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	iface = netdev_priv(dev);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	if (iface && iface->local)
60762306a36Sopenharmony_ci		dev_open = iface->local->num_dev_open > 0;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	prism2_hw_shutdown(dev, 1);
61062306a36Sopenharmony_ci	prism2_hw_config(dev, dev_open ? 0 : 1);
61162306a36Sopenharmony_ci	if (dev_open) {
61262306a36Sopenharmony_ci		netif_device_attach(dev);
61362306a36Sopenharmony_ci		netif_start_queue(dev);
61462306a36Sopenharmony_ci	}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	return 0;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic const struct pcmcia_device_id hostap_cs_ids[] = {
62062306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
62162306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
62262306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
62362306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
62462306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
62562306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301),
62662306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
62762306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
62862306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
62962306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
63062306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
63162306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
63262306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001),
63362306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
63462306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
63562306a36Sopenharmony_ci/*	PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000),    conflict with pcnet_cs */
63662306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
63762306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
63862306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
63962306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
64062306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
64162306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF",
64262306a36Sopenharmony_ci					 0x2d858104),
64362306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
64462306a36Sopenharmony_ci					 0x74c5e40d),
64562306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
64662306a36Sopenharmony_ci					 0x4b801a17),
64762306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02",
64862306a36Sopenharmony_ci					 0x4b74baa0),
64962306a36Sopenharmony_ci	PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
65062306a36Sopenharmony_ci				    0x7a954bd9, 0x74be00c6),
65162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123(
65262306a36Sopenharmony_ci		"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
65362306a36Sopenharmony_ci		0xe6ec52ce, 0x08649af2, 0x4b74baa0),
65462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123(
65562306a36Sopenharmony_ci		"Canon", "Wireless LAN CF Card K30225", "Version 01.00",
65662306a36Sopenharmony_ci		0x96ef6fe2, 0x263fcbab, 0xa57adb8c),
65762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123(
65862306a36Sopenharmony_ci		"D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02",
65962306a36Sopenharmony_ci		0x71b18589, 0xb6f1b0ab, 0x4b74baa0),
66062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123(
66162306a36Sopenharmony_ci		"Instant Wireless ", " Network PC CARD", "Version 01.02",
66262306a36Sopenharmony_ci		0x11d901af, 0x6e9bd926, 0x4b74baa0),
66362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123(
66462306a36Sopenharmony_ci		"SMC", "SMC2632W", "Version 01.02",
66562306a36Sopenharmony_ci		0xc4f8b18b, 0x474a1f2a, 0x4b74baa0),
66662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G",
66762306a36Sopenharmony_ci				0x2decece3, 0x82067c18),
66862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card",
66962306a36Sopenharmony_ci				0x54f7c49c, 0x15a75e5b),
67062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE",
67162306a36Sopenharmony_ci				0x74c5e40d, 0xdb472a18),
67262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card",
67362306a36Sopenharmony_ci				0x0733cc81, 0x0c52f395),
67462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12(
67562306a36Sopenharmony_ci		"ZoomAir 11Mbps High", "Rate wireless Networking",
67662306a36Sopenharmony_ci		0x273fe3db, 0x32a1eaee),
67762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card",
67862306a36Sopenharmony_ci		0xa37434e9, 0x9762e8f1),
67962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123(
68062306a36Sopenharmony_ci		"Pretec", "CompactWLAN Card 802.11b", "2.5",
68162306a36Sopenharmony_ci		0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
68262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123(
68362306a36Sopenharmony_ci		"U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02",
68462306a36Sopenharmony_ci		0xc7b8df9d, 0x1700d087, 0x4b74baa0),
68562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123(
68662306a36Sopenharmony_ci		"Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio",
68762306a36Sopenharmony_ci		"Ver. 1.00",
68862306a36Sopenharmony_ci		0x5cd01705, 0x4271660f, 0x9d08ee12),
68962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123(
69062306a36Sopenharmony_ci		"Wireless LAN" , "11Mbps PC Card", "Version 01.02",
69162306a36Sopenharmony_ci		0x4b8870ff, 0x70e946d1, 0x4b74baa0),
69262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
69362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
69462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
69562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
69662306a36Sopenharmony_ci	PCMCIA_DEVICE_NULL
69762306a36Sopenharmony_ci};
69862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic struct pcmcia_driver hostap_driver = {
70262306a36Sopenharmony_ci	.name		= "hostap_cs",
70362306a36Sopenharmony_ci	.probe		= hostap_cs_probe,
70462306a36Sopenharmony_ci	.remove		= prism2_detach,
70562306a36Sopenharmony_ci	.owner		= THIS_MODULE,
70662306a36Sopenharmony_ci	.id_table	= hostap_cs_ids,
70762306a36Sopenharmony_ci	.suspend	= hostap_cs_suspend,
70862306a36Sopenharmony_ci	.resume		= hostap_cs_resume,
70962306a36Sopenharmony_ci};
71062306a36Sopenharmony_cimodule_pcmcia_driver(hostap_driver);
711