pcmcia: do not use io_req_t after call to pcmcia_request_io()
[linux-2.6.git] / drivers / isdn / hisax / avma1_cs.c
1 /*
2  * PCMCIA client driver for AVM A1 / Fritz!PCMCIA
3  *
4  * Author       Carsten Paeth
5  * Copyright    1998-2001 by Carsten Paeth <calle@calle.in-berlin.de>
6  * 
7  * This software may be used and distributed according to the terms
8  * of the GNU General Public License, incorporated herein by reference.
9  *
10  */
11
12 #include <linux/module.h>
13
14
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/ptrace.h>
18 #include <linux/slab.h>
19 #include <linux/string.h>
20 #include <asm/io.h>
21 #include <asm/system.h>
22
23 #include <pcmcia/cs.h>
24 #include <pcmcia/cistpl.h>
25 #include <pcmcia/ds.h>
26 #include "hisax_cfg.h"
27
28 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
29 MODULE_AUTHOR("Carsten Paeth");
30 MODULE_LICENSE("GPL");
31
32
33 /*====================================================================*/
34
35 /* Parameters that can be set with 'insmod' */
36
37 static int isdnprot = 2;
38
39 module_param(isdnprot, int, 0);
40
41 /*====================================================================*/
42
43 /*
44    The event() function is this driver's Card Services event handler.
45    It will be called by Card Services when an appropriate card status
46    event is received.  The config() and release() entry points are
47    used to configure or release a socket, in response to card insertion
48    and ejection events.  They are invoked from the skeleton event
49    handler.
50 */
51
52 static int avma1cs_config(struct pcmcia_device *link) __devinit ;
53 static void avma1cs_release(struct pcmcia_device *link);
54
55 /*
56    The attach() and detach() entry points are used to create and destroy
57    "instances" of the driver, where each instance represents everything
58    needed to manage one actual PCMCIA card.
59 */
60
61 static void avma1cs_detach(struct pcmcia_device *p_dev) __devexit ;
62
63
64 /*======================================================================
65
66     avma1cs_attach() creates an "instance" of the driver, allocating
67     local data structures for one device.  The device is registered
68     with Card Services.
69
70     The dev_link structure is initialized, but we don't actually
71     configure the card at this point -- we wait until we receive a
72     card insertion event.
73     
74 ======================================================================*/
75
76 static int __devinit avma1cs_probe(struct pcmcia_device *p_dev)
77 {
78     dev_dbg(&p_dev->dev, "avma1cs_attach()\n");
79
80     /* The io structure describes IO port mapping */
81     p_dev->io.NumPorts1 = 16;
82     p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
83     p_dev->io.NumPorts2 = 16;
84     p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
85     p_dev->io.IOAddrLines = 5;
86
87     /* General socket configuration */
88     p_dev->conf.Attributes = CONF_ENABLE_IRQ;
89     p_dev->conf.IntType = INT_MEMORY_AND_IO;
90     p_dev->conf.ConfigIndex = 1;
91     p_dev->conf.Present = PRESENT_OPTION;
92
93     return avma1cs_config(p_dev);
94 } /* avma1cs_attach */
95
96 /*======================================================================
97
98     This deletes a driver "instance".  The device is de-registered
99     with Card Services.  If it has been released, all local data
100     structures are freed.  Otherwise, the structures will be freed
101     when the device is released.
102
103 ======================================================================*/
104
105 static void __devexit avma1cs_detach(struct pcmcia_device *link)
106 {
107         dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
108         avma1cs_release(link);
109         kfree(link->priv);
110 } /* avma1cs_detach */
111
112 /*======================================================================
113
114     avma1cs_config() is scheduled to run after a CARD_INSERTION event
115     is received, to configure the PCMCIA socket, and to make the
116     ethernet device available to the system.
117     
118 ======================================================================*/
119
120 static int avma1cs_configcheck(struct pcmcia_device *p_dev,
121                                cistpl_cftable_entry_t *cf,
122                                cistpl_cftable_entry_t *dflt,
123                                unsigned int vcc,
124                                void *priv_data)
125 {
126         if (cf->io.nwin <= 0)
127                 return -ENODEV;
128
129         p_dev->io.BasePort1 = cf->io.win[0].base;
130         p_dev->io.NumPorts1 = cf->io.win[0].len;
131         p_dev->io.NumPorts2 = 0;
132         printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
133                p_dev->io.BasePort1,
134                p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
135         return pcmcia_request_io(p_dev, &p_dev->io);
136 }
137
138
139 static int __devinit avma1cs_config(struct pcmcia_device *link)
140 {
141     int i = -1;
142     char devname[128];
143     IsdnCard_t  icard;
144     int busy = 0;
145
146     dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link);
147
148     devname[0] = 0;
149     if (link->prod_id[1])
150             strlcpy(devname, link->prod_id[1], sizeof(devname));
151
152     if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
153             return -ENODEV;
154
155     do {
156         /*
157          * allocate an interrupt line
158          */
159         if (!link->irq) {
160             /* undo */
161             pcmcia_disable_device(link);
162             break;
163         }
164
165         /*
166          * configure the PCMCIA socket
167          */
168         i = pcmcia_request_configuration(link, &link->conf);
169         if (i != 0) {
170             pcmcia_disable_device(link);
171             break;
172         }
173
174     } while (0);
175
176     /* If any step failed, release any partially configured state */
177     if (i != 0) {
178         avma1cs_release(link);
179         return -ENODEV;
180     }
181
182     printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
183                 (unsigned int) link->resource[0]->start, link->irq);
184
185     icard.para[0] = link->irq;
186     icard.para[1] = link->resource[0]->start;
187     icard.protocol = isdnprot;
188     icard.typ = ISDN_CTYPE_A1_PCMCIA;
189     
190     i = hisax_init_pcmcia(link, &busy, &icard);
191     if (i < 0) {
192         printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 "
193                         "PCMCIA %d at i/o %#x\n", i,
194                         (unsigned int) link->resource[0]->start);
195         avma1cs_release(link);
196         return -ENODEV;
197     }
198     link->priv = (void *) (unsigned long) i;
199
200     return 0;
201 } /* avma1cs_config */
202
203 /*======================================================================
204
205     After a card is removed, avma1cs_release() will unregister the net
206     device, and release the PCMCIA configuration.  If the device is
207     still open, this will be postponed until it is closed.
208     
209 ======================================================================*/
210
211 static void avma1cs_release(struct pcmcia_device *link)
212 {
213         unsigned long minor = (unsigned long) link->priv;
214
215         dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link);
216
217         /* now unregister function with hisax */
218         HiSax_closecard(minor);
219
220         pcmcia_disable_device(link);
221 } /* avma1cs_release */
222
223
224 static struct pcmcia_device_id avma1cs_ids[] = {
225         PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
226         PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
227         PCMCIA_DEVICE_NULL
228 };
229 MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
230
231 static struct pcmcia_driver avma1cs_driver = {
232         .owner          = THIS_MODULE,
233         .drv            = {
234                 .name   = "avma1_cs",
235         },
236         .probe          = avma1cs_probe,
237         .remove         = __devexit_p(avma1cs_detach),
238         .id_table       = avma1cs_ids,
239 };
240
241 /*====================================================================*/
242
243 static int __init init_avma1_cs(void)
244 {
245         return(pcmcia_register_driver(&avma1cs_driver));
246 }
247
248 static void __exit exit_avma1_cs(void)
249 {
250         pcmcia_unregister_driver(&avma1cs_driver);
251 }
252
253 module_init(init_avma1_cs);
254 module_exit(exit_avma1_cs);