OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [isdn/] [avmb1/] [avm_cs.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* $Id: avm_cs.c,v 1.1.1.1 2004-04-15 02:04:11 phoenix Exp $
2
 *
3
 * A PCMCIA client driver for AVM B1/M1/M2
4
 *
5
 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6
 *
7
 * This software may be used and distributed according to the terms
8
 * of the GNU General Public License, incorporated herein by reference.
9
 *
10
 */
11
 
12
#include <linux/module.h>
13
#include <linux/kernel.h>
14
#include <linux/init.h>
15
#include <linux/sched.h>
16
#include <linux/ptrace.h>
17
#include <linux/slab.h>
18
#include <linux/string.h>
19
#include <linux/timer.h>
20
#include <linux/tty.h>
21
#include <linux/serial.h>
22
#include <linux/major.h>
23
#include <asm/io.h>
24
#include <asm/system.h>
25
 
26
#include <pcmcia/version.h>
27
#include <pcmcia/cs_types.h>
28
#include <pcmcia/cs.h>
29
#include <pcmcia/cistpl.h>
30
#include <pcmcia/ciscode.h>
31
#include <pcmcia/ds.h>
32
#include <pcmcia/cisreg.h>
33
 
34
#include <linux/skbuff.h>
35
#include <linux/capi.h>
36
#include <linux/b1lli.h>
37
#include <linux/b1pcmcia.h>
38
 
39
/*====================================================================*/
40
 
41
MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");
42
MODULE_AUTHOR("Carsten Paeth");
43
MODULE_LICENSE("GPL");
44
 
45
/*====================================================================*/
46
 
47
/* Parameters that can be set with 'insmod' */
48
 
49
/* This means pick from 15, 12, 11, 10, 9, 7, 5, 4, and 3 */
50
static int default_irq_list[10] = { 15, 12, 11, 10, 9, 7, 5, 4, 3, -1 };
51
static int irq_list[10] = { -1 };
52
 
53
MODULE_PARM(irq_list, "1-10i");
54
 
55
/*====================================================================*/
56
 
57
/*
58
   The event() function is this driver's Card Services event handler.
59
   It will be called by Card Services when an appropriate card status
60
   event is received.  The config() and release() entry points are
61
   used to configure or release a socket, in response to card insertion
62
   and ejection events.  They are invoked from the skeleton event
63
   handler.
64
*/
65
 
66
static void avmcs_config(dev_link_t *link);
67
static void avmcs_release(u_long arg);
68
static int avmcs_event(event_t event, int priority,
69
                          event_callback_args_t *args);
70
 
71
/*
72
   The attach() and detach() entry points are used to create and destroy
73
   "instances" of the driver, where each instance represents everything
74
   needed to manage one actual PCMCIA card.
75
*/
76
 
77
static dev_link_t *avmcs_attach(void);
78
static void avmcs_detach(dev_link_t *);
79
 
80
/*
81
   The dev_info variable is the "key" that is used to match up this
82
   device driver with appropriate cards, through the card configuration
83
   database.
84
*/
85
 
86
static dev_info_t dev_info = "avm_cs";
87
 
88
/*
89
   A linked list of "instances" of the skeleton device.  Each actual
90
   PCMCIA card corresponds to one device instance, and is described
91
   by one dev_link_t structure (defined in ds.h).
92
 
93
   You may not want to use a linked list for this -- for example, the
94
   memory card driver uses an array of dev_link_t pointers, where minor
95
   device numbers are used to derive the corresponding array index.
96
*/
97
 
98
static dev_link_t *dev_list = NULL;
99
 
100
/*
101
   A dev_link_t structure has fields for most things that are needed
102
   to keep track of a socket, but there will usually be some device
103
   specific information that also needs to be kept track of.  The
104
   'priv' pointer in a dev_link_t structure can be used to point to
105
   a device-specific private data structure, like this.
106
 
107
   A driver needs to provide a dev_node_t structure for each device
108
   on a card.  In some cases, there is only one device per card (for
109
   example, ethernet cards, modems).  In other cases, there may be
110
   many actual or logical devices (SCSI adapters, memory cards with
111
   multiple partitions).  The dev_node_t structures need to be kept
112
   in a linked list starting at the 'dev' field of a dev_link_t
113
   structure.  We allocate them in the card's private data structure,
114
   because they generally can't be allocated dynamically.
115
*/
116
 
117
typedef struct local_info_t {
118
    dev_node_t  node;
119
} local_info_t;
120
 
121
/*====================================================================*/
122
 
123
static void cs_error(client_handle_t handle, int func, int ret)
124
{
125
    error_info_t err = { func, ret };
126
    CardServices(ReportError, handle, &err);
127
}
128
 
129
/*======================================================================
130
 
131
    avmcs_attach() creates an "instance" of the driver, allocating
132
    local data structures for one device.  The device is registered
133
    with Card Services.
134
 
135
    The dev_link structure is initialized, but we don't actually
136
    configure the card at this point -- we wait until we receive a
137
    card insertion event.
138
 
139
======================================================================*/
140
 
141
static dev_link_t *avmcs_attach(void)
142
{
143
    client_reg_t client_reg;
144
    dev_link_t *link;
145
    local_info_t *local;
146
    int ret, i;
147
 
148
    /* Initialize the dev_link_t structure */
149
    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
150
    if (!link)
151
        return NULL;
152
    memset(link, 0, sizeof(struct dev_link_t));
153
    link->release.function = &avmcs_release;
154
    link->release.data = (u_long)link;
155
 
156
    /* The io structure describes IO port mapping */
157
    link->io.NumPorts1 = 16;
158
    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
159
    link->io.NumPorts2 = 0;
160
 
161
    /* Interrupt setup */
162
    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
163
    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
164
 
165
    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
166
    if (irq_list[0] != -1) {
167
            for (i = 0; i < 10 && irq_list[i] > 0; i++)
168
               link->irq.IRQInfo2 |= 1 << irq_list[i];
169
    } else {
170
            for (i = 0; i < 10 && default_irq_list[i] > 0; i++)
171
               link->irq.IRQInfo2 |= 1 << default_irq_list[i];
172
    }
173
 
174
    /* General socket configuration */
175
    link->conf.Attributes = CONF_ENABLE_IRQ;
176
    link->conf.Vcc = 50;
177
    link->conf.IntType = INT_MEMORY_AND_IO;
178
    link->conf.ConfigIndex = 1;
179
    link->conf.Present = PRESENT_OPTION;
180
 
181
    /* Allocate space for private device-specific data */
182
    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
183
    if (!local)
184
        return NULL;
185
    memset(local, 0, sizeof(local_info_t));
186
    link->priv = local;
187
 
188
    /* Register with Card Services */
189
    link->next = dev_list;
190
    dev_list = link;
191
    client_reg.dev_info = &dev_info;
192
    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
193
    client_reg.EventMask =
194
        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
195
        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
196
        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
197
    client_reg.event_handler = &avmcs_event;
198
    client_reg.Version = 0x0210;
199
    client_reg.event_callback_args.client_data = link;
200
    ret = CardServices(RegisterClient, &link->handle, &client_reg);
201
    if (ret != 0) {
202
        cs_error(link->handle, RegisterClient, ret);
203
        avmcs_detach(link);
204
        return NULL;
205
    }
206
 
207
    return link;
208
} /* avmcs_attach */
209
 
210
/*======================================================================
211
 
212
    This deletes a driver "instance".  The device is de-registered
213
    with Card Services.  If it has been released, all local data
214
    structures are freed.  Otherwise, the structures will be freed
215
    when the device is released.
216
 
217
======================================================================*/
218
 
219
static void avmcs_detach(dev_link_t *link)
220
{
221
    dev_link_t **linkp;
222
 
223
    /* Locate device structure */
224
    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
225
        if (*linkp == link) break;
226
    if (*linkp == NULL)
227
        return;
228
 
229
    /*
230
       If the device is currently configured and active, we won't
231
       actually delete it yet.  Instead, it is marked so that when
232
       the release() function is called, that will trigger a proper
233
       detach().
234
    */
235
    if (link->state & DEV_CONFIG) {
236
        link->state |= DEV_STALE_LINK;
237
        return;
238
    }
239
 
240
    /* Break the link with Card Services */
241
    if (link->handle)
242
        CardServices(DeregisterClient, link->handle);
243
 
244
    /* Unlink device structure, free pieces */
245
    *linkp = link->next;
246
    if (link->priv) {
247
        kfree(link->priv);
248
    }
249
    kfree(link);
250
 
251
} /* avmcs_detach */
252
 
253
/*======================================================================
254
 
255
    avmcs_config() is scheduled to run after a CARD_INSERTION event
256
    is received, to configure the PCMCIA socket, and to make the
257
    ethernet device available to the system.
258
 
259
======================================================================*/
260
 
261
static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
262
                     cisparse_t *parse)
263
{
264
    int i;
265
    i = CardServices(fn, handle, tuple);
266
    if (i != CS_SUCCESS) return i;
267
    i = CardServices(GetTupleData, handle, tuple);
268
    if (i != CS_SUCCESS) return i;
269
    return CardServices(ParseTuple, handle, tuple, parse);
270
}
271
 
272
#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
273
#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
274
 
275
static void avmcs_config(dev_link_t *link)
276
{
277
    client_handle_t handle;
278
    tuple_t tuple;
279
    cisparse_t parse;
280
    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
281
    local_info_t *dev;
282
    int i;
283
    u_char buf[64];
284
    char devname[128];
285
    int cardtype;
286
    int (*addcard)(unsigned int port, unsigned irq);
287
 
288
    handle = link->handle;
289
    dev = link->priv;
290
 
291
    /*
292
       This reads the card's CONFIG tuple to find its configuration
293
       registers.
294
    */
295
    do {
296
        tuple.DesiredTuple = CISTPL_CONFIG;
297
        i = CardServices(GetFirstTuple, handle, &tuple);
298
        if (i != CS_SUCCESS) break;
299
        tuple.TupleData = buf;
300
        tuple.TupleDataMax = 64;
301
        tuple.TupleOffset = 0;
302
        i = CardServices(GetTupleData, handle, &tuple);
303
        if (i != CS_SUCCESS) break;
304
        i = CardServices(ParseTuple, handle, &tuple, &parse);
305
        if (i != CS_SUCCESS) break;
306
        link->conf.ConfigBase = parse.config.base;
307
    } while (0);
308
    if (i != CS_SUCCESS) {
309
        cs_error(link->handle, ParseTuple, i);
310
        link->state &= ~DEV_CONFIG_PENDING;
311
        return;
312
    }
313
 
314
    /* Configure card */
315
    link->state |= DEV_CONFIG;
316
 
317
    do {
318
 
319
        tuple.Attributes = 0;
320
        tuple.TupleData = buf;
321
        tuple.TupleDataMax = 254;
322
        tuple.TupleOffset = 0;
323
        tuple.DesiredTuple = CISTPL_VERS_1;
324
 
325
        devname[0] = 0;
326
        if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
327
            strncpy(devname,parse.version_1.str + parse.version_1.ofs[1],
328
                        sizeof(devname));
329
        }
330
        /*
331
         * find IO port
332
         */
333
        tuple.TupleData = (cisdata_t *)buf;
334
        tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
335
        tuple.Attributes = 0;
336
        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
337
        i = first_tuple(handle, &tuple, &parse);
338
        while (i == CS_SUCCESS) {
339
            if (cf->io.nwin > 0) {
340
                link->conf.ConfigIndex = cf->index;
341
                link->io.BasePort1 = cf->io.win[0].base;
342
                link->io.NumPorts1 = cf->io.win[0].len;
343
                link->io.NumPorts2 = 0;
344
                printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
345
                        link->io.BasePort1,
346
                        link->io.BasePort1+link->io.NumPorts1-1);
347
                i = CardServices(RequestIO, link->handle, &link->io);
348
                if (i == CS_SUCCESS) goto found_port;
349
            }
350
            i = next_tuple(handle, &tuple, &parse);
351
        }
352
 
353
found_port:
354
        if (i != CS_SUCCESS) {
355
            cs_error(link->handle, RequestIO, i);
356
            break;
357
        }
358
 
359
        /*
360
         * allocate an interrupt line
361
         */
362
        i = CardServices(RequestIRQ, link->handle, &link->irq);
363
        if (i != CS_SUCCESS) {
364
            cs_error(link->handle, RequestIRQ, i);
365
            CardServices(ReleaseIO, link->handle, &link->io);
366
            break;
367
        }
368
 
369
        /*
370
         * configure the PCMCIA socket
371
          */
372
        i = CardServices(RequestConfiguration, link->handle, &link->conf);
373
        if (i != CS_SUCCESS) {
374
            cs_error(link->handle, RequestConfiguration, i);
375
            CardServices(ReleaseIO, link->handle, &link->io);
376
            CardServices(ReleaseIRQ, link->handle, &link->irq);
377
            break;
378
        }
379
 
380
    } while (0);
381
 
382
    /* At this point, the dev_node_t structure(s) should be
383
       initialized and arranged in a linked list at link->dev. */
384
 
385
    if (devname[0]) {
386
        char *s = strrchr(devname, ' ');
387
        if (!s)
388
           s = devname;
389
        else s++;
390
        strcpy(dev->node.dev_name, s);
391
        if (strcmp("M1", s) == 0) {
392
           cardtype = AVM_CARDTYPE_M1;
393
        } else if (strcmp("M2", s) == 0) {
394
           cardtype = AVM_CARDTYPE_M2;
395
        } else {
396
           cardtype = AVM_CARDTYPE_B1;
397
        }
398
    } else {
399
        strcpy(dev->node.dev_name, "b1");
400
        cardtype = AVM_CARDTYPE_B1;
401
    }
402
 
403
    dev->node.major = 64;
404
    dev->node.minor = 0;
405
    link->dev = &dev->node;
406
 
407
    link->state &= ~DEV_CONFIG_PENDING;
408
    /* If any step failed, release any partially configured state */
409
    if (i != 0) {
410
        avmcs_release((u_long)link);
411
        return;
412
    }
413
 
414
 
415
    switch (cardtype) {
416
        case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
417
        case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
418
        default:
419
        case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
420
    }
421
    if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) {
422
        printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
423
                dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
424
        avmcs_release((u_long)link);
425
        return;
426
    }
427
    dev->node.minor = i;
428
 
429
} /* avmcs_config */
430
 
431
/*======================================================================
432
 
433
    After a card is removed, avmcs_release() will unregister the net
434
    device, and release the PCMCIA configuration.  If the device is
435
    still open, this will be postponed until it is closed.
436
 
437
======================================================================*/
438
 
439
static void avmcs_release(u_long arg)
440
{
441
    dev_link_t *link = (dev_link_t *)arg;
442
 
443
    /*
444
       If the device is currently in use, we won't release until it
445
       is actually closed.
446
    */
447
    if (link->open) {
448
        link->state |= DEV_STALE_CONFIG;
449
        return;
450
    }
451
 
452
    b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
453
 
454
    /* Unlink the device chain */
455
    link->dev = NULL;
456
 
457
    /* Don't bother checking to see if these succeed or not */
458
    CardServices(ReleaseConfiguration, link->handle);
459
    CardServices(ReleaseIO, link->handle, &link->io);
460
    CardServices(ReleaseIRQ, link->handle, &link->irq);
461
    link->state &= ~DEV_CONFIG;
462
 
463
    if (link->state & DEV_STALE_LINK)
464
        avmcs_detach(link);
465
 
466
} /* avmcs_release */
467
 
468
/*======================================================================
469
 
470
    The card status event handler.  Mostly, this schedules other
471
    stuff to run after an event is received.  A CARD_REMOVAL event
472
    also sets some flags to discourage the net drivers from trying
473
    to talk to the card any more.
474
 
475
    When a CARD_REMOVAL event is received, we immediately set a flag
476
    to block future accesses to this device.  All the functions that
477
    actually access the device should check this flag to make sure
478
    the card is still present.
479
 
480
======================================================================*/
481
 
482
static int avmcs_event(event_t event, int priority,
483
                          event_callback_args_t *args)
484
{
485
    dev_link_t *link = args->client_data;
486
 
487
    switch (event) {
488
    case CS_EVENT_CARD_REMOVAL:
489
        link->state &= ~DEV_PRESENT;
490
        if (link->state & DEV_CONFIG) {
491
            link->release.expires = jiffies + (HZ/20);
492
            add_timer(&link->release);
493
        }
494
        break;
495
    case CS_EVENT_CARD_INSERTION:
496
        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
497
        avmcs_config(link);
498
        break;
499
    case CS_EVENT_PM_SUSPEND:
500
        link->state |= DEV_SUSPEND;
501
        /* Fall through... */
502
    case CS_EVENT_RESET_PHYSICAL:
503
        if (link->state & DEV_CONFIG)
504
            CardServices(ReleaseConfiguration, link->handle);
505
        break;
506
    case CS_EVENT_PM_RESUME:
507
        link->state &= ~DEV_SUSPEND;
508
        /* Fall through... */
509
    case CS_EVENT_CARD_RESET:
510
        if (link->state & DEV_CONFIG)
511
            CardServices(RequestConfiguration, link->handle, &link->conf);
512
        break;
513
    }
514
    return 0;
515
} /* avmcs_event */
516
 
517
/*====================================================================*/
518
 
519
static int __init avmcs_init(void)
520
{
521
    servinfo_t serv;
522
    CardServices(GetCardServicesInfo, &serv);
523
    if (serv.Revision != CS_RELEASE_CODE) {
524
        printk(KERN_NOTICE "avm_cs: Card Services release "
525
               "does not match!\n");
526
        return -1;
527
    }
528
    register_pccard_driver(&dev_info, &avmcs_attach, &avmcs_detach);
529
    return 0;
530
}
531
 
532
static void __exit avmcs_exit(void)
533
{
534
    unregister_pccard_driver(&dev_info);
535
    while (dev_list != NULL) {
536
        if (dev_list->state & DEV_CONFIG)
537
            avmcs_release((u_long)dev_list);
538
        avmcs_detach(dev_list);
539
    }
540
}
541
 
542
module_init(avmcs_init);
543
module_exit(avmcs_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.