• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/net/wireless/hostap/
1#define PRISM2_PCCARD
2
3#include <linux/module.h>
4#include <linux/init.h>
5#include <linux/if.h>
6#include <linux/slab.h>
7#include <linux/wait.h>
8#include <linux/timer.h>
9#include <linux/skbuff.h>
10#include <linux/netdevice.h>
11#include <linux/workqueue.h>
12#include <linux/wireless.h>
13#include <net/iw_handler.h>
14
15#include <pcmcia/cs.h>
16#include <pcmcia/cistpl.h>
17#include <pcmcia/cisreg.h>
18#include <pcmcia/ds.h>
19
20#include <asm/io.h>
21
22#include "hostap_wlan.h"
23
24
25static char *dev_info = "hostap_cs";
26
27MODULE_AUTHOR("Jouni Malinen");
28MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
29		   "cards (PC Card).");
30MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)");
31MODULE_LICENSE("GPL");
32
33
34static int ignore_cis_vcc;
35module_param(ignore_cis_vcc, int, 0444);
36MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry");
37
38
39/* struct local_info::hw_priv */
40struct hostap_cs_priv {
41	struct pcmcia_device *link;
42	int sandisk_connectplus;
43};
44
45
46#ifdef PRISM2_IO_DEBUG
47
48static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
49{
50	struct hostap_interface *iface;
51	local_info_t *local;
52	unsigned long flags;
53
54	iface = netdev_priv(dev);
55	local = iface->local;
56	spin_lock_irqsave(&local->lock, flags);
57	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
58	outb(v, dev->base_addr + a);
59	spin_unlock_irqrestore(&local->lock, flags);
60}
61
62static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
63{
64	struct hostap_interface *iface;
65	local_info_t *local;
66	unsigned long flags;
67	u8 v;
68
69	iface = netdev_priv(dev);
70	local = iface->local;
71	spin_lock_irqsave(&local->lock, flags);
72	v = inb(dev->base_addr + a);
73	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
74	spin_unlock_irqrestore(&local->lock, flags);
75	return v;
76}
77
78static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
79{
80	struct hostap_interface *iface;
81	local_info_t *local;
82	unsigned long flags;
83
84	iface = netdev_priv(dev);
85	local = iface->local;
86	spin_lock_irqsave(&local->lock, flags);
87	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
88	outw(v, dev->base_addr + a);
89	spin_unlock_irqrestore(&local->lock, flags);
90}
91
92static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
93{
94	struct hostap_interface *iface;
95	local_info_t *local;
96	unsigned long flags;
97	u16 v;
98
99	iface = netdev_priv(dev);
100	local = iface->local;
101	spin_lock_irqsave(&local->lock, flags);
102	v = inw(dev->base_addr + a);
103	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
104	spin_unlock_irqrestore(&local->lock, flags);
105	return v;
106}
107
108static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
109				       u8 *buf, int wc)
110{
111	struct hostap_interface *iface;
112	local_info_t *local;
113	unsigned long flags;
114
115	iface = netdev_priv(dev);
116	local = iface->local;
117	spin_lock_irqsave(&local->lock, flags);
118	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
119	outsw(dev->base_addr + a, buf, wc);
120	spin_unlock_irqrestore(&local->lock, flags);
121}
122
123static inline void hfa384x_insw_debug(struct net_device *dev, int a,
124				      u8 *buf, int wc)
125{
126	struct hostap_interface *iface;
127	local_info_t *local;
128	unsigned long flags;
129
130	iface = netdev_priv(dev);
131	local = iface->local;
132	spin_lock_irqsave(&local->lock, flags);
133	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
134	insw(dev->base_addr + a, buf, wc);
135	spin_unlock_irqrestore(&local->lock, flags);
136}
137
138#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
139#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
140#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
141#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
142#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
143#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
144
145#else /* PRISM2_IO_DEBUG */
146
147#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
148#define HFA384X_INB(a) inb(dev->base_addr + (a))
149#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
150#define HFA384X_INW(a) inw(dev->base_addr + (a))
151#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
152#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
153
154#endif /* PRISM2_IO_DEBUG */
155
156
157static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
158			    int len)
159{
160	u16 d_off;
161	u16 *pos;
162
163	d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
164	pos = (u16 *) buf;
165
166	if (len / 2)
167		HFA384X_INSW(d_off, buf, len / 2);
168	pos += len / 2;
169
170	if (len & 1)
171		*((char *) pos) = HFA384X_INB(d_off);
172
173	return 0;
174}
175
176
177static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
178{
179	u16 d_off;
180	u16 *pos;
181
182	d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
183	pos = (u16 *) buf;
184
185	if (len / 2)
186		HFA384X_OUTSW(d_off, buf, len / 2);
187	pos += len / 2;
188
189	if (len & 1)
190		HFA384X_OUTB(*((char *) pos), d_off);
191
192	return 0;
193}
194
195
196/* FIX: This might change at some point.. */
197#include "hostap_hw.c"
198
199
200
201static void prism2_detach(struct pcmcia_device *p_dev);
202static void prism2_release(u_long arg);
203static int prism2_config(struct pcmcia_device *link);
204
205
206static int prism2_pccard_card_present(local_info_t *local)
207{
208	struct hostap_cs_priv *hw_priv = local->hw_priv;
209	if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link))
210		return 1;
211	return 0;
212}
213
214
215/*
216 * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0
217 * Document No. 20-10-00058, January 2004
218 * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf
219 */
220#define SANDISK_WLAN_ACTIVATION_OFF 0x40
221#define SANDISK_HCR_OFF 0x42
222
223
224static void sandisk_set_iobase(local_info_t *local)
225{
226	int res;
227	struct hostap_cs_priv *hw_priv = local->hw_priv;
228
229	res = pcmcia_write_config_byte(hw_priv->link, 0x10,
230				hw_priv->link->resource[0]->start & 0x00ff);
231	if (res != 0) {
232		printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
233		       " res=%d\n", res);
234	}
235	udelay(10);
236
237	res = pcmcia_write_config_byte(hw_priv->link, 0x12,
238				(hw_priv->link->resource[0]->start >> 8) & 0x00ff);
239	if (res != 0) {
240		printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
241		       " res=%d\n", res);
242	}
243}
244
245
246static void sandisk_write_hcr(local_info_t *local, int hcr)
247{
248	struct net_device *dev = local->dev;
249	int i;
250
251	HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF);
252	udelay(50);
253	for (i = 0; i < 10; i++) {
254		HFA384X_OUTB(hcr, SANDISK_HCR_OFF);
255	}
256	udelay(55);
257	HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF);
258}
259
260
261static int sandisk_enable_wireless(struct net_device *dev)
262{
263	int res, ret = 0;
264	struct hostap_interface *iface = netdev_priv(dev);
265	local_info_t *local = iface->local;
266	struct hostap_cs_priv *hw_priv = local->hw_priv;
267
268	if (resource_size(hw_priv->link->resource[0]) < 0x42) {
269		/* Not enough ports to be SanDisk multi-function card */
270		ret = -ENODEV;
271		goto done;
272	}
273
274	if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) {
275		/* No SanDisk manfid found */
276		ret = -ENODEV;
277		goto done;
278	}
279
280	if (hw_priv->link->socket->functions < 2) {
281		/* No multi-function links found */
282		ret = -ENODEV;
283		goto done;
284	}
285
286	printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected"
287	       " - using vendor-specific initialization\n", dev->name);
288	hw_priv->sandisk_connectplus = 1;
289
290	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
291				COR_SOFT_RESET);
292	if (res != 0) {
293		printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
294		       dev->name, res);
295		goto done;
296	}
297	mdelay(5);
298
299	/*
300	 * Do not enable interrupts here to avoid some bogus events. Interrupts
301	 * will be enabled during the first cor_sreset call.
302	 */
303	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
304				(COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE |
305					COR_FUNC_ENA));
306	if (res != 0) {
307		printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
308		       dev->name, res);
309		goto done;
310	}
311	mdelay(5);
312
313	sandisk_set_iobase(local);
314
315	HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF);
316	udelay(10);
317	HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF);
318	udelay(10);
319
320done:
321	return ret;
322}
323
324
325static void prism2_pccard_cor_sreset(local_info_t *local)
326{
327	int res;
328	u8 val;
329	struct hostap_cs_priv *hw_priv = local->hw_priv;
330
331	if (!prism2_pccard_card_present(local))
332	       return;
333
334	res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val);
335	if (res != 0) {
336		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
337		       res);
338		return;
339	}
340	printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n",
341		val);
342
343	val |= COR_SOFT_RESET;
344	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
345	if (res != 0) {
346		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
347		       res);
348		return;
349	}
350
351	mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
352
353	val &= ~COR_SOFT_RESET;
354	if (hw_priv->sandisk_connectplus)
355		val |= COR_IREQ_ENA;
356	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
357	if (res != 0) {
358		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
359		       res);
360		return;
361	}
362
363	mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
364
365	if (hw_priv->sandisk_connectplus)
366		sandisk_set_iobase(local);
367}
368
369
370static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
371{
372	int res;
373	u8 old_cor;
374	struct hostap_cs_priv *hw_priv = local->hw_priv;
375
376	if (!prism2_pccard_card_present(local))
377	       return;
378
379	if (hw_priv->sandisk_connectplus) {
380		sandisk_write_hcr(local, hcr);
381		return;
382	}
383
384	res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor);
385	if (res != 0) {
386		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 "
387		       "(%d)\n", res);
388		return;
389	}
390	printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n",
391		old_cor);
392
393	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
394				old_cor | COR_SOFT_RESET);
395	if (res != 0) {
396		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 "
397		       "(%d)\n", res);
398		return;
399	}
400
401	mdelay(10);
402
403	/* Setup Genesis mode */
404	res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr);
405	if (res != 0) {
406		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 "
407		       "(%d)\n", res);
408		return;
409	}
410	mdelay(10);
411
412	res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
413				old_cor & ~COR_SOFT_RESET);
414	if (res != 0) {
415		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 "
416		       "(%d)\n", res);
417		return;
418	}
419
420	mdelay(10);
421}
422
423
424static struct prism2_helper_functions prism2_pccard_funcs =
425{
426	.card_present	= prism2_pccard_card_present,
427	.cor_sreset	= prism2_pccard_cor_sreset,
428	.genesis_reset	= prism2_pccard_genesis_reset,
429	.hw_type	= HOSTAP_HW_PCCARD,
430};
431
432
433/* allocate local data and register with CardServices
434 * initialize dev_link structure, but do not configure the card yet */
435static int hostap_cs_probe(struct pcmcia_device *p_dev)
436{
437	int ret;
438
439	PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
440	p_dev->conf.IntType = INT_MEMORY_AND_IO;
441
442	ret = prism2_config(p_dev);
443	if (ret) {
444		PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n");
445	}
446
447	return ret;
448}
449
450
451static void prism2_detach(struct pcmcia_device *link)
452{
453	PDEBUG(DEBUG_FLOW, "prism2_detach\n");
454
455	prism2_release((u_long)link);
456
457	/* release net devices */
458	if (link->priv) {
459		struct hostap_cs_priv *hw_priv;
460		struct net_device *dev;
461		struct hostap_interface *iface;
462		dev = link->priv;
463		iface = netdev_priv(dev);
464		hw_priv = iface->local->hw_priv;
465		prism2_free_local_data(dev);
466		kfree(hw_priv);
467	}
468}
469
470
471/* run after a CARD_INSERTION event is received to configure the PCMCIA
472 * socket and make the device available to the system */
473
474static int prism2_config_check(struct pcmcia_device *p_dev,
475			       cistpl_cftable_entry_t *cfg,
476			       cistpl_cftable_entry_t *dflt,
477			       unsigned int vcc,
478			       void *priv_data)
479{
480	if (cfg->index == 0)
481		return -ENODEV;
482
483	PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
484	       "(default 0x%02X)\n", cfg->index, dflt->index);
485
486	/* Does this card need audio output? */
487	if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
488		p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
489		p_dev->conf.Status = CCSR_AUDIO_ENA;
490	}
491
492	/* Use power settings for Vcc and Vpp if present */
493	/*  Note that the CIS values need to be rescaled */
494	if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
495		if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
496		    10000 && !ignore_cis_vcc) {
497			PDEBUG(DEBUG_EXTRA, "  Vcc mismatch - skipping"
498			       " this entry\n");
499			return -ENODEV;
500		}
501	} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
502		if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] /
503		    10000 && !ignore_cis_vcc) {
504			PDEBUG(DEBUG_EXTRA, "  Vcc (default) mismatch "
505			       "- skipping this entry\n");
506			return -ENODEV;
507		}
508	}
509
510	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
511		p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
512	else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
513		p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
514
515	/* Do we need to allocate an interrupt? */
516	p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
517
518	/* IO window settings */
519	PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
520	       "dflt->io.nwin=%d\n",
521	       cfg->io.nwin, dflt->io.nwin);
522	p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
523	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
524		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
525		p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
526		p_dev->resource[0]->flags |=
527					pcmcia_io_cfg_data_width(io->flags);
528		p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
529		p_dev->resource[0]->start = io->win[0].base;
530		p_dev->resource[0]->end = io->win[0].len;
531		if (io->nwin > 1) {
532			p_dev->resource[1]->flags = p_dev->resource[0]->flags;
533			p_dev->resource[1]->start = io->win[1].base;
534			p_dev->resource[1]->end = io->win[1].len;
535		}
536	}
537
538	/* This reserves IO space but doesn't actually enable it */
539	return pcmcia_request_io(p_dev);
540}
541
542static int prism2_config(struct pcmcia_device *link)
543{
544	struct net_device *dev;
545	struct hostap_interface *iface;
546	local_info_t *local;
547	int ret = 1;
548	struct hostap_cs_priv *hw_priv;
549	unsigned long flags;
550
551	PDEBUG(DEBUG_FLOW, "prism2_config()\n");
552
553	hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
554	if (hw_priv == NULL) {
555		ret = -ENOMEM;
556		goto failed;
557	}
558
559	/* Look for an appropriate configuration table entry in the CIS */
560	ret = pcmcia_loop_config(link, prism2_config_check, NULL);
561	if (ret) {
562		if (!ignore_cis_vcc)
563			printk(KERN_ERR "GetNextTuple(): No matching "
564			       "CIS configuration.  Maybe you need the "
565			       "ignore_cis_vcc=1 parameter.\n");
566		goto failed;
567	}
568
569	/* Need to allocate net_device before requesting IRQ handler */
570	dev = prism2_init_local_data(&prism2_pccard_funcs, 0,
571				     &link->dev);
572	if (dev == NULL)
573		goto failed;
574	link->priv = dev;
575
576	iface = netdev_priv(dev);
577	local = iface->local;
578	local->hw_priv = hw_priv;
579	hw_priv->link = link;
580
581	/*
582	 * Make sure the IRQ handler cannot proceed until at least
583	 * dev->base_addr is initialized.
584	 */
585	spin_lock_irqsave(&local->irq_init_lock, flags);
586
587	ret = pcmcia_request_irq(link, prism2_interrupt);
588	if (ret)
589		goto failed_unlock;
590
591	/*
592	 * This actually configures the PCMCIA socket -- setting up
593	 * the I/O windows and the interrupt mapping, and putting the
594	 * card and host interface into "Memory and IO" mode.
595	 */
596	ret = pcmcia_request_configuration(link, &link->conf);
597	if (ret)
598		goto failed_unlock;
599
600	dev->irq = link->irq;
601	dev->base_addr = link->resource[0]->start;
602
603	spin_unlock_irqrestore(&local->irq_init_lock, flags);
604
605	/* Finally, report what we've done */
606	printk(KERN_INFO "%s: index 0x%02x: ",
607	       dev_info, link->conf.ConfigIndex);
608	if (link->conf.Vpp)
609		printk(", Vpp %d.%d", link->conf.Vpp / 10,
610		       link->conf.Vpp % 10);
611	if (link->conf.Attributes & CONF_ENABLE_IRQ)
612		printk(", irq %d", link->irq);
613	if (link->resource[0])
614		printk(" & %pR", link->resource[0]);
615	if (link->resource[1])
616		printk(" & %pR", link->resource[1]);
617	printk("\n");
618
619	local->shutdown = 0;
620
621	sandisk_enable_wireless(dev);
622
623	ret = prism2_hw_config(dev, 1);
624	if (!ret)
625		ret = hostap_hw_ready(dev);
626
627	return ret;
628
629 failed_unlock:
630	 spin_unlock_irqrestore(&local->irq_init_lock, flags);
631 failed:
632	kfree(hw_priv);
633	prism2_release((u_long)link);
634	return ret;
635}
636
637
638static void prism2_release(u_long arg)
639{
640	struct pcmcia_device *link = (struct pcmcia_device *)arg;
641
642	PDEBUG(DEBUG_FLOW, "prism2_release\n");
643
644	if (link->priv) {
645		struct net_device *dev = link->priv;
646		struct hostap_interface *iface;
647
648		iface = netdev_priv(dev);
649		prism2_hw_shutdown(dev, 0);
650		iface->local->shutdown = 1;
651	}
652
653	pcmcia_disable_device(link);
654	PDEBUG(DEBUG_FLOW, "release - done\n");
655}
656
657static int hostap_cs_suspend(struct pcmcia_device *link)
658{
659	struct net_device *dev = (struct net_device *) link->priv;
660	int dev_open = 0;
661	struct hostap_interface *iface = NULL;
662
663	if (!dev)
664		return -ENODEV;
665
666	iface = netdev_priv(dev);
667
668	PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
669	if (iface && iface->local)
670		dev_open = iface->local->num_dev_open > 0;
671	if (dev_open) {
672		netif_stop_queue(dev);
673		netif_device_detach(dev);
674	}
675	prism2_suspend(dev);
676
677	return 0;
678}
679
680static int hostap_cs_resume(struct pcmcia_device *link)
681{
682	struct net_device *dev = (struct net_device *) link->priv;
683	int dev_open = 0;
684	struct hostap_interface *iface = NULL;
685
686	if (!dev)
687		return -ENODEV;
688
689	iface = netdev_priv(dev);
690
691	PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
692
693	if (iface && iface->local)
694		dev_open = iface->local->num_dev_open > 0;
695
696	prism2_hw_shutdown(dev, 1);
697	prism2_hw_config(dev, dev_open ? 0 : 1);
698	if (dev_open) {
699		netif_device_attach(dev);
700		netif_start_queue(dev);
701	}
702
703	return 0;
704}
705
706static struct pcmcia_device_id hostap_cs_ids[] = {
707	PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
708	PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
709	PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
710	PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
711	PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
712	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301),
713	PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
714	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
715	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
716	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
717	PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
718	PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
719	PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001),
720	PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
721	PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
722/*	PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000),    conflict with pcnet_cs */
723	PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
724	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
725	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
726	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
727	PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
728	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF",
729					 0x2d858104),
730	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
731					 0x74c5e40d),
732	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
733					 0x4b801a17),
734	PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
735				    0x7a954bd9, 0x74be00c6),
736	PCMCIA_DEVICE_PROD_ID123(
737		"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
738		0xe6ec52ce, 0x08649af2, 0x4b74baa0),
739	PCMCIA_DEVICE_PROD_ID123(
740		"D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02",
741		0x71b18589, 0xb6f1b0ab, 0x4b74baa0),
742	PCMCIA_DEVICE_PROD_ID123(
743		"Instant Wireless ", " Network PC CARD", "Version 01.02",
744		0x11d901af, 0x6e9bd926, 0x4b74baa0),
745	PCMCIA_DEVICE_PROD_ID123(
746		"SMC", "SMC2632W", "Version 01.02",
747		0xc4f8b18b, 0x474a1f2a, 0x4b74baa0),
748	PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G",
749				0x2decece3, 0x82067c18),
750	PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card",
751				0x54f7c49c, 0x15a75e5b),
752	PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE",
753				0x74c5e40d, 0xdb472a18),
754	PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card",
755				0x0733cc81, 0x0c52f395),
756	PCMCIA_DEVICE_PROD_ID12(
757		"ZoomAir 11Mbps High", "Rate wireless Networking",
758		0x273fe3db, 0x32a1eaee),
759	PCMCIA_DEVICE_PROD_ID123(
760		"Pretec", "CompactWLAN Card 802.11b", "2.5",
761		0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
762	PCMCIA_DEVICE_PROD_ID123(
763		"U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02",
764		0xc7b8df9d, 0x1700d087, 0x4b74baa0),
765	PCMCIA_DEVICE_PROD_ID123(
766		"Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio",
767		"Ver. 1.00",
768		0x5cd01705, 0x4271660f, 0x9d08ee12),
769	PCMCIA_DEVICE_PROD_ID123(
770		"Wireless LAN" , "11Mbps PC Card", "Version 01.02",
771		0x4b8870ff, 0x70e946d1, 0x4b74baa0),
772	PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
773	PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
774	PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
775	PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
776	PCMCIA_DEVICE_NULL
777};
778MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
779
780
781static struct pcmcia_driver hostap_driver = {
782	.drv		= {
783		.name	= "hostap_cs",
784	},
785	.probe		= hostap_cs_probe,
786	.remove		= prism2_detach,
787	.owner		= THIS_MODULE,
788	.id_table	= hostap_cs_ids,
789	.suspend	= hostap_cs_suspend,
790	.resume		= hostap_cs_resume,
791};
792
793static int __init init_prism2_pccard(void)
794{
795	return pcmcia_register_driver(&hostap_driver);
796}
797
798static void __exit exit_prism2_pccard(void)
799{
800	pcmcia_unregister_driver(&hostap_driver);
801}
802
803
804module_init(init_prism2_pccard);
805module_exit(exit_prism2_pccard);
806