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