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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [isdn/] [hisax/] [avma1_cs.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * PCMCIA client driver for AVM A1 / Fritz!PCMCIA
3
 *
4
 * Author       Carsten Paeth
5
 * Copyright    1998-2001 by Carsten Paeth <calle@calle.in-berlin.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
 
14
 
15
#include <linux/kernel.h>
16
#include <linux/init.h>
17
#include <linux/ptrace.h>
18
#include <linux/slab.h>
19
#include <linux/string.h>
20
#include <asm/io.h>
21
#include <asm/system.h>
22
 
23
#include <pcmcia/cs_types.h>
24
#include <pcmcia/cs.h>
25
#include <pcmcia/cistpl.h>
26
#include <pcmcia/ds.h>
27
#include "hisax_cfg.h"
28
 
29
MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
30
MODULE_AUTHOR("Carsten Paeth");
31
MODULE_LICENSE("GPL");
32
 
33
/*
34
   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
35
   you do not define PCMCIA_DEBUG at all, all the debug code will be
36
   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
37
   be present but disabled -- but it can then be enabled for specific
38
   modules at load time with a 'pc_debug=#' option to insmod.
39
*/
40
#ifdef PCMCIA_DEBUG
41
static int pc_debug = PCMCIA_DEBUG;
42
module_param(pc_debug, int, 0);
43
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
44
static char *version =
45
"avma1_cs.c 1.00 1998/01/23 10:00:00 (Carsten Paeth)";
46
#else
47
#define DEBUG(n, args...)
48
#endif
49
 
50
/*====================================================================*/
51
 
52
/* Parameters that can be set with 'insmod' */
53
 
54
static int isdnprot = 2;
55
 
56
module_param(isdnprot, int, 0);
57
 
58
/*====================================================================*/
59
 
60
/*
61
   The event() function is this driver's Card Services event handler.
62
   It will be called by Card Services when an appropriate card status
63
   event is received.  The config() and release() entry points are
64
   used to configure or release a socket, in response to card insertion
65
   and ejection events.  They are invoked from the skeleton event
66
   handler.
67
*/
68
 
69
static int avma1cs_config(struct pcmcia_device *link);
70
static void avma1cs_release(struct pcmcia_device *link);
71
 
72
/*
73
   The attach() and detach() entry points are used to create and destroy
74
   "instances" of the driver, where each instance represents everything
75
   needed to manage one actual PCMCIA card.
76
*/
77
 
78
static void avma1cs_detach(struct pcmcia_device *p_dev);
79
 
80
 
81
/*
82
   A linked list of "instances" of the skeleton device.  Each actual
83
   PCMCIA card corresponds to one device instance, and is described
84
   by one struct pcmcia_device structure (defined in ds.h).
85
 
86
   You may not want to use a linked list for this -- for example, the
87
   memory card driver uses an array of struct pcmcia_device pointers, where minor
88
   device numbers are used to derive the corresponding array index.
89
*/
90
 
91
/*
92
   A driver needs to provide a dev_node_t structure for each device
93
   on a card.  In some cases, there is only one device per card (for
94
   example, ethernet cards, modems).  In other cases, there may be
95
   many actual or logical devices (SCSI adapters, memory cards with
96
   multiple partitions).  The dev_node_t structures need to be kept
97
   in a linked list starting at the 'dev' field of a struct pcmcia_device
98
   structure.  We allocate them in the card's private data structure,
99
   because they generally can't be allocated dynamically.
100
*/
101
 
102
typedef struct local_info_t {
103
    dev_node_t  node;
104
} local_info_t;
105
 
106
/*======================================================================
107
 
108
    avma1cs_attach() creates an "instance" of the driver, allocating
109
    local data structures for one device.  The device is registered
110
    with Card Services.
111
 
112
    The dev_link structure is initialized, but we don't actually
113
    configure the card at this point -- we wait until we receive a
114
    card insertion event.
115
 
116
======================================================================*/
117
 
118
static int avma1cs_probe(struct pcmcia_device *p_dev)
119
{
120
    local_info_t *local;
121
 
122
    DEBUG(0, "avma1cs_attach()\n");
123
 
124
    /* Allocate space for private device-specific data */
125
    local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
126
    if (!local)
127
        return -ENOMEM;
128
 
129
    p_dev->priv = local;
130
 
131
    /* The io structure describes IO port mapping */
132
    p_dev->io.NumPorts1 = 16;
133
    p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
134
    p_dev->io.NumPorts2 = 16;
135
    p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
136
    p_dev->io.IOAddrLines = 5;
137
 
138
    /* Interrupt setup */
139
    p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
140
    p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
141
 
142
    p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
143
 
144
    /* General socket configuration */
145
    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
146
    p_dev->conf.IntType = INT_MEMORY_AND_IO;
147
    p_dev->conf.ConfigIndex = 1;
148
    p_dev->conf.Present = PRESENT_OPTION;
149
 
150
    return avma1cs_config(p_dev);
151
} /* avma1cs_attach */
152
 
153
/*======================================================================
154
 
155
    This deletes a driver "instance".  The device is de-registered
156
    with Card Services.  If it has been released, all local data
157
    structures are freed.  Otherwise, the structures will be freed
158
    when the device is released.
159
 
160
======================================================================*/
161
 
162
static void avma1cs_detach(struct pcmcia_device *link)
163
{
164
        DEBUG(0, "avma1cs_detach(0x%p)\n", link);
165
        avma1cs_release(link);
166
        kfree(link->priv);
167
} /* avma1cs_detach */
168
 
169
/*======================================================================
170
 
171
    avma1cs_config() is scheduled to run after a CARD_INSERTION event
172
    is received, to configure the PCMCIA socket, and to make the
173
    ethernet device available to the system.
174
 
175
======================================================================*/
176
 
177
static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
178
                     cisparse_t *parse)
179
{
180
    int i = pcmcia_get_tuple_data(handle, tuple);
181
    if (i != CS_SUCCESS) return i;
182
    return pcmcia_parse_tuple(handle, tuple, parse);
183
}
184
 
185
static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
186
                     cisparse_t *parse)
187
{
188
    int i = pcmcia_get_first_tuple(handle, tuple);
189
    if (i != CS_SUCCESS) return i;
190
    return get_tuple(handle, tuple, parse);
191
}
192
 
193
static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
194
                     cisparse_t *parse)
195
{
196
    int i = pcmcia_get_next_tuple(handle, tuple);
197
    if (i != CS_SUCCESS) return i;
198
    return get_tuple(handle, tuple, parse);
199
}
200
 
201
static int avma1cs_config(struct pcmcia_device *link)
202
{
203
    tuple_t tuple;
204
    cisparse_t parse;
205
    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
206
    local_info_t *dev;
207
    int i;
208
    u_char buf[64];
209
    char devname[128];
210
    IsdnCard_t  icard;
211
    int busy = 0;
212
 
213
    dev = link->priv;
214
 
215
    DEBUG(0, "avma1cs_config(0x%p)\n", link);
216
 
217
    do {
218
        devname[0] = 0;
219
        if (link->prod_id[1])
220
                strlcpy(devname, link->prod_id[1], sizeof(devname));
221
 
222
        /*
223
         * find IO port
224
         */
225
        tuple.TupleData = (cisdata_t *)buf;
226
        tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
227
        tuple.Attributes = 0;
228
        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
229
        i = first_tuple(link, &tuple, &parse);
230
        while (i == CS_SUCCESS) {
231
            if (cf->io.nwin > 0) {
232
                link->conf.ConfigIndex = cf->index;
233
                link->io.BasePort1 = cf->io.win[0].base;
234
                link->io.NumPorts1 = cf->io.win[0].len;
235
                link->io.NumPorts2 = 0;
236
                printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
237
                        link->io.BasePort1,
238
                        link->io.BasePort1+link->io.NumPorts1 - 1);
239
                i = pcmcia_request_io(link, &link->io);
240
                if (i == CS_SUCCESS) goto found_port;
241
            }
242
            i = next_tuple(link, &tuple, &parse);
243
        }
244
 
245
found_port:
246
        if (i != CS_SUCCESS) {
247
            cs_error(link, RequestIO, i);
248
            break;
249
        }
250
 
251
        /*
252
         * allocate an interrupt line
253
         */
254
        i = pcmcia_request_irq(link, &link->irq);
255
        if (i != CS_SUCCESS) {
256
            cs_error(link, RequestIRQ, i);
257
            /* undo */
258
            pcmcia_disable_device(link);
259
            break;
260
        }
261
 
262
        /*
263
         * configure the PCMCIA socket
264
         */
265
        i = pcmcia_request_configuration(link, &link->conf);
266
        if (i != CS_SUCCESS) {
267
            cs_error(link, RequestConfiguration, i);
268
            pcmcia_disable_device(link);
269
            break;
270
        }
271
 
272
    } while (0);
273
 
274
    /* At this point, the dev_node_t structure(s) should be
275
       initialized and arranged in a linked list at link->dev. */
276
 
277
    strcpy(dev->node.dev_name, "A1");
278
    dev->node.major = 45;
279
    dev->node.minor = 0;
280
    link->dev_node = &dev->node;
281
 
282
    /* If any step failed, release any partially configured state */
283
    if (i != 0) {
284
        avma1cs_release(link);
285
        return -ENODEV;
286
    }
287
 
288
    printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
289
                                link->io.BasePort1, link->irq.AssignedIRQ);
290
 
291
    icard.para[0] = link->irq.AssignedIRQ;
292
    icard.para[1] = link->io.BasePort1;
293
    icard.protocol = isdnprot;
294
    icard.typ = ISDN_CTYPE_A1_PCMCIA;
295
 
296
    i = hisax_init_pcmcia(link, &busy, &icard);
297
    if (i < 0) {
298
        printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
299
        avma1cs_release(link);
300
        return -ENODEV;
301
    }
302
    dev->node.minor = i;
303
 
304
    return 0;
305
} /* avma1cs_config */
306
 
307
/*======================================================================
308
 
309
    After a card is removed, avma1cs_release() will unregister the net
310
    device, and release the PCMCIA configuration.  If the device is
311
    still open, this will be postponed until it is closed.
312
 
313
======================================================================*/
314
 
315
static void avma1cs_release(struct pcmcia_device *link)
316
{
317
        local_info_t *local = link->priv;
318
 
319
        DEBUG(0, "avma1cs_release(0x%p)\n", link);
320
 
321
        /* now unregister function with hisax */
322
        HiSax_closecard(local->node.minor);
323
 
324
        pcmcia_disable_device(link);
325
} /* avma1cs_release */
326
 
327
 
328
static struct pcmcia_device_id avma1cs_ids[] = {
329
        PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
330
        PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
331
        PCMCIA_DEVICE_NULL
332
};
333
MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
334
 
335
static struct pcmcia_driver avma1cs_driver = {
336
        .owner          = THIS_MODULE,
337
        .drv            = {
338
                .name   = "avma1_cs",
339
        },
340
        .probe          = avma1cs_probe,
341
        .remove         = avma1cs_detach,
342
        .id_table       = avma1cs_ids,
343
};
344
 
345
/*====================================================================*/
346
 
347
static int __init init_avma1_cs(void)
348
{
349
        return(pcmcia_register_driver(&avma1cs_driver));
350
}
351
 
352
static void __exit exit_avma1_cs(void)
353
{
354
        pcmcia_unregister_driver(&avma1cs_driver);
355
}
356
 
357
module_init(init_avma1_cs);
358
module_exit(exit_avma1_cs);

powered by: WebSVN 2.1.0

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