pcmcia: convert pcmcia_request_configuration to pcmcia_enable_device
[linux-2.6.git] / drivers / isdn / hisax / teles_cs.c
1 /* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */
2 /*======================================================================
3
4     A teles S0 PCMCIA client driver
5
6     Based on skeleton by David Hinds, dhinds@allegro.stanford.edu
7     Written by Christof Petig, christof.petig@wtal.de
8     
9     Also inspired by ELSA PCMCIA driver 
10     by Klaus Lichtenwalder <Lichtenwalder@ACM.org>
11     
12     Extentions to new hisax_pcmcia by Karsten Keil
13
14     minor changes to be compatible with kernel 2.4.x
15     by Jan.Schubert@GMX.li
16
17 ======================================================================*/
18
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/init.h>
22 #include <linux/ptrace.h>
23 #include <linux/slab.h>
24 #include <linux/string.h>
25 #include <linux/timer.h>
26 #include <linux/ioport.h>
27 #include <asm/io.h>
28 #include <asm/system.h>
29
30 #include <pcmcia/cistpl.h>
31 #include <pcmcia/cisreg.h>
32 #include <pcmcia/ds.h>
33 #include "hisax_cfg.h"
34
35 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
36 MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
37 MODULE_LICENSE("GPL");
38
39
40 /*====================================================================*/
41
42 /* Parameters that can be set with 'insmod' */
43
44 static int protocol = 2;        /* EURO-ISDN Default */
45 module_param(protocol, int, 0);
46
47 /*====================================================================*/
48
49 /*
50    The event() function is this driver's Card Services event handler.
51    It will be called by Card Services when an appropriate card status
52    event is received.  The config() and release() entry points are
53    used to configure or release a socket, in response to card insertion
54    and ejection events.  They are invoked from the teles_cs event
55    handler.
56 */
57
58 static int teles_cs_config(struct pcmcia_device *link) __devinit ;
59 static void teles_cs_release(struct pcmcia_device *link);
60
61 /*
62    The attach() and detach() entry points are used to create and destroy
63    "instances" of the driver, where each instance represents everything
64    needed to manage one actual PCMCIA card.
65 */
66
67 static void teles_detach(struct pcmcia_device *p_dev) __devexit ;
68
69 typedef struct local_info_t {
70         struct pcmcia_device    *p_dev;
71     int                 busy;
72     int                 cardnr;
73 } local_info_t;
74
75 /*======================================================================
76
77     teles_attach() creates an "instance" of the driver, allocatingx
78     local data structures for one device.  The device is registered
79     with Card Services.
80
81     The dev_link structure is initialized, but we don't actually
82     configure the card at this point -- we wait until we receive a
83     card insertion event.
84
85 ======================================================================*/
86
87 static int __devinit teles_probe(struct pcmcia_device *link)
88 {
89     local_info_t *local;
90
91     dev_dbg(&link->dev, "teles_attach()\n");
92
93     /* Allocate space for private device-specific data */
94     local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
95     if (!local) return -ENOMEM;
96     local->cardnr = -1;
97
98     local->p_dev = link;
99     link->priv = local;
100
101     /*
102       General socket configuration defaults can go here.  In this
103       client, we assume very little, and rely on the CIS for almost
104       everything.  In most clients, many details (i.e., number, sizes,
105       and attributes of IO windows) are fixed by the nature of the
106       device, and can be hard-wired here.
107     */
108     link->resource[0]->end = 96;
109     link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
110
111     link->config_flags |= CONF_ENABLE_IRQ;
112
113     return teles_cs_config(link);
114 } /* teles_attach */
115
116 /*======================================================================
117
118     This deletes a driver "instance".  The device is de-registered
119     with Card Services.  If it has been released, all local data
120     structures are freed.  Otherwise, the structures will be freed
121     when the device is released.
122
123 ======================================================================*/
124
125 static void __devexit teles_detach(struct pcmcia_device *link)
126 {
127         local_info_t *info = link->priv;
128
129         dev_dbg(&link->dev, "teles_detach(0x%p)\n", link);
130
131         info->busy = 1;
132         teles_cs_release(link);
133
134         kfree(info);
135 } /* teles_detach */
136
137 /*======================================================================
138
139     teles_cs_config() is scheduled to run after a CARD_INSERTION event
140     is received, to configure the PCMCIA socket, and to make the
141     device available to the system.
142
143 ======================================================================*/
144
145 static int teles_cs_configcheck(struct pcmcia_device *p_dev,
146                                 cistpl_cftable_entry_t *cf,
147                                 cistpl_cftable_entry_t *dflt,
148                                 unsigned int vcc,
149                                 void *priv_data)
150 {
151         int j;
152
153         p_dev->io_lines = 5;
154
155         if ((cf->io.nwin > 0) && cf->io.win[0].base) {
156                 printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
157                 p_dev->resource[0]->start = cf->io.win[0].base;
158                 if (!pcmcia_request_io(p_dev))
159                         return 0;
160         } else {
161                 printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
162                 for (j = 0x2f0; j > 0x100; j -= 0x10) {
163                         p_dev->resource[0]->start = j;
164                         if (!pcmcia_request_io(p_dev))
165                                 return 0;
166                 }
167         }
168         return -ENODEV;
169 }
170
171 static int __devinit teles_cs_config(struct pcmcia_device *link)
172 {
173     local_info_t *dev;
174     int i;
175     IsdnCard_t icard;
176
177     dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
178     dev = link->priv;
179
180     i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
181     if (i != 0)
182         goto cs_failed;
183
184     if (!link->irq)
185         goto cs_failed;
186
187     i = pcmcia_enable_device(link);
188     if (i != 0)
189       goto cs_failed;
190
191     /* Finally, report what we've done */
192     dev_info(&link->dev, "index 0x%02x:",
193             link->config_index);
194     printk(", irq %d", link->irq);
195     if (link->resource[0])
196         printk(" & %pR", link->resource[0]);
197     if (link->resource[1])
198         printk(" & %pR", link->resource[1]);
199     printk("\n");
200
201     icard.para[0] = link->irq;
202     icard.para[1] = link->resource[0]->start;
203     icard.protocol = protocol;
204     icard.typ = ISDN_CTYPE_TELESPCMCIA;
205     
206     i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
207     if (i < 0) {
208         printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
209                         i, (unsigned int) link->resource[0]->start);
210         teles_cs_release(link);
211         return -ENODEV;
212     }
213
214     ((local_info_t*)link->priv)->cardnr = i;
215     return 0;
216
217 cs_failed:
218     teles_cs_release(link);
219     return -ENODEV;
220 } /* teles_cs_config */
221
222 /*======================================================================
223
224     After a card is removed, teles_cs_release() will unregister the net
225     device, and release the PCMCIA configuration.  If the device is
226     still open, this will be postponed until it is closed.
227
228 ======================================================================*/
229
230 static void teles_cs_release(struct pcmcia_device *link)
231 {
232     local_info_t *local = link->priv;
233
234     dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link);
235
236     if (local) {
237         if (local->cardnr >= 0) {
238             /* no unregister function with hisax */
239             HiSax_closecard(local->cardnr);
240         }
241     }
242
243     pcmcia_disable_device(link);
244 } /* teles_cs_release */
245
246 static int teles_suspend(struct pcmcia_device *link)
247 {
248         local_info_t *dev = link->priv;
249
250         dev->busy = 1;
251
252         return 0;
253 }
254
255 static int teles_resume(struct pcmcia_device *link)
256 {
257         local_info_t *dev = link->priv;
258
259         dev->busy = 0;
260
261         return 0;
262 }
263
264
265 static struct pcmcia_device_id teles_ids[] = {
266         PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
267         PCMCIA_DEVICE_NULL,
268 };
269 MODULE_DEVICE_TABLE(pcmcia, teles_ids);
270
271 static struct pcmcia_driver teles_cs_driver = {
272         .owner          = THIS_MODULE,
273         .drv            = {
274                 .name   = "teles_cs",
275         },
276         .probe          = teles_probe,
277         .remove         = __devexit_p(teles_detach),
278         .id_table       = teles_ids,
279         .suspend        = teles_suspend,
280         .resume         = teles_resume,
281 };
282
283 static int __init init_teles_cs(void)
284 {
285         return pcmcia_register_driver(&teles_cs_driver);
286 }
287
288 static void __exit exit_teles_cs(void)
289 {
290         pcmcia_unregister_driver(&teles_cs_driver);
291 }
292
293 module_init(init_teles_cs);
294 module_exit(exit_teles_cs);