ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / net / wireless / airport.c
1 /* airport.c 0.13e
2  *
3  * A driver for "Hermes" chipset based Apple Airport wireless
4  * card.
5  *
6  * Copyright notice & release notes in file orinoco.c
7  * 
8  * Note specific to airport stub:
9  * 
10  *  0.05 : first version of the new split driver
11  *  0.06 : fix possible hang on powerup, add sleep support
12  */
13
14 #include <linux/config.h>
15
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/ptrace.h>
20 #include <linux/slab.h>
21 #include <linux/string.h>
22 #include <linux/timer.h>
23 #include <linux/ioport.h>
24 #include <linux/netdevice.h>
25 #include <linux/if_arp.h>
26 #include <linux/etherdevice.h>
27 #include <linux/wireless.h>
28
29 #include <asm/io.h>
30 #include <asm/system.h>
31 #include <asm/current.h>
32 #include <asm/prom.h>
33 #include <asm/machdep.h>
34 #include <asm/pmac_feature.h>
35 #include <asm/irq.h>
36 #include <asm/uaccess.h>
37
38 #include "orinoco.h"
39
40 #define AIRPORT_IO_LEN  (0x1000)        /* one page */
41
42 struct airport {
43         struct macio_dev *mdev;
44         void *vaddr;
45         int irq_requested;
46         int ndev_registered;
47 };
48
49 static int
50 airport_suspend(struct macio_dev *mdev, u32 state)
51 {
52         struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
53         struct orinoco_private *priv = dev->priv;
54         unsigned long flags;
55         int err;
56
57         printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
58
59         err = orinoco_lock(priv, &flags);
60         if (err) {
61                 printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
62                        dev->name);
63                 return 0;
64         }
65
66         err = __orinoco_down(dev);
67         if (err)
68                 printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
69                        dev->name, err);
70
71         netif_device_detach(dev);
72
73         priv->hw_unavailable++;
74
75         orinoco_unlock(priv, &flags);
76
77         disable_irq(dev->irq);
78         pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
79
80         return 0;
81 }
82
83 static int
84 airport_resume(struct macio_dev *mdev)
85 {
86         struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
87         struct orinoco_private *priv = dev->priv;
88         unsigned long flags;
89         int err;
90
91         printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
92
93         pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
94         set_current_state(TASK_UNINTERRUPTIBLE);
95         schedule_timeout(HZ/5);
96
97         enable_irq(dev->irq);
98
99         err = orinoco_reinit_firmware(dev);
100         if (err) {
101                 printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
102                        dev->name, err);
103                 return 0;
104         }
105
106         spin_lock_irqsave(&priv->lock, flags);
107
108         netif_device_attach(dev);
109
110         priv->hw_unavailable--;
111
112         if (priv->open && (! priv->hw_unavailable)) {
113                 err = __orinoco_up(dev);
114                 if (err)
115                         printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
116                                dev->name, err);
117         }
118
119
120         spin_unlock_irqrestore(&priv->lock, flags);
121
122         return 0;
123 }
124
125 static int
126 airport_detach(struct macio_dev *mdev)
127 {
128         struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
129         struct orinoco_private *priv = dev->priv;
130         struct airport *card = priv->card;
131
132         if (card->ndev_registered)
133                 unregister_netdev(dev);
134         card->ndev_registered = 0;
135
136         if (card->irq_requested)
137                 free_irq(dev->irq, dev);
138         card->irq_requested = 0;
139
140         if (card->vaddr)
141                 iounmap(card->vaddr);
142         card->vaddr = 0;
143
144         macio_release_resource(mdev, 0);
145
146         pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
147         set_current_state(TASK_UNINTERRUPTIBLE);
148         schedule_timeout(HZ);
149
150         macio_set_drvdata(mdev, NULL);
151         free_netdev(dev);
152
153         return 0;
154 }
155
156 static int airport_hard_reset(struct orinoco_private *priv)
157 {
158         /* It would be nice to power cycle the Airport for a real hard
159          * reset, but for some reason although it appears to
160          * re-initialize properly, it falls in a screaming heap
161          * shortly afterwards. */
162 #if 0
163         struct net_device *dev = priv->ndev;
164         struct airport *card = priv->card;
165
166         /* Vitally important.  If we don't do this it seems we get an
167          * interrupt somewhere during the power cycle, since
168          * hw_unavailable is already set it doesn't get ACKed, we get
169          * into an interrupt loop and the the PMU decides to turn us
170          * off. */
171         disable_irq(dev->irq);
172
173         pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0);
174         set_current_state(TASK_UNINTERRUPTIBLE);
175         schedule_timeout(HZ);
176         pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1);
177         set_current_state(TASK_UNINTERRUPTIBLE);
178         schedule_timeout(HZ);
179
180         enable_irq(dev->irq);
181         schedule_timeout(HZ);
182 #endif
183
184         return 0;
185 }
186
187 static int
188 airport_attach(struct macio_dev *mdev, const struct of_match *match)
189 {
190         struct orinoco_private *priv;
191         struct net_device *dev;
192         struct airport *card;
193         unsigned long phys_addr;
194         hermes_t *hw;
195
196         if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
197                 printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n");
198                 return -ENODEV;
199         }
200
201         /* Allocate space for private device-specific data */
202         dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
203         if (! dev) {
204                 printk(KERN_ERR "airport: can't allocate device datas\n");
205                 return -ENODEV;
206         }
207         priv = dev->priv;
208         card = priv->card;
209
210         hw = &priv->hw;
211         card->mdev = mdev;
212
213         if (macio_request_resource(mdev, 0, "airport")) {
214                 printk(KERN_ERR "airport: can't request IO resource !\n");
215                 free_netdev(dev);
216                 return -EBUSY;
217         }
218
219         SET_MODULE_OWNER(dev);
220         SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
221
222         macio_set_drvdata(mdev, dev);
223
224         /* Setup interrupts & base address */
225         dev->irq = macio_irq(mdev, 0);
226         phys_addr = macio_resource_start(mdev, 0);  /* Physical address */
227         printk(KERN_DEBUG "Airport at physical address %lx\n", phys_addr);
228         dev->base_addr = phys_addr;
229         card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
230         if (!card->vaddr) {
231                 printk("airport: ioremap() failed\n");
232                 goto failed;
233         }
234
235         hermes_struct_init(hw, (ulong)card->vaddr,
236                         HERMES_MEM, HERMES_16BIT_REGSPACING);
237                 
238         /* Power up card */
239         pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
240         set_current_state(TASK_UNINTERRUPTIBLE);
241         schedule_timeout(HZ);
242
243         /* Reset it before we get the interrupt */
244         hermes_init(hw);
245
246         if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", dev)) {
247                 printk(KERN_ERR "airport: Couldn't get IRQ %d\n", dev->irq);
248                 goto failed;
249         }
250         card->irq_requested = 1;
251
252         /* Tell the stack we exist */
253         if (register_netdev(dev) != 0) {
254                 printk(KERN_ERR "airport: register_netdev() failed\n");
255                 goto failed;
256         }
257         printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name);
258         card->ndev_registered = 1;
259         return 0;
260  failed:
261         airport_detach(mdev);
262         return -ENODEV;
263 }                               /* airport_attach */
264
265
266 static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
267 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
268 MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
269 MODULE_LICENSE("Dual MPL/GPL");
270
271 static struct of_match airport_match[] = 
272 {
273         {
274         .name           = "radio",
275         .type           = OF_ANY_MATCH,
276         .compatible     = OF_ANY_MATCH
277         },
278         {},
279 };
280
281 static struct macio_driver airport_driver = 
282 {
283         .name           = "airport",
284         .match_table    = airport_match,
285         .probe          = airport_attach,
286         .remove         = airport_detach,
287         .suspend        = airport_suspend,
288         .resume         = airport_resume,
289 };
290
291 static int __init
292 init_airport(void)
293 {
294         printk(KERN_DEBUG "%s\n", version);
295
296         return macio_register_driver(&airport_driver);
297 }
298
299 static void __exit
300 exit_airport(void)
301 {
302         return macio_unregister_driver(&airport_driver);
303 }
304
305 module_init(init_airport);
306 module_exit(exit_airport);