pcmcia: use autoconfiguration feature for ioports and iomem
[GitHub/mt8127/android_kernel_alcatel_ttab.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 */
00990e7c 108 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
1da177e4 109
15b99ac1 110 return teles_cs_config(link);
1da177e4
LT
111} /* teles_attach */
112
113/*======================================================================
114
115 This deletes a driver "instance". The device is de-registered
116 with Card Services. If it has been released, all local data
117 structures are freed. Otherwise, the structures will be freed
118 when the device is released.
119
120======================================================================*/
121
158e33d1 122static void __devexit teles_detach(struct pcmcia_device *link)
1da177e4 123{
e2d40963 124 local_info_t *info = link->priv;
1da177e4 125
e773cfe1 126 dev_dbg(&link->dev, "teles_detach(0x%p)\n", link);
1da177e4 127
e2d40963
DB
128 info->busy = 1;
129 teles_cs_release(link);
1da177e4 130
e2d40963 131 kfree(info);
1da177e4
LT
132} /* teles_detach */
133
134/*======================================================================
135
136 teles_cs_config() is scheduled to run after a CARD_INSERTION event
137 is received, to configure the PCMCIA socket, and to make the
138 device available to the system.
139
140======================================================================*/
1da177e4 141
00990e7c 142static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
1da177e4 143{
5fcd4da0
DB
144 int j;
145
90abdc3b 146 p_dev->io_lines = 5;
00990e7c
DB
147 p_dev->resource[0]->end = 96;
148 p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
149 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
90abdc3b 150
00990e7c 151 if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
5fcd4da0 152 printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
90abdc3b 153 if (!pcmcia_request_io(p_dev))
5fcd4da0
DB
154 return 0;
155 } else {
156 printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
5fcd4da0 157 for (j = 0x2f0; j > 0x100; j -= 0x10) {
90abdc3b
DB
158 p_dev->resource[0]->start = j;
159 if (!pcmcia_request_io(p_dev))
5fcd4da0
DB
160 return 0;
161 }
162 }
163 return -ENODEV;
1da177e4
LT
164}
165
158e33d1 166static int __devinit teles_cs_config(struct pcmcia_device *link)
1da177e4 167{
1da177e4 168 local_info_t *dev;
e773cfe1 169 int i;
1da177e4
LT
170 IsdnCard_t icard;
171
e773cfe1 172 dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
1da177e4
LT
173 dev = link->priv;
174
5fcd4da0 175 i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
e773cfe1 176 if (i != 0)
1da177e4 177 goto cs_failed;
1da177e4 178
eb14120f 179 if (!link->irq)
1da177e4 180 goto cs_failed;
1da177e4 181
1ac71e5a 182 i = pcmcia_enable_device(link);
e773cfe1 183 if (i != 0)
1da177e4 184 goto cs_failed;
1da177e4 185
1da177e4 186 /* Finally, report what we've done */
ded6a1a3 187 dev_info(&link->dev, "index 0x%02x:",
7feabb64 188 link->config_index);
1ac71e5a 189 printk(", irq %d", link->irq);
9a017a91
DB
190 if (link->resource[0])
191 printk(" & %pR", link->resource[0]);
192 if (link->resource[1])
193 printk(" & %pR", link->resource[1]);
1da177e4
LT
194 printk("\n");
195
eb14120f 196 icard.para[0] = link->irq;
9a017a91 197 icard.para[1] = link->resource[0]->start;
1da177e4
LT
198 icard.protocol = protocol;
199 icard.typ = ISDN_CTYPE_TELESPCMCIA;
200
201 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
202 if (i < 0) {
203 printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
9a017a91 204 i, (unsigned int) link->resource[0]->start);
1da177e4 205 teles_cs_release(link);
15b99ac1
DB
206 return -ENODEV;
207 }
208
209 ((local_info_t*)link->priv)->cardnr = i;
210 return 0;
1da177e4 211
1da177e4 212cs_failed:
1da177e4 213 teles_cs_release(link);
15b99ac1 214 return -ENODEV;
1da177e4
LT
215} /* teles_cs_config */
216
217/*======================================================================
218
219 After a card is removed, teles_cs_release() will unregister the net
220 device, and release the PCMCIA configuration. If the device is
221 still open, this will be postponed until it is closed.
222
223======================================================================*/
224
fba395ee 225static void teles_cs_release(struct pcmcia_device *link)
1da177e4
LT
226{
227 local_info_t *local = link->priv;
228
e773cfe1 229 dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link);
1da177e4
LT
230
231 if (local) {
232 if (local->cardnr >= 0) {
233 /* no unregister function with hisax */
234 HiSax_closecard(local->cardnr);
235 }
236 }
5f2a71fc 237
fba395ee 238 pcmcia_disable_device(link);
1da177e4
LT
239} /* teles_cs_release */
240
fba395ee 241static int teles_suspend(struct pcmcia_device *link)
98e4c28b 242{
98e4c28b
DB
243 local_info_t *dev = link->priv;
244
98e4c28b 245 dev->busy = 1;
98e4c28b
DB
246
247 return 0;
248}
249
fba395ee 250static int teles_resume(struct pcmcia_device *link)
98e4c28b 251{
98e4c28b
DB
252 local_info_t *dev = link->priv;
253
98e4c28b
DB
254 dev->busy = 0;
255
256 return 0;
257}
258
1da177e4 259
0a10d73d
DB
260static struct pcmcia_device_id teles_ids[] = {
261 PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
262 PCMCIA_DEVICE_NULL,
263};
264MODULE_DEVICE_TABLE(pcmcia, teles_ids);
265
1da177e4
LT
266static struct pcmcia_driver teles_cs_driver = {
267 .owner = THIS_MODULE,
268 .drv = {
269 .name = "teles_cs",
270 },
15b99ac1 271 .probe = teles_probe,
158e33d1 272 .remove = __devexit_p(teles_detach),
0a10d73d 273 .id_table = teles_ids,
98e4c28b
DB
274 .suspend = teles_suspend,
275 .resume = teles_resume,
1da177e4
LT
276};
277
278static int __init init_teles_cs(void)
279{
280 return pcmcia_register_driver(&teles_cs_driver);
281}
282
283static void __exit exit_teles_cs(void)
284{
285 pcmcia_unregister_driver(&teles_cs_driver);
1da177e4
LT
286}
287
288module_init(init_teles_cs);
289module_exit(exit_teles_cs);