[PATCH] pcmcia: rename pcmcia_device.state
[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>
22#include <linux/sched.h>
23#include <linux/ptrace.h>
24#include <linux/slab.h>
25#include <linux/string.h>
26#include <linux/timer.h>
27#include <linux/ioport.h>
28#include <asm/io.h>
29#include <asm/system.h>
30
1da177e4
LT
31#include <pcmcia/cs_types.h>
32#include <pcmcia/cs.h>
33#include <pcmcia/cistpl.h>
34#include <pcmcia/cisreg.h>
35#include <pcmcia/ds.h>
36#include "hisax_cfg.h"
37
38MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
39MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
40MODULE_LICENSE("GPL");
41
42/*
43 All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
44 you do not define PCMCIA_DEBUG at all, all the debug code will be
45 left out. If you compile with PCMCIA_DEBUG=0, the debug code will
46 be present but disabled -- but it can then be enabled for specific
47 modules at load time with a 'pc_debug=#' option to insmod.
48*/
49
50#ifdef PCMCIA_DEBUG
51static int pc_debug = PCMCIA_DEBUG;
52module_param(pc_debug, int, 0);
53#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
54static char *version =
55"teles_cs.c 2.10 2002/07/30 22:23:34 kkeil";
56#else
57#define DEBUG(n, args...)
58#endif
59
60/*====================================================================*/
61
62/* Parameters that can be set with 'insmod' */
63
64static int protocol = 2; /* EURO-ISDN Default */
65module_param(protocol, int, 0);
66
67/*====================================================================*/
68
69/*
70 The event() function is this driver's Card Services event handler.
71 It will be called by Card Services when an appropriate card status
72 event is received. The config() and release() entry points are
73 used to configure or release a socket, in response to card insertion
74 and ejection events. They are invoked from the teles_cs event
75 handler.
76*/
77
78static void teles_cs_config(dev_link_t *link);
79static void teles_cs_release(dev_link_t *link);
1da177e4
LT
80
81/*
82 The attach() and detach() entry points are used to create and destroy
83 "instances" of the driver, where each instance represents everything
84 needed to manage one actual PCMCIA card.
85*/
86
cc3b4866 87static void teles_detach(struct pcmcia_device *p_dev);
1da177e4 88
1da177e4
LT
89/*
90 A linked list of "instances" of the teles_cs device. Each actual
91 PCMCIA card corresponds to one device instance, and is described
92 by one dev_link_t structure (defined in ds.h).
93
94 You may not want to use a linked list for this -- for example, the
95 memory card driver uses an array of dev_link_t pointers, where minor
96 device numbers are used to derive the corresponding array index.
97*/
98
1da177e4 99/*
1da177e4
LT
100 A driver needs to provide a dev_node_t structure for each device
101 on a card. In some cases, there is only one device per card (for
102 example, ethernet cards, modems). In other cases, there may be
103 many actual or logical devices (SCSI adapters, memory cards with
104 multiple partitions). The dev_node_t structures need to be kept
105 in a linked list starting at the 'dev' field of a dev_link_t
106 structure. We allocate them in the card's private data structure,
107 because they generally shouldn't be allocated dynamically.
108 In this case, we also provide a flag to indicate if a device is
109 "stopped" due to a power management event, or card ejection. The
110 device IO routines can use a flag like this to throttle IO to a
111 card that is not ready to accept it.
112*/
113
114typedef struct local_info_t {
115 dev_link_t link;
116 dev_node_t node;
117 int busy;
118 int cardnr;
119} local_info_t;
120
121/*======================================================================
122
123 teles_attach() creates an "instance" of the driver, allocatingx
124 local data structures for one device. The device is registered
125 with Card Services.
126
127 The dev_link structure is initialized, but we don't actually
128 configure the card at this point -- we wait until we receive a
129 card insertion event.
130
131======================================================================*/
132
f8cfa618 133static int teles_attach(struct pcmcia_device *p_dev)
1da177e4 134{
1da177e4
LT
135 dev_link_t *link;
136 local_info_t *local;
1da177e4
LT
137
138 DEBUG(0, "teles_attach()\n");
139
140 /* Allocate space for private device-specific data */
141 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
f8cfa618 142 if (!local) return -ENOMEM;
1da177e4
LT
143 memset(local, 0, sizeof(local_info_t));
144 local->cardnr = -1;
145 link = &local->link; link->priv = local;
146
147 /* Interrupt setup */
148 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
149 link->irq.IRQInfo1 = IRQ_LEVEL_ID|IRQ_SHARE_ID;
150 link->irq.Handler = NULL;
151
152 /*
153 General socket configuration defaults can go here. In this
154 client, we assume very little, and rely on the CIS for almost
155 everything. In most clients, many details (i.e., number, sizes,
156 and attributes of IO windows) are fixed by the nature of the
157 device, and can be hard-wired here.
158 */
159 link->io.NumPorts1 = 96;
160 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
161 link->io.IOAddrLines = 5;
162
163 link->conf.Attributes = CONF_ENABLE_IRQ;
1da177e4
LT
164 link->conf.IntType = INT_MEMORY_AND_IO;
165
f8cfa618
DB
166 link->handle = p_dev;
167 p_dev->instance = link;
1da177e4 168
f8cfa618
DB
169 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
170 teles_cs_config(link);
171
172 return 0;
1da177e4
LT
173} /* teles_attach */
174
175/*======================================================================
176
177 This deletes a driver "instance". The device is de-registered
178 with Card Services. If it has been released, all local data
179 structures are freed. Otherwise, the structures will be freed
180 when the device is released.
181
182======================================================================*/
183
cc3b4866 184static void teles_detach(struct pcmcia_device *p_dev)
1da177e4 185{
cc3b4866 186 dev_link_t *link = dev_to_instance(p_dev);
1da177e4 187 local_info_t *info = link->priv;
1da177e4
LT
188
189 DEBUG(0, "teles_detach(0x%p)\n", link);
190
cc3b4866 191 if (link->state & DEV_CONFIG) {
b4635811
DB
192 info->busy = 1;
193 teles_cs_release(link);
1da177e4
LT
194 }
195
1da177e4
LT
196 kfree(info);
197
198} /* teles_detach */
199
200/*======================================================================
201
202 teles_cs_config() is scheduled to run after a CARD_INSERTION event
203 is received, to configure the PCMCIA socket, and to make the
204 device available to the system.
205
206======================================================================*/
207static int get_tuple(client_handle_t handle, tuple_t *tuple,
208 cisparse_t *parse)
209{
210 int i = pcmcia_get_tuple_data(handle, tuple);
211 if (i != CS_SUCCESS) return i;
212 return pcmcia_parse_tuple(handle, tuple, parse);
213}
214
215static int first_tuple(client_handle_t handle, tuple_t *tuple,
216 cisparse_t *parse)
217{
218 int i = pcmcia_get_first_tuple(handle, tuple);
219 if (i != CS_SUCCESS) return i;
220 return get_tuple(handle, tuple, parse);
221}
222
223static int next_tuple(client_handle_t handle, tuple_t *tuple,
224 cisparse_t *parse)
225{
226 int i = pcmcia_get_next_tuple(handle, tuple);
227 if (i != CS_SUCCESS) return i;
228 return get_tuple(handle, tuple, parse);
229}
230
231static void teles_cs_config(dev_link_t *link)
232{
233 client_handle_t handle;
234 tuple_t tuple;
235 cisparse_t parse;
236 local_info_t *dev;
237 int i, j, last_fn;
238 u_short buf[128];
239 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
240 IsdnCard_t icard;
241
242 DEBUG(0, "teles_config(0x%p)\n", link);
243 handle = link->handle;
244 dev = link->priv;
245
246 /*
247 This reads the card's CONFIG tuple to find its configuration
248 registers.
249 */
250 tuple.DesiredTuple = CISTPL_CONFIG;
251 tuple.TupleData = (cisdata_t *)buf;
252 tuple.TupleDataMax = 255;
253 tuple.TupleOffset = 0;
254 tuple.Attributes = 0;
255 i = first_tuple(handle, &tuple, &parse);
256 if (i != CS_SUCCESS) {
257 last_fn = ParseTuple;
258 goto cs_failed;
259 }
260 link->conf.ConfigBase = parse.config.base;
261 link->conf.Present = parse.config.rmask[0];
262
263 /* Configure card */
264 link->state |= DEV_CONFIG;
265
266 tuple.TupleData = (cisdata_t *)buf;
267 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
268 tuple.Attributes = 0;
269 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
270 i = first_tuple(handle, &tuple, &parse);
271 while (i == CS_SUCCESS) {
272 if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
273 printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
274 link->conf.ConfigIndex = cf->index;
275 link->io.BasePort1 = cf->io.win[0].base;
276 i = pcmcia_request_io(link->handle, &link->io);
277 if (i == CS_SUCCESS) break;
278 } else {
279 printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
280 link->conf.ConfigIndex = cf->index;
281 for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
282 link->io.BasePort1 = j;
283 i = pcmcia_request_io(link->handle, &link->io);
284 if (i == CS_SUCCESS) break;
285 }
286 break;
287 }
288 i = next_tuple(handle, &tuple, &parse);
289 }
290
291 if (i != CS_SUCCESS) {
292 last_fn = RequestIO;
293 goto cs_failed;
294 }
295
296 i = pcmcia_request_irq(link->handle, &link->irq);
297 if (i != CS_SUCCESS) {
298 link->irq.AssignedIRQ = 0;
299 last_fn = RequestIRQ;
300 goto cs_failed;
301 }
302
303 i = pcmcia_request_configuration(link->handle, &link->conf);
304 if (i != CS_SUCCESS) {
305 last_fn = RequestConfiguration;
306 goto cs_failed;
307 }
308
309 /* At this point, the dev_node_t structure(s) should be
310 initialized and arranged in a linked list at link->dev. *//* */
311 sprintf(dev->node.dev_name, "teles");
312 dev->node.major = dev->node.minor = 0x0;
313
314 link->dev = &dev->node;
315
316 /* Finally, report what we've done */
70294b46
DB
317 printk(KERN_INFO "%s: index 0x%02x:",
318 dev->node.dev_name, link->conf.ConfigIndex);
1da177e4
LT
319 if (link->conf.Attributes & CONF_ENABLE_IRQ)
320 printk(", irq %d", link->irq.AssignedIRQ);
321 if (link->io.NumPorts1)
322 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
323 link->io.BasePort1+link->io.NumPorts1-1);
324 if (link->io.NumPorts2)
325 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
326 link->io.BasePort2+link->io.NumPorts2-1);
327 printk("\n");
328
329 link->state &= ~DEV_CONFIG_PENDING;
330
331 icard.para[0] = link->irq.AssignedIRQ;
332 icard.para[1] = link->io.BasePort1;
333 icard.protocol = protocol;
334 icard.typ = ISDN_CTYPE_TELESPCMCIA;
335
336 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
337 if (i < 0) {
338 printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
339 i, link->io.BasePort1);
340 teles_cs_release(link);
341 } else
342 ((local_info_t*)link->priv)->cardnr = i;
343
344 return;
345cs_failed:
346 cs_error(link->handle, last_fn, i);
347 teles_cs_release(link);
348} /* teles_cs_config */
349
350/*======================================================================
351
352 After a card is removed, teles_cs_release() will unregister the net
353 device, and release the PCMCIA configuration. If the device is
354 still open, this will be postponed until it is closed.
355
356======================================================================*/
357
358static void teles_cs_release(dev_link_t *link)
359{
360 local_info_t *local = link->priv;
361
362 DEBUG(0, "teles_cs_release(0x%p)\n", link);
363
364 if (local) {
365 if (local->cardnr >= 0) {
366 /* no unregister function with hisax */
367 HiSax_closecard(local->cardnr);
368 }
369 }
5f2a71fc
DB
370
371 pcmcia_disable_device(link->handle);
1da177e4
LT
372} /* teles_cs_release */
373
98e4c28b
DB
374static int teles_suspend(struct pcmcia_device *p_dev)
375{
376 dev_link_t *link = dev_to_instance(p_dev);
377 local_info_t *dev = link->priv;
378
98e4c28b 379 dev->busy = 1;
98e4c28b
DB
380
381 return 0;
382}
383
384static int teles_resume(struct pcmcia_device *p_dev)
385{
386 dev_link_t *link = dev_to_instance(p_dev);
387 local_info_t *dev = link->priv;
388
98e4c28b
DB
389 dev->busy = 0;
390
391 return 0;
392}
393
1da177e4 394
0a10d73d
DB
395static struct pcmcia_device_id teles_ids[] = {
396 PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
397 PCMCIA_DEVICE_NULL,
398};
399MODULE_DEVICE_TABLE(pcmcia, teles_ids);
400
1da177e4
LT
401static struct pcmcia_driver teles_cs_driver = {
402 .owner = THIS_MODULE,
403 .drv = {
404 .name = "teles_cs",
405 },
f8cfa618 406 .probe = teles_attach,
cc3b4866 407 .remove = teles_detach,
0a10d73d 408 .id_table = teles_ids,
98e4c28b
DB
409 .suspend = teles_suspend,
410 .resume = teles_resume,
1da177e4
LT
411};
412
413static int __init init_teles_cs(void)
414{
415 return pcmcia_register_driver(&teles_cs_driver);
416}
417
418static void __exit exit_teles_cs(void)
419{
420 pcmcia_unregister_driver(&teles_cs_driver);
1da177e4
LT
421}
422
423module_init(init_teles_cs);
424module_exit(exit_teles_cs);
This page took 0.18756 seconds and 5 git commands to generate.