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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [ide/] [legacy/] [ide-cs.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*======================================================================
2
 
3
    A driver for PCMCIA IDE/ATA disk cards
4
 
5
    ide_cs.c 1.26 1999/11/16 02:10:49
6
 
7
    The contents of this file are subject to the Mozilla Public
8
    License Version 1.1 (the "License"); you may not use this file
9
    except in compliance with the License. You may obtain a copy of
10
    the License at http://www.mozilla.org/MPL/
11
 
12
    Software distributed under the License is distributed on an "AS
13
    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14
    implied. See the License for the specific language governing
15
    rights and limitations under the License.
16
 
17
    The initial developer of the original code is David A. Hinds
18
    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
19
    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
20
 
21
    Alternatively, the contents of this file may be used under the
22
    terms of the GNU General Public License version 2 (the "GPL"), in which
23
    case the provisions of the GPL are applicable instead of the
24
    above.  If you wish to allow the use of your version of this file
25
    only under the terms of the GPL and not to allow others to use
26
    your version of this file under the MPL, indicate your decision
27
    by deleting the provisions above and replace them with the notice
28
    and other provisions required by the GPL.  If you do not delete
29
    the provisions above, a recipient may use your version of this
30
    file under either the MPL or the GPL.
31
 
32
======================================================================*/
33
 
34
#include <linux/module.h>
35
#include <linux/kernel.h>
36
#include <linux/init.h>
37
#include <linux/sched.h>
38
#include <linux/ptrace.h>
39
#include <linux/slab.h>
40
#include <linux/string.h>
41
#include <linux/timer.h>
42
#include <linux/ioport.h>
43
#include <linux/hdreg.h>
44
#include <linux/major.h>
45
#include <linux/ide.h>
46
 
47
#include <asm/io.h>
48
#include <asm/system.h>
49
 
50
#include <pcmcia/version.h>
51
#include <pcmcia/cs_types.h>
52
#include <pcmcia/cs.h>
53
#include <pcmcia/cistpl.h>
54
#include <pcmcia/ds.h>
55
#include <pcmcia/cisreg.h>
56
 
57
#ifdef PCMCIA_DEBUG
58
static int pc_debug = PCMCIA_DEBUG;
59
MODULE_PARM(pc_debug, "i");
60
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
61
static char *version =
62
"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
63
#else
64
#define DEBUG(n, args...)
65
#endif
66
 
67
/*====================================================================*/
68
 
69
/* Parameters that can be set with 'insmod' */
70
 
71
/* Bit map of interrupts to choose from */
72
static u_int irq_mask = 0xdeb8;
73
static int irq_list[4] = { -1 };
74
 
75
MODULE_PARM(irq_mask, "i");
76
MODULE_PARM(irq_list, "1-4i");
77
 
78
MODULE_LICENSE("GPL");
79
 
80
 
81
/*====================================================================*/
82
 
83
static const char ide_major[] = {
84
    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
85
#ifdef IDE4_MAJOR
86
    IDE4_MAJOR, IDE5_MAJOR
87
#endif
88
};
89
 
90
typedef struct ide_info_t {
91
    dev_link_t  link;
92
    int         ndev;
93
    dev_node_t  node;
94
    int         hd;
95
    struct tq_struct rel_task;
96
} ide_info_t;
97
 
98
static void ide_config(dev_link_t *link);
99
static void ide_release(void *arg);
100
static int ide_event(event_t event, int priority,
101
                     event_callback_args_t *args);
102
 
103
static dev_info_t dev_info = "ide-cs";
104
 
105
static dev_link_t *ide_attach(void);
106
static void ide_detach(dev_link_t *);
107
 
108
static dev_link_t *dev_list = NULL;
109
 
110
/*====================================================================*/
111
 
112
static void cs_error(client_handle_t handle, int func, int ret)
113
{
114
    error_info_t err = { func, ret };
115
    CardServices(ReportError, handle, &err);
116
}
117
 
118
/*======================================================================
119
 
120
    ide_attach() creates an "instance" of the driver, allocating
121
    local data structures for one device.  The device is registered
122
    with Card Services.
123
 
124
======================================================================*/
125
 
126
static dev_link_t *ide_attach(void)
127
{
128
    ide_info_t *info;
129
    dev_link_t *link;
130
    client_reg_t client_reg;
131
    int i, ret;
132
 
133
    DEBUG(0, "ide_attach()\n");
134
 
135
    /* Create new ide device */
136
    info = kmalloc(sizeof(*info), GFP_KERNEL);
137
    if (!info) return NULL;
138
    memset(info, 0, sizeof(*info));
139
    link = &info->link; link->priv = info;
140
    INIT_TQUEUE(&info->rel_task, ide_release, link);
141
 
142
    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
143
    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
144
    link->io.IOAddrLines = 3;
145
    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
146
    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
147
    if (irq_list[0] == -1)
148
        link->irq.IRQInfo2 = irq_mask;
149
    else
150
        for (i = 0; i < 4; i++)
151
            link->irq.IRQInfo2 |= 1 << irq_list[i];
152
    link->conf.Attributes = CONF_ENABLE_IRQ;
153
    link->conf.Vcc = 50;
154
    link->conf.IntType = INT_MEMORY_AND_IO;
155
 
156
    /* Register with Card Services */
157
    link->next = dev_list;
158
    dev_list = link;
159
    client_reg.dev_info = &dev_info;
160
    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
161
    client_reg.EventMask =
162
        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
163
        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
164
        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
165
    client_reg.event_handler = &ide_event;
166
    client_reg.Version = 0x0210;
167
    client_reg.event_callback_args.client_data = link;
168
    ret = CardServices(RegisterClient, &link->handle, &client_reg);
169
    if (ret != CS_SUCCESS) {
170
        cs_error(link->handle, RegisterClient, ret);
171
        ide_detach(link);
172
        return NULL;
173
    }
174
 
175
    return link;
176
} /* ide_attach */
177
 
178
/*======================================================================
179
 
180
    This deletes a driver "instance".  The device is de-registered
181
    with Card Services.  If it has been released, all local data
182
    structures are freed.  Otherwise, the structures will be freed
183
    when the device is released.
184
 
185
======================================================================*/
186
 
187
static void ide_detach(dev_link_t *link)
188
{
189
    dev_link_t **linkp;
190
    ide_info_t *info = link->priv;
191
    int ret;
192
 
193
    DEBUG(0, "ide_detach(0x%p)\n", link);
194
 
195
    /* Locate device structure */
196
    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
197
        if (*linkp == link) break;
198
    if (*linkp == NULL)
199
        return;
200
 
201
    if (link->state & DEV_CONFIG) {
202
        schedule_task(&info->rel_task);
203
        flush_scheduled_tasks();
204
    }
205
 
206
    if (link->handle) {
207
        ret = CardServices(DeregisterClient, link->handle);
208
        if (ret != CS_SUCCESS)
209
            cs_error(link->handle, DeregisterClient, ret);
210
    }
211
 
212
    /* Unlink, free device structure */
213
    *linkp = link->next;
214
    kfree(info);
215
 
216
} /* ide_detach */
217
 
218
/*======================================================================
219
 
220
    ide_config() is scheduled to run after a CARD_INSERTION event
221
    is received, to configure the PCMCIA socket, and to make the
222
    ide device available to the system.
223
 
224
======================================================================*/
225
 
226
#define CS_CHECK(fn, args...) \
227
while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
228
 
229
#define CFG_CHECK(fn, args...) \
230
if (CardServices(fn, args) != 0) goto next_entry
231
 
232
int idecs_register (int arg1, int arg2, int irq)
233
{
234
        hw_regs_t hw;
235
        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
236
        hw.irq = irq;
237
        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
238
        return ide_register_hw(&hw, NULL);
239
}
240
 
241
void ide_config(dev_link_t *link)
242
{
243
    client_handle_t handle = link->handle;
244
    ide_info_t *info = link->priv;
245
    tuple_t tuple;
246
    u_short buf[128];
247
    cisparse_t parse;
248
    config_info_t conf;
249
    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
250
    cistpl_cftable_entry_t dflt = { 0 };
251
    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
252
 
253
    DEBUG(0, "ide_config(0x%p)\n", link);
254
 
255
    tuple.TupleData = (cisdata_t *)buf;
256
    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
257
    tuple.Attributes = 0;
258
    tuple.DesiredTuple = CISTPL_CONFIG;
259
    CS_CHECK(GetFirstTuple, handle, &tuple);
260
    CS_CHECK(GetTupleData, handle, &tuple);
261
    CS_CHECK(ParseTuple, handle, &tuple, &parse);
262
    link->conf.ConfigBase = parse.config.base;
263
    link->conf.Present = parse.config.rmask[0];
264
 
265
    /* Configure card */
266
    link->state |= DEV_CONFIG;
267
 
268
    /* Not sure if this is right... look up the current Vcc */
269
    CS_CHECK(GetConfigurationInfo, handle, &conf);
270
    link->conf.Vcc = conf.Vcc;
271
 
272
    pass = io_base = ctl_base = 0;
273
    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
274
    tuple.Attributes = 0;
275
    CS_CHECK(GetFirstTuple, handle, &tuple);
276
    while (1) {
277
        CFG_CHECK(GetTupleData, handle, &tuple);
278
        CFG_CHECK(ParseTuple, handle, &tuple, &parse);
279
 
280
        /* Check for matching Vcc, unless we're desperate */
281
        if (!pass) {
282
            if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
283
                if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
284
                    goto next_entry;
285
            } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
286
                if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
287
                    goto next_entry;
288
            }
289
        }
290
 
291
        if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
292
            link->conf.Vpp1 = link->conf.Vpp2 =
293
                cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
294
        else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
295
            link->conf.Vpp1 = link->conf.Vpp2 =
296
                dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
297
 
298
        if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
299
            cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
300
            link->conf.ConfigIndex = cfg->index;
301
            link->io.BasePort1 = io->win[0].base;
302
            link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
303
            if (!(io->flags & CISTPL_IO_16BIT))
304
                link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
305
            if (io->nwin == 2) {
306
                link->io.NumPorts1 = 8;
307
                link->io.BasePort2 = io->win[1].base;
308
                link->io.NumPorts2 = 1;
309
                CFG_CHECK(RequestIO, link->handle, &link->io);
310
                io_base = link->io.BasePort1;
311
                ctl_base = link->io.BasePort2;
312
            } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
313
                link->io.NumPorts1 = io->win[0].len;
314
                link->io.NumPorts2 = 0;
315
                CFG_CHECK(RequestIO, link->handle, &link->io);
316
                io_base = link->io.BasePort1;
317
                ctl_base = link->io.BasePort1+0x0e;
318
            } else goto next_entry;
319
            /* If we've got this far, we're done */
320
            break;
321
        }
322
 
323
    next_entry:
324
        if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
325
        if (pass) {
326
            CS_CHECK(GetNextTuple, handle, &tuple);
327
        } else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
328
            CS_CHECK(GetFirstTuple, handle, &tuple);
329
            memset(&dflt, 0, sizeof(dflt));
330
            pass++;
331
        }
332
    }
333
 
334
    CS_CHECK(RequestIRQ, handle, &link->irq);
335
    CS_CHECK(RequestConfiguration, handle, &link->conf);
336
 
337
    /* deal with brain dead IDE resource management */
338
    release_region(link->io.BasePort1, link->io.NumPorts1);
339
    if (link->io.NumPorts2)
340
        release_region(link->io.BasePort2, link->io.NumPorts2);
341
 
342
    /* retry registration in case device is still spinning up */
343
    for (i = 0; i < 10; i++) {
344
        if (ctl_base)
345
            outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
346
        hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
347
        if (hd >= 0) break;
348
        if (link->io.NumPorts1 == 0x20) {
349
            if (ctl_base)
350
                outb(0x02, ctl_base+0x10);
351
            hd = idecs_register(io_base+0x10, ctl_base+0x10,
352
                              link->irq.AssignedIRQ);
353
            if (hd >= 0) {
354
                io_base += 0x10; ctl_base += 0x10;
355
                break;
356
            }
357
        }
358
        __set_current_state(TASK_UNINTERRUPTIBLE);
359
        schedule_timeout(HZ/10);
360
    }
361
 
362
    if (hd < 0) {
363
        printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
364
               ", irq %u failed\n", io_base, ctl_base,
365
               link->irq.AssignedIRQ);
366
        goto failed;
367
    }
368
 
369
    MOD_INC_USE_COUNT;
370
    info->ndev = 1;
371
    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
372
    info->node.major = ide_major[hd];
373
    info->node.minor = 0;
374
    info->hd = hd;
375
    link->dev = &info->node;
376
    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
377
           info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
378
           link->conf.Vpp1/10, link->conf.Vpp1%10);
379
 
380
    link->state &= ~DEV_CONFIG_PENDING;
381
    return;
382
 
383
cs_failed:
384
    cs_error(link->handle, last_fn, last_ret);
385
failed:
386
    ide_release(link);
387
 
388
} /* ide_config */
389
 
390
/*======================================================================
391
 
392
    After a card is removed, ide_release() will unregister the net
393
    device, and release the PCMCIA configuration.  If the device is
394
    still open, this will be postponed until it is closed.
395
 
396
======================================================================*/
397
 
398
static void ide_release(void *arg)
399
{
400
    dev_link_t *link = arg;
401
    ide_info_t *info = link->priv;
402
 
403
    if (!(link->state & DEV_CONFIG))
404
        return;
405
 
406
    DEBUG(0, "ide_do_release(0x%p)\n", link);
407
 
408
    if (info->ndev) {
409
        /* FIXME: if this fails we need to queue the cleanup somehow
410
           -- need to investigate the required PCMCIA magic */
411
        ide_unregister(info->hd);
412
        MOD_DEC_USE_COUNT;
413
    }
414
 
415
    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
416
    if (link->io.NumPorts2)
417
        request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
418
 
419
    info->ndev = 0;
420
    link->dev = NULL;
421
 
422
    CardServices(ReleaseConfiguration, link->handle);
423
    CardServices(ReleaseIO, link->handle, &link->io);
424
    CardServices(ReleaseIRQ, link->handle, &link->irq);
425
 
426
    link->state &= ~DEV_CONFIG;
427
 
428
} /* ide_release */
429
 
430
/*======================================================================
431
 
432
    The card status event handler.  Mostly, this schedules other
433
    stuff to run after an event is received.  A CARD_REMOVAL event
434
    also sets some flags to discourage the ide drivers from
435
    talking to the ports.
436
 
437
======================================================================*/
438
 
439
int ide_event(event_t event, int priority,
440
              event_callback_args_t *args)
441
{
442
    dev_link_t *link = args->client_data;
443
    ide_info_t *info = link->priv;
444
 
445
    DEBUG(1, "ide_event(0x%06x)\n", event);
446
 
447
    switch (event) {
448
    case CS_EVENT_CARD_REMOVAL:
449
        link->state &= ~DEV_PRESENT;
450
        if (link->state & DEV_CONFIG)
451
            schedule_task(&info->rel_task);
452
        break;
453
    case CS_EVENT_CARD_INSERTION:
454
        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
455
        ide_config(link);
456
        break;
457
    case CS_EVENT_PM_SUSPEND:
458
        link->state |= DEV_SUSPEND;
459
        /* Fall through... */
460
    case CS_EVENT_RESET_PHYSICAL:
461
        if (link->state & DEV_CONFIG)
462
            CardServices(ReleaseConfiguration, link->handle);
463
        break;
464
    case CS_EVENT_PM_RESUME:
465
        link->state &= ~DEV_SUSPEND;
466
        /* Fall through... */
467
    case CS_EVENT_CARD_RESET:
468
        if (DEV_OK(link))
469
            CardServices(RequestConfiguration, link->handle, &link->conf);
470
        break;
471
    }
472
    return 0;
473
} /* ide_event */
474
 
475
/*====================================================================*/
476
 
477
static int __init init_ide_cs(void)
478
{
479
    servinfo_t serv;
480
    DEBUG(0, "%s\n", version);
481
    CardServices(GetCardServicesInfo, &serv);
482
    if (serv.Revision != CS_RELEASE_CODE) {
483
        printk(KERN_NOTICE "ide_cs: Card Services release "
484
               "does not match!\n");
485
        return -1;
486
    }
487
    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
488
    return 0;
489
}
490
 
491
static void __exit exit_ide_cs(void)
492
{
493
    DEBUG(0, "ide_cs: unloading\n");
494
    unregister_pccard_driver(&dev_info);
495
    while (dev_list != NULL)
496
        ide_detach(dev_list);
497
}
498
 
499
module_init(init_ide_cs);
500
module_exit(exit_ide_cs);

powered by: WebSVN 2.1.0

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