pcmcia: introduce autoconfiguration feature
[deliverable/linux.git] / drivers / isdn / hisax / teles_cs.c
CommitLineData
1da177e4
LT
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>
1da177e4
LT
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
1da177e4
LT
30#include <pcmcia/cistpl.h>
31#include <pcmcia/cisreg.h>
32#include <pcmcia/ds.h>
33#include "hisax_cfg.h"
34
35MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
36MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
37MODULE_LICENSE("GPL");
38
1da177e4
LT
39
40/*====================================================================*/
41
42/* Parameters that can be set with 'insmod' */
43
44static int protocol = 2; /* EURO-ISDN Default */
45module_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
158e33d1 58static int teles_cs_config(struct pcmcia_device *link) __devinit ;
fba395ee 59static void teles_cs_release(struct pcmcia_device *link);
1da177e4
LT
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
158e33d1 67static void teles_detach(struct pcmcia_device *p_dev) __devexit ;
1da177e4 68
1da177e4 69typedef struct local_info_t {
fd238232 70 struct pcmcia_device *p_dev;
1da177e4
LT
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
158e33d1 87static int __devinit teles_probe(struct pcmcia_device *link)
1da177e4 88{
1da177e4 89 local_info_t *local;
1da177e4 90
e773cfe1 91 dev_dbg(&link->dev, "teles_attach()\n");
1da177e4
LT
92
93 /* Allocate space for private device-specific data */
41f96935 94 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
f8cfa618 95 if (!local) return -ENOMEM;
1da177e4 96 local->cardnr = -1;
fd238232 97
fba395ee 98 local->p_dev = link;
fd238232 99 link->priv = local;
1da177e4 100
1da177e4
LT
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 */
90abdc3b
DB
108 link->resource[0]->end = 96;
109 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
1da177e4 110
1ac71e5a 111 link->config_flags |= CONF_ENABLE_IRQ;
1da177e4 112
15b99ac1 113 return teles_cs_config(link);
1da177e4
LT
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
158e33d1 125static void __devexit teles_detach(struct pcmcia_device *link)
1da177e4 126{
e2d40963 127 local_info_t *info = link->priv;
1da177e4 128
e773cfe1 129 dev_dbg(&link->dev, "teles_detach(0x%p)\n", link);
1da177e4 130
e2d40963
DB
131 info->busy = 1;
132 teles_cs_release(link);
1da177e4 133
e2d40963 134 kfree(info);
1da177e4
LT
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======================================================================*/
1da177e4 144
5fcd4da0
DB
145static int teles_cs_configcheck(struct pcmcia_device *p_dev,
146 cistpl_cftable_entry_t *cf,
8e2fc39d 147 cistpl_cftable_entry_t *dflt,
5fcd4da0 148 void *priv_data)
1da177e4 149{
5fcd4da0
DB
150 int j;
151
90abdc3b
DB
152 p_dev->io_lines = 5;
153
5fcd4da0
DB
154 if ((cf->io.nwin > 0) && cf->io.win[0].base) {
155 printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
90abdc3b
DB
156 p_dev->resource[0]->start = cf->io.win[0].base;
157 if (!pcmcia_request_io(p_dev))
5fcd4da0
DB
158 return 0;
159 } else {
160 printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
5fcd4da0 161 for (j = 0x2f0; j > 0x100; j -= 0x10) {
90abdc3b
DB
162 p_dev->resource[0]->start = j;
163 if (!pcmcia_request_io(p_dev))
5fcd4da0
DB
164 return 0;
165 }
166 }
167 return -ENODEV;
1da177e4
LT
168}
169
158e33d1 170static int __devinit teles_cs_config(struct pcmcia_device *link)
1da177e4 171{
1da177e4 172 local_info_t *dev;
e773cfe1 173 int i;
1da177e4
LT
174 IsdnCard_t icard;
175
e773cfe1 176 dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
1da177e4
LT
177 dev = link->priv;
178
5fcd4da0 179 i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
e773cfe1 180 if (i != 0)
1da177e4 181 goto cs_failed;
1da177e4 182
eb14120f 183 if (!link->irq)
1da177e4 184 goto cs_failed;
1da177e4 185
1ac71e5a 186 i = pcmcia_enable_device(link);
e773cfe1 187 if (i != 0)
1da177e4 188 goto cs_failed;
1da177e4 189
1da177e4 190 /* Finally, report what we've done */
ded6a1a3 191 dev_info(&link->dev, "index 0x%02x:",
7feabb64 192 link->config_index);
1ac71e5a 193 printk(", irq %d", link->irq);
9a017a91
DB
194 if (link->resource[0])
195 printk(" & %pR", link->resource[0]);
196 if (link->resource[1])
197 printk(" & %pR", link->resource[1]);
1da177e4
LT
198 printk("\n");
199
eb14120f 200 icard.para[0] = link->irq;
9a017a91 201 icard.para[1] = link->resource[0]->start;
1da177e4
LT
202 icard.protocol = protocol;
203 icard.typ = ISDN_CTYPE_TELESPCMCIA;
204
205 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
206 if (i < 0) {
207 printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
9a017a91 208 i, (unsigned int) link->resource[0]->start);
1da177e4 209 teles_cs_release(link);
15b99ac1
DB
210 return -ENODEV;
211 }
212
213 ((local_info_t*)link->priv)->cardnr = i;
214 return 0;
1da177e4 215
1da177e4 216cs_failed:
1da177e4 217 teles_cs_release(link);
15b99ac1 218 return -ENODEV;
1da177e4
LT
219} /* teles_cs_config */
220
221/*======================================================================
222
223 After a card is removed, teles_cs_release() will unregister the net
224 device, and release the PCMCIA configuration. If the device is
225 still open, this will be postponed until it is closed.
226
227======================================================================*/
228
fba395ee 229static void teles_cs_release(struct pcmcia_device *link)
1da177e4
LT
230{
231 local_info_t *local = link->priv;
232
e773cfe1 233 dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link);
1da177e4
LT
234
235 if (local) {
236 if (local->cardnr >= 0) {
237 /* no unregister function with hisax */
238 HiSax_closecard(local->cardnr);
239 }
240 }
5f2a71fc 241
fba395ee 242 pcmcia_disable_device(link);
1da177e4
LT
243} /* teles_cs_release */
244
fba395ee 245static int teles_suspend(struct pcmcia_device *link)
98e4c28b 246{
98e4c28b
DB
247 local_info_t *dev = link->priv;
248
98e4c28b 249 dev->busy = 1;
98e4c28b
DB
250
251 return 0;
252}
253
fba395ee 254static int teles_resume(struct pcmcia_device *link)
98e4c28b 255{
98e4c28b
DB
256 local_info_t *dev = link->priv;
257
98e4c28b
DB
258 dev->busy = 0;
259
260 return 0;
261}
262
1da177e4 263
0a10d73d
DB
264static struct pcmcia_device_id teles_ids[] = {
265 PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
266 PCMCIA_DEVICE_NULL,
267};
268MODULE_DEVICE_TABLE(pcmcia, teles_ids);
269
1da177e4
LT
270static struct pcmcia_driver teles_cs_driver = {
271 .owner = THIS_MODULE,
272 .drv = {
273 .name = "teles_cs",
274 },
15b99ac1 275 .probe = teles_probe,
158e33d1 276 .remove = __devexit_p(teles_detach),
0a10d73d 277 .id_table = teles_ids,
98e4c28b
DB
278 .suspend = teles_suspend,
279 .resume = teles_resume,
1da177e4
LT
280};
281
282static int __init init_teles_cs(void)
283{
284 return pcmcia_register_driver(&teles_cs_driver);
285}
286
287static void __exit exit_teles_cs(void)
288{
289 pcmcia_unregister_driver(&teles_cs_driver);
1da177e4
LT
290}
291
292module_init(init_teles_cs);
293module_exit(exit_teles_cs);
This page took 0.563432 seconds and 5 git commands to generate.