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