ipwireless: make more use of pcmcia_loop_config()
[safe/jmp/linux-2.6] / drivers / char / pcmcia / ipwireless / main.c
1 /*
2  * IPWireless 3G PCMCIA Network Driver
3  *
4  * Original code
5  *   by Stephen Blackheath <stephen@blacksapphire.com>,
6  *      Ben Martel <benm@symmetric.co.nz>
7  *
8  * Copyrighted as follows:
9  *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
10  *
11  * Various driver changes and rewrites, port to new kernels
12  *   Copyright (C) 2006-2007 Jiri Kosina
13  *
14  * Misc code cleanups and updates
15  *   Copyright (C) 2007 David Sterba
16  */
17
18 #include "hardware.h"
19 #include "network.h"
20 #include "main.h"
21 #include "tty.h"
22
23 #include <linux/delay.h>
24 #include <linux/init.h>
25 #include <linux/io.h>
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/sched.h>
29 #include <linux/slab.h>
30
31 #include <pcmcia/cisreg.h>
32 #include <pcmcia/device_id.h>
33 #include <pcmcia/ss.h>
34 #include <pcmcia/ds.h>
35 #include <pcmcia/cs.h>
36
37 static struct pcmcia_device_id ipw_ids[] = {
38         PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),
39         PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200),
40         PCMCIA_DEVICE_NULL
41 };
42 MODULE_DEVICE_TABLE(pcmcia, ipw_ids);
43
44 static void ipwireless_detach(struct pcmcia_device *link);
45
46 /*
47  * Module params
48  */
49 /* Debug mode: more verbose, print sent/recv bytes */
50 int ipwireless_debug;
51 int ipwireless_loopback;
52 int ipwireless_out_queue = 10;
53
54 module_param_named(debug, ipwireless_debug, int, 0);
55 module_param_named(loopback, ipwireless_loopback, int, 0);
56 module_param_named(out_queue, ipwireless_out_queue, int, 0);
57 MODULE_PARM_DESC(debug, "switch on debug messages [0]");
58 MODULE_PARM_DESC(loopback,
59                 "debug: enable ras_raw channel [0]");
60 MODULE_PARM_DESC(out_queue, "debug: set size of outgoing PPP queue [10]");
61
62 /* Executes in process context. */
63 static void signalled_reboot_work(struct work_struct *work_reboot)
64 {
65         struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev,
66                         work_reboot);
67         struct pcmcia_device *link = ipw->link;
68         int ret = pcmcia_reset_card(link->socket);
69
70         if (ret != 0)
71                 cs_error(link, ResetCard, ret);
72 }
73
74 static void signalled_reboot_callback(void *callback_data)
75 {
76         struct ipw_dev *ipw = (struct ipw_dev *) callback_data;
77
78         /* Delegate to process context. */
79         schedule_work(&ipw->work_reboot);
80 }
81
82 static int ipwireless_probe(struct pcmcia_device *p_dev,
83                             cistpl_cftable_entry_t *cfg,
84                             cistpl_cftable_entry_t *dflt,
85                             unsigned int vcc,
86                             void *priv_data)
87 {
88         struct ipw_dev *ipw = priv_data;
89         struct resource *io_resource;
90         memreq_t memreq_attr_memory;
91         memreq_t memreq_common_memory;
92         int ret;
93
94         p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
95         p_dev->io.BasePort1 = cfg->io.win[0].base;
96         p_dev->io.NumPorts1 = cfg->io.win[0].len;
97         p_dev->io.IOAddrLines = 16;
98
99         p_dev->irq.IRQInfo1 = cfg->irq.IRQInfo1;
100
101         /* 0x40 causes it to generate level mode interrupts. */
102         /* 0x04 enables IREQ pin. */
103         p_dev->conf.ConfigIndex = cfg->index | 0x44;
104         ret = pcmcia_request_io(p_dev, &p_dev->io);
105         if (ret)
106                 return ret;
107
108         io_resource = request_region(p_dev->io.BasePort1, p_dev->io.NumPorts1,
109                                 IPWIRELESS_PCCARD_NAME);
110
111         if (cfg->mem.nwin == 0)
112                 return 0;
113
114         ipw->request_common_memory.Attributes =
115                 WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
116         ipw->request_common_memory.Base = cfg->mem.win[0].host_addr;
117         ipw->request_common_memory.Size = cfg->mem.win[0].len;
118         if (ipw->request_common_memory.Size < 0x1000)
119                 ipw->request_common_memory.Size = 0x1000;
120         ipw->request_common_memory.AccessSpeed = 0;
121
122         ret = pcmcia_request_window(&p_dev, &ipw->request_common_memory,
123                                 &ipw->handle_common_memory);
124
125         if (ret != 0) {
126                 cs_error(p_dev, RequestWindow, ret);
127                 goto exit1;
128         }
129
130         memreq_common_memory.CardOffset = cfg->mem.win[0].card_addr;
131         memreq_common_memory.Page = 0;
132
133         ret = pcmcia_map_mem_page(ipw->handle_common_memory,
134                                 &memreq_common_memory);
135
136         if (ret != 0) {
137                 cs_error(p_dev, MapMemPage, ret);
138                 goto exit2;
139         }
140
141         ipw->is_v2_card = cfg->mem.win[0].len == 0x100;
142
143         ipw->common_memory = ioremap(ipw->request_common_memory.Base,
144                                 ipw->request_common_memory.Size);
145         request_mem_region(ipw->request_common_memory.Base,
146                         ipw->request_common_memory.Size,
147                         IPWIRELESS_PCCARD_NAME);
148
149         ipw->request_attr_memory.Attributes =
150                 WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE;
151         ipw->request_attr_memory.Base = 0;
152         ipw->request_attr_memory.Size = 0;      /* this used to be 0x1000 */
153         ipw->request_attr_memory.AccessSpeed = 0;
154
155         ret = pcmcia_request_window(&p_dev, &ipw->request_attr_memory,
156                                 &ipw->handle_attr_memory);
157
158         if (ret != 0) {
159                 cs_error(p_dev, RequestWindow, ret);
160                 goto exit2;
161         }
162
163         memreq_attr_memory.CardOffset = 0;
164         memreq_attr_memory.Page = 0;
165
166         ret = pcmcia_map_mem_page(ipw->handle_attr_memory,
167                                 &memreq_attr_memory);
168
169         if (ret != 0) {
170                 cs_error(p_dev, MapMemPage, ret);
171                 goto exit3;
172         }
173
174         ipw->attr_memory = ioremap(ipw->request_attr_memory.Base,
175                                 ipw->request_attr_memory.Size);
176         request_mem_region(ipw->request_attr_memory.Base,
177                         ipw->request_attr_memory.Size, IPWIRELESS_PCCARD_NAME);
178
179         return 0;
180
181 exit3:
182         pcmcia_release_window(ipw->handle_attr_memory);
183 exit2:
184         if (ipw->common_memory) {
185                 release_mem_region(ipw->request_common_memory.Base,
186                                 ipw->request_common_memory.Size);
187                 iounmap(ipw->common_memory);
188                 pcmcia_release_window(ipw->handle_common_memory);
189         } else
190                 pcmcia_release_window(ipw->handle_common_memory);
191 exit1:
192         release_resource(io_resource);
193         pcmcia_disable_device(p_dev);
194         return -1;
195 }
196
197 static int config_ipwireless(struct ipw_dev *ipw)
198 {
199         struct pcmcia_device *link = ipw->link;
200         int ret = 0;
201
202         ipw->is_v2_card = 0;
203
204         ret = pcmcia_loop_config(link, ipwireless_probe, ipw);
205         if (ret != 0) {
206                 cs_error(link, RequestIO, ret);
207                 return ret;
208         }
209
210         link->conf.Attributes = CONF_ENABLE_IRQ;
211         link->conf.IntType = INT_MEMORY_AND_IO;
212
213         link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
214         link->irq.Handler = ipwireless_interrupt;
215         link->irq.Instance = ipw->hardware;
216
217         INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
218
219         ipwireless_init_hardware_v1(ipw->hardware, link->io.BasePort1,
220                                     ipw->attr_memory, ipw->common_memory,
221                                     ipw->is_v2_card, signalled_reboot_callback,
222                                     ipw);
223
224         ret = pcmcia_request_irq(link, &link->irq);
225
226         if (ret != 0) {
227                 cs_error(link, RequestIRQ, ret);
228                 goto exit;
229         }
230
231         printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
232                         ipw->is_v2_card ? "V2/V3" : "V1");
233         printk(KERN_INFO IPWIRELESS_PCCARD_NAME
234                         ": I/O ports 0x%04x-0x%04x, irq %d\n",
235                         (unsigned int) link->io.BasePort1,
236                         (unsigned int) (link->io.BasePort1 +
237                                 link->io.NumPorts1 - 1),
238                         (unsigned int) link->irq.AssignedIRQ);
239         if (ipw->attr_memory && ipw->common_memory)
240                 printk(KERN_INFO IPWIRELESS_PCCARD_NAME
241                         ": attr memory 0x%08lx-0x%08lx, common memory 0x%08lx-0x%08lx\n",
242                         ipw->request_attr_memory.Base,
243                         ipw->request_attr_memory.Base
244                         + ipw->request_attr_memory.Size - 1,
245                         ipw->request_common_memory.Base,
246                         ipw->request_common_memory.Base
247                         + ipw->request_common_memory.Size - 1);
248
249         ipw->network = ipwireless_network_create(ipw->hardware);
250         if (!ipw->network)
251                 goto exit;
252
253         ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network,
254                         ipw->nodes);
255         if (!ipw->tty)
256                 goto exit;
257
258         ipwireless_init_hardware_v2_v3(ipw->hardware);
259
260         /*
261          * Do the RequestConfiguration last, because it enables interrupts.
262          * Then we don't get any interrupts before we're ready for them.
263          */
264         ret = pcmcia_request_configuration(link, &link->conf);
265
266         if (ret != 0) {
267                 cs_error(link, RequestConfiguration, ret);
268                 goto exit;
269         }
270
271         link->dev_node = &ipw->nodes[0];
272
273         return 0;
274
275 exit:
276         if (ipw->attr_memory) {
277                 release_mem_region(ipw->request_attr_memory.Base,
278                                 ipw->request_attr_memory.Size);
279                 iounmap(ipw->attr_memory);
280                 pcmcia_release_window(ipw->handle_attr_memory);
281         }
282         if (ipw->common_memory) {
283                 release_mem_region(ipw->request_common_memory.Base,
284                                 ipw->request_common_memory.Size);
285                 iounmap(ipw->common_memory);
286                 pcmcia_release_window(ipw->handle_common_memory);
287         }
288         pcmcia_disable_device(link);
289         return -1;
290 }
291
292 static void release_ipwireless(struct ipw_dev *ipw)
293 {
294         pcmcia_disable_device(ipw->link);
295
296         if (ipw->common_memory) {
297                 release_mem_region(ipw->request_common_memory.Base,
298                                 ipw->request_common_memory.Size);
299                 iounmap(ipw->common_memory);
300         }
301         if (ipw->attr_memory) {
302                 release_mem_region(ipw->request_attr_memory.Base,
303                                 ipw->request_attr_memory.Size);
304                 iounmap(ipw->attr_memory);
305         }
306         if (ipw->common_memory)
307                 pcmcia_release_window(ipw->handle_common_memory);
308         if (ipw->attr_memory)
309                 pcmcia_release_window(ipw->handle_attr_memory);
310
311         /* Break the link with Card Services */
312         pcmcia_disable_device(ipw->link);
313 }
314
315 /*
316  * ipwireless_attach() creates an "instance" of the driver, allocating
317  * local data structures for one device (one interface).  The device
318  * is registered with Card Services.
319  *
320  * The pcmcia_device structure is initialized, but we don't actually
321  * configure the card at this point -- we wait until we receive a
322  * card insertion event.
323  */
324 static int ipwireless_attach(struct pcmcia_device *link)
325 {
326         struct ipw_dev *ipw;
327         int ret;
328
329         ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL);
330         if (!ipw)
331                 return -ENOMEM;
332
333         ipw->link = link;
334         link->priv = ipw;
335         link->irq.Instance = ipw;
336
337         /* Link this device into our device list. */
338         link->dev_node = &ipw->nodes[0];
339
340         ipw->hardware = ipwireless_hardware_create();
341         if (!ipw->hardware) {
342                 kfree(ipw);
343                 return -ENOMEM;
344         }
345         /* RegisterClient will call config_ipwireless */
346
347         ret = config_ipwireless(ipw);
348
349         if (ret != 0) {
350                 cs_error(link, RegisterClient, ret);
351                 ipwireless_detach(link);
352                 return ret;
353         }
354
355         return 0;
356 }
357
358 /*
359  * This deletes a driver "instance".  The device is de-registered with
360  * Card Services.  If it has been released, all local data structures
361  * are freed.  Otherwise, the structures will be freed when the device
362  * is released.
363  */
364 static void ipwireless_detach(struct pcmcia_device *link)
365 {
366         struct ipw_dev *ipw = link->priv;
367
368         release_ipwireless(ipw);
369
370         if (ipw->tty != NULL)
371                 ipwireless_tty_free(ipw->tty);
372         if (ipw->network != NULL)
373                 ipwireless_network_free(ipw->network);
374         if (ipw->hardware != NULL)
375                 ipwireless_hardware_free(ipw->hardware);
376         kfree(ipw);
377 }
378
379 static struct pcmcia_driver me = {
380         .owner          = THIS_MODULE,
381         .probe          = ipwireless_attach,
382         .remove         = ipwireless_detach,
383         .drv = { .name  = IPWIRELESS_PCCARD_NAME },
384         .id_table       = ipw_ids
385 };
386
387 /*
388  * Module insertion : initialisation of the module.
389  * Register the card with cardmgr...
390  */
391 static int __init init_ipwireless(void)
392 {
393         int ret;
394
395         printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
396                IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n");
397
398         ret = ipwireless_tty_init();
399         if (ret != 0)
400                 return ret;
401
402         ret = pcmcia_register_driver(&me);
403         if (ret != 0)
404                 ipwireless_tty_release();
405
406         return ret;
407 }
408
409 /*
410  * Module removal
411  */
412 static void __exit exit_ipwireless(void)
413 {
414         printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
415                         IPWIRELESS_PCMCIA_VERSION " removed\n");
416
417         pcmcia_unregister_driver(&me);
418         ipwireless_tty_release();
419 }
420
421 module_init(init_ipwireless);
422 module_exit(exit_ipwireless);
423
424 MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR);
425 MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION);
426 MODULE_LICENSE("GPL");