xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/intersil/hostap/hostap_pci.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun #define PRISM2_PCI
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun /* Host AP driver's support for Intersil Prism2.5 PCI cards is based on
5*4882a593Smuzhiyun  * driver patches from Reyk Floeter <reyk@vantronix.net> and
6*4882a593Smuzhiyun  * Andy Warner <andyw@pobox.com> */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/if.h>
10*4882a593Smuzhiyun #include <linux/skbuff.h>
11*4882a593Smuzhiyun #include <linux/netdevice.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <linux/workqueue.h>
14*4882a593Smuzhiyun #include <linux/wireless.h>
15*4882a593Smuzhiyun #include <net/iw_handler.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <linux/ioport.h>
18*4882a593Smuzhiyun #include <linux/pci.h>
19*4882a593Smuzhiyun #include <asm/io.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include "hostap_wlan.h"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun static char *dev_info = "hostap_pci";
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun MODULE_AUTHOR("Jouni Malinen");
28*4882a593Smuzhiyun MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
29*4882a593Smuzhiyun 		   "PCI cards.");
30*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
31*4882a593Smuzhiyun MODULE_LICENSE("GPL");
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /* struct local_info::hw_priv */
35*4882a593Smuzhiyun struct hostap_pci_priv {
36*4882a593Smuzhiyun 	void __iomem *mem_start;
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* FIX: do we need mb/wmb/rmb with memory operations? */
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static const struct pci_device_id prism2_pci_id_table[] = {
44*4882a593Smuzhiyun 	/* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
45*4882a593Smuzhiyun 	{ 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
46*4882a593Smuzhiyun 	/* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
47*4882a593Smuzhiyun 	{ 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID },
48*4882a593Smuzhiyun 	/* Samsung MagicLAN SWL-2210P */
49*4882a593Smuzhiyun 	{ 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID },
50*4882a593Smuzhiyun 	{ 0 }
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #ifdef PRISM2_IO_DEBUG
55*4882a593Smuzhiyun 
hfa384x_outb_debug(struct net_device * dev,int a,u8 v)56*4882a593Smuzhiyun static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	struct hostap_interface *iface;
59*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
60*4882a593Smuzhiyun 	local_info_t *local;
61*4882a593Smuzhiyun 	unsigned long flags;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	iface = netdev_priv(dev);
64*4882a593Smuzhiyun 	local = iface->local;
65*4882a593Smuzhiyun 	hw_priv = local->hw_priv;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	spin_lock_irqsave(&local->lock, flags);
68*4882a593Smuzhiyun 	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
69*4882a593Smuzhiyun 	writeb(v, hw_priv->mem_start + a);
70*4882a593Smuzhiyun 	spin_unlock_irqrestore(&local->lock, flags);
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
hfa384x_inb_debug(struct net_device * dev,int a)73*4882a593Smuzhiyun static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	struct hostap_interface *iface;
76*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
77*4882a593Smuzhiyun 	local_info_t *local;
78*4882a593Smuzhiyun 	unsigned long flags;
79*4882a593Smuzhiyun 	u8 v;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	iface = netdev_priv(dev);
82*4882a593Smuzhiyun 	local = iface->local;
83*4882a593Smuzhiyun 	hw_priv = local->hw_priv;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	spin_lock_irqsave(&local->lock, flags);
86*4882a593Smuzhiyun 	v = readb(hw_priv->mem_start + a);
87*4882a593Smuzhiyun 	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
88*4882a593Smuzhiyun 	spin_unlock_irqrestore(&local->lock, flags);
89*4882a593Smuzhiyun 	return v;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
hfa384x_outw_debug(struct net_device * dev,int a,u16 v)92*4882a593Smuzhiyun static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	struct hostap_interface *iface;
95*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
96*4882a593Smuzhiyun 	local_info_t *local;
97*4882a593Smuzhiyun 	unsigned long flags;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	iface = netdev_priv(dev);
100*4882a593Smuzhiyun 	local = iface->local;
101*4882a593Smuzhiyun 	hw_priv = local->hw_priv;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	spin_lock_irqsave(&local->lock, flags);
104*4882a593Smuzhiyun 	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
105*4882a593Smuzhiyun 	writew(v, hw_priv->mem_start + a);
106*4882a593Smuzhiyun 	spin_unlock_irqrestore(&local->lock, flags);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
hfa384x_inw_debug(struct net_device * dev,int a)109*4882a593Smuzhiyun static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	struct hostap_interface *iface;
112*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
113*4882a593Smuzhiyun 	local_info_t *local;
114*4882a593Smuzhiyun 	unsigned long flags;
115*4882a593Smuzhiyun 	u16 v;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	iface = netdev_priv(dev);
118*4882a593Smuzhiyun 	local = iface->local;
119*4882a593Smuzhiyun 	hw_priv = local->hw_priv;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	spin_lock_irqsave(&local->lock, flags);
122*4882a593Smuzhiyun 	v = readw(hw_priv->mem_start + a);
123*4882a593Smuzhiyun 	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
124*4882a593Smuzhiyun 	spin_unlock_irqrestore(&local->lock, flags);
125*4882a593Smuzhiyun 	return v;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
129*4882a593Smuzhiyun #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
130*4882a593Smuzhiyun #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
131*4882a593Smuzhiyun #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
132*4882a593Smuzhiyun #define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v)))
133*4882a593Smuzhiyun #define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a)))
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun #else /* PRISM2_IO_DEBUG */
136*4882a593Smuzhiyun 
hfa384x_outb(struct net_device * dev,int a,u8 v)137*4882a593Smuzhiyun static inline void hfa384x_outb(struct net_device *dev, int a, u8 v)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	struct hostap_interface *iface;
140*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
141*4882a593Smuzhiyun 	iface = netdev_priv(dev);
142*4882a593Smuzhiyun 	hw_priv = iface->local->hw_priv;
143*4882a593Smuzhiyun 	writeb(v, hw_priv->mem_start + a);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
hfa384x_inb(struct net_device * dev,int a)146*4882a593Smuzhiyun static inline u8 hfa384x_inb(struct net_device *dev, int a)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	struct hostap_interface *iface;
149*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
150*4882a593Smuzhiyun 	iface = netdev_priv(dev);
151*4882a593Smuzhiyun 	hw_priv = iface->local->hw_priv;
152*4882a593Smuzhiyun 	return readb(hw_priv->mem_start + a);
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
hfa384x_outw(struct net_device * dev,int a,u16 v)155*4882a593Smuzhiyun static inline void hfa384x_outw(struct net_device *dev, int a, u16 v)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct hostap_interface *iface;
158*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
159*4882a593Smuzhiyun 	iface = netdev_priv(dev);
160*4882a593Smuzhiyun 	hw_priv = iface->local->hw_priv;
161*4882a593Smuzhiyun 	writew(v, hw_priv->mem_start + a);
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
hfa384x_inw(struct net_device * dev,int a)164*4882a593Smuzhiyun static inline u16 hfa384x_inw(struct net_device *dev, int a)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	struct hostap_interface *iface;
167*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
168*4882a593Smuzhiyun 	iface = netdev_priv(dev);
169*4882a593Smuzhiyun 	hw_priv = iface->local->hw_priv;
170*4882a593Smuzhiyun 	return readw(hw_priv->mem_start + a);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun #define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v))
174*4882a593Smuzhiyun #define HFA384X_INB(a) hfa384x_inb(dev, (a))
175*4882a593Smuzhiyun #define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v))
176*4882a593Smuzhiyun #define HFA384X_INW(a) hfa384x_inw(dev, (a))
177*4882a593Smuzhiyun #define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v)))
178*4882a593Smuzhiyun #define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a)))
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun #endif /* PRISM2_IO_DEBUG */
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 
hfa384x_from_bap(struct net_device * dev,u16 bap,void * buf,int len)183*4882a593Smuzhiyun static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
184*4882a593Smuzhiyun 			    int len)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	u16 d_off;
187*4882a593Smuzhiyun 	__le16 *pos;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
190*4882a593Smuzhiyun 	pos = (__le16 *) buf;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	for ( ; len > 1; len -= 2)
193*4882a593Smuzhiyun 		*pos++ = HFA384X_INW_DATA(d_off);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	if (len & 1)
196*4882a593Smuzhiyun 		*((char *) pos) = HFA384X_INB(d_off);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 
hfa384x_to_bap(struct net_device * dev,u16 bap,void * buf,int len)202*4882a593Smuzhiyun static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	u16 d_off;
205*4882a593Smuzhiyun 	__le16 *pos;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
208*4882a593Smuzhiyun 	pos = (__le16 *) buf;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	for ( ; len > 1; len -= 2)
211*4882a593Smuzhiyun 		HFA384X_OUTW_DATA(*pos++, d_off);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (len & 1)
214*4882a593Smuzhiyun 		HFA384X_OUTB(*((char *) pos), d_off);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	return 0;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun /* FIX: This might change at some point.. */
221*4882a593Smuzhiyun #include "hostap_hw.c"
222*4882a593Smuzhiyun 
prism2_pci_cor_sreset(local_info_t * local)223*4882a593Smuzhiyun static void prism2_pci_cor_sreset(local_info_t *local)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	struct net_device *dev = local->dev;
226*4882a593Smuzhiyun 	u16 reg;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	reg = HFA384X_INB(HFA384X_PCICOR_OFF);
229*4882a593Smuzhiyun 	printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	/* linux-wlan-ng uses extremely long hold and settle times for
232*4882a593Smuzhiyun 	 * COR sreset. A comment in the driver code mentions that the long
233*4882a593Smuzhiyun 	 * delays appear to be necessary. However, at least IBM 22P6901 seems
234*4882a593Smuzhiyun 	 * to work fine with shorter delays.
235*4882a593Smuzhiyun 	 *
236*4882a593Smuzhiyun 	 * Longer delays can be configured by uncommenting following line: */
237*4882a593Smuzhiyun /* #define PRISM2_PCI_USE_LONG_DELAYS */
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun #ifdef PRISM2_PCI_USE_LONG_DELAYS
240*4882a593Smuzhiyun 	int i;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
243*4882a593Smuzhiyun 	mdelay(250);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
246*4882a593Smuzhiyun 	mdelay(500);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	/* Wait for f/w to complete initialization (CMD:BUSY == 0) */
249*4882a593Smuzhiyun 	i = 2000000 / 10;
250*4882a593Smuzhiyun 	while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i)
251*4882a593Smuzhiyun 		udelay(10);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun #else /* PRISM2_PCI_USE_LONG_DELAYS */
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
256*4882a593Smuzhiyun 	mdelay(2);
257*4882a593Smuzhiyun 	HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
258*4882a593Smuzhiyun 	mdelay(2);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun #endif /* PRISM2_PCI_USE_LONG_DELAYS */
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) {
263*4882a593Smuzhiyun 		printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name);
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 
prism2_pci_genesis_reset(local_info_t * local,int hcr)268*4882a593Smuzhiyun static void prism2_pci_genesis_reset(local_info_t *local, int hcr)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	struct net_device *dev = local->dev;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF);
273*4882a593Smuzhiyun 	mdelay(10);
274*4882a593Smuzhiyun 	HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF);
275*4882a593Smuzhiyun 	mdelay(10);
276*4882a593Smuzhiyun 	HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF);
277*4882a593Smuzhiyun 	mdelay(10);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun static struct prism2_helper_functions prism2_pci_funcs =
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	.card_present	= NULL,
284*4882a593Smuzhiyun 	.cor_sreset	= prism2_pci_cor_sreset,
285*4882a593Smuzhiyun 	.genesis_reset	= prism2_pci_genesis_reset,
286*4882a593Smuzhiyun 	.hw_type	= HOSTAP_HW_PCI,
287*4882a593Smuzhiyun };
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 
prism2_pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)290*4882a593Smuzhiyun static int prism2_pci_probe(struct pci_dev *pdev,
291*4882a593Smuzhiyun 			    const struct pci_device_id *id)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	unsigned long phymem;
294*4882a593Smuzhiyun 	void __iomem *mem = NULL;
295*4882a593Smuzhiyun 	local_info_t *local = NULL;
296*4882a593Smuzhiyun 	struct net_device *dev = NULL;
297*4882a593Smuzhiyun 	static int cards_found /* = 0 */;
298*4882a593Smuzhiyun 	int irq_registered = 0;
299*4882a593Smuzhiyun 	struct hostap_interface *iface;
300*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
303*4882a593Smuzhiyun 	if (hw_priv == NULL)
304*4882a593Smuzhiyun 		return -ENOMEM;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	if (pci_enable_device(pdev))
307*4882a593Smuzhiyun 		goto err_out_free;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	phymem = pci_resource_start(pdev, 0);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
312*4882a593Smuzhiyun 		printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
313*4882a593Smuzhiyun 		goto err_out_disable;
314*4882a593Smuzhiyun 	}
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	mem = pci_ioremap_bar(pdev, 0);
317*4882a593Smuzhiyun 	if (mem == NULL) {
318*4882a593Smuzhiyun 		printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
319*4882a593Smuzhiyun 		goto fail;
320*4882a593Smuzhiyun 	}
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	dev = prism2_init_local_data(&prism2_pci_funcs, cards_found,
323*4882a593Smuzhiyun 				     &pdev->dev);
324*4882a593Smuzhiyun 	if (dev == NULL)
325*4882a593Smuzhiyun 		goto fail;
326*4882a593Smuzhiyun 	iface = netdev_priv(dev);
327*4882a593Smuzhiyun 	local = iface->local;
328*4882a593Smuzhiyun 	local->hw_priv = hw_priv;
329*4882a593Smuzhiyun 	cards_found++;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun         dev->irq = pdev->irq;
332*4882a593Smuzhiyun         hw_priv->mem_start = mem;
333*4882a593Smuzhiyun 	dev->base_addr = (unsigned long) mem;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	prism2_pci_cor_sreset(local);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	pci_set_drvdata(pdev, dev);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
340*4882a593Smuzhiyun 			dev)) {
341*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
342*4882a593Smuzhiyun 		goto fail;
343*4882a593Smuzhiyun 	} else
344*4882a593Smuzhiyun 		irq_registered = 1;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	if (!local->pri_only && prism2_hw_config(dev, 1)) {
347*4882a593Smuzhiyun 		printk(KERN_DEBUG "%s: hardware initialization failed\n",
348*4882a593Smuzhiyun 		       dev_info);
349*4882a593Smuzhiyun 		goto fail;
350*4882a593Smuzhiyun 	}
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	printk(KERN_INFO "%s: Intersil Prism2.5 PCI: "
353*4882a593Smuzhiyun 	       "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq);
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	return hostap_hw_ready(dev);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun  fail:
358*4882a593Smuzhiyun 	if (irq_registered && dev)
359*4882a593Smuzhiyun 		free_irq(dev->irq, dev);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	if (mem)
362*4882a593Smuzhiyun 		iounmap(mem);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	release_mem_region(phymem, pci_resource_len(pdev, 0));
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun  err_out_disable:
367*4882a593Smuzhiyun 	pci_disable_device(pdev);
368*4882a593Smuzhiyun 	prism2_free_local_data(dev);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun  err_out_free:
371*4882a593Smuzhiyun 	kfree(hw_priv);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	return -ENODEV;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 
prism2_pci_remove(struct pci_dev * pdev)377*4882a593Smuzhiyun static void prism2_pci_remove(struct pci_dev *pdev)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	struct net_device *dev;
380*4882a593Smuzhiyun 	struct hostap_interface *iface;
381*4882a593Smuzhiyun 	void __iomem *mem_start;
382*4882a593Smuzhiyun 	struct hostap_pci_priv *hw_priv;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	dev = pci_get_drvdata(pdev);
385*4882a593Smuzhiyun 	iface = netdev_priv(dev);
386*4882a593Smuzhiyun 	hw_priv = iface->local->hw_priv;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	/* Reset the hardware, and ensure interrupts are disabled. */
389*4882a593Smuzhiyun 	prism2_pci_cor_sreset(iface->local);
390*4882a593Smuzhiyun 	hfa384x_disable_interrupts(dev);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	if (dev->irq)
393*4882a593Smuzhiyun 		free_irq(dev->irq, dev);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	mem_start = hw_priv->mem_start;
396*4882a593Smuzhiyun 	prism2_free_local_data(dev);
397*4882a593Smuzhiyun 	kfree(hw_priv);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	iounmap(mem_start);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	release_mem_region(pci_resource_start(pdev, 0),
402*4882a593Smuzhiyun 			   pci_resource_len(pdev, 0));
403*4882a593Smuzhiyun 	pci_disable_device(pdev);
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun 
prism2_pci_suspend(struct device * dev_d)406*4882a593Smuzhiyun static int __maybe_unused prism2_pci_suspend(struct device *dev_d)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	struct net_device *dev = dev_get_drvdata(dev_d);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	if (netif_running(dev)) {
411*4882a593Smuzhiyun 		netif_stop_queue(dev);
412*4882a593Smuzhiyun 		netif_device_detach(dev);
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 	prism2_suspend(dev);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	return 0;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
prism2_pci_resume(struct device * dev_d)419*4882a593Smuzhiyun static int __maybe_unused prism2_pci_resume(struct device *dev_d)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	struct net_device *dev = dev_get_drvdata(dev_d);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	prism2_hw_config(dev, 0);
424*4882a593Smuzhiyun 	if (netif_running(dev)) {
425*4882a593Smuzhiyun 		netif_device_attach(dev);
426*4882a593Smuzhiyun 		netif_start_queue(dev);
427*4882a593Smuzhiyun 	}
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	return 0;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(prism2_pci_pm_ops,
435*4882a593Smuzhiyun 			 prism2_pci_suspend,
436*4882a593Smuzhiyun 			 prism2_pci_resume);
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun static struct pci_driver prism2_pci_driver = {
439*4882a593Smuzhiyun 	.name		= "hostap_pci",
440*4882a593Smuzhiyun 	.id_table	= prism2_pci_id_table,
441*4882a593Smuzhiyun 	.probe		= prism2_pci_probe,
442*4882a593Smuzhiyun 	.remove		= prism2_pci_remove,
443*4882a593Smuzhiyun 	.driver.pm	= &prism2_pci_pm_ops,
444*4882a593Smuzhiyun };
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun module_pci_driver(prism2_pci_driver);
447