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