linux/drivers/ide/legacy/ide-cs.c
<<
>>
Prefs
   1/*======================================================================
   2
   3    A driver for PCMCIA IDE/ATA disk cards
   4
   5    ide-cs.c 1.3 2002/10/26 05:45:31
   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
  23    which 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/ptrace.h>
  38#include <linux/slab.h>
  39#include <linux/string.h>
  40#include <linux/timer.h>
  41#include <linux/ioport.h>
  42#include <linux/ide.h>
  43#include <linux/hdreg.h>
  44#include <linux/major.h>
  45#include <linux/delay.h>
  46#include <asm/io.h>
  47#include <asm/system.h>
  48
  49#include <pcmcia/cs_types.h>
  50#include <pcmcia/cs.h>
  51#include <pcmcia/cistpl.h>
  52#include <pcmcia/ds.h>
  53#include <pcmcia/cisreg.h>
  54#include <pcmcia/ciscode.h>
  55
  56/*====================================================================*/
  57
  58/* Module parameters */
  59
  60MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
  61MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver");
  62MODULE_LICENSE("Dual MPL/GPL");
  63
  64#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
  65
  66#ifdef PCMCIA_DEBUG
  67INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
  68#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
  69static char *version =
  70"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)";
  71#else
  72#define DEBUG(n, args...)
  73#endif
  74
  75/*====================================================================*/
  76
  77static const char ide_major[] = {
  78    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
  79    IDE4_MAJOR, IDE5_MAJOR
  80};
  81
  82typedef struct ide_info_t {
  83        struct pcmcia_device    *p_dev;
  84    int         ndev;
  85    dev_node_t  node;
  86    int         hd;
  87} ide_info_t;
  88
  89static void ide_release(struct pcmcia_device *);
  90static int ide_config(struct pcmcia_device *);
  91
  92static void ide_detach(struct pcmcia_device *p_dev);
  93
  94
  95
  96
  97/*======================================================================
  98
  99    ide_attach() creates an "instance" of the driver, allocating
 100    local data structures for one device.  The device is registered
 101    with Card Services.
 102
 103======================================================================*/
 104
 105static int ide_probe(struct pcmcia_device *link)
 106{
 107    ide_info_t *info;
 108
 109    DEBUG(0, "ide_attach()\n");
 110
 111    /* Create new ide device */
 112    info = kzalloc(sizeof(*info), GFP_KERNEL);
 113    if (!info)
 114        return -ENOMEM;
 115
 116    info->p_dev = link;
 117    link->priv = info;
 118
 119    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
 120    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
 121    link->io.IOAddrLines = 3;
 122    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 123    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 124    link->conf.Attributes = CONF_ENABLE_IRQ;
 125    link->conf.IntType = INT_MEMORY_AND_IO;
 126
 127    return ide_config(link);
 128} /* ide_attach */
 129
 130/*======================================================================
 131
 132    This deletes a driver "instance".  The device is de-registered
 133    with Card Services.  If it has been released, all local data
 134    structures are freed.  Otherwise, the structures will be freed
 135    when the device is released.
 136
 137======================================================================*/
 138
 139static void ide_detach(struct pcmcia_device *link)
 140{
 141    DEBUG(0, "ide_detach(0x%p)\n", link);
 142
 143    ide_release(link);
 144
 145    kfree(link->priv);
 146} /* ide_detach */
 147
 148static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle)
 149{
 150    hw_regs_t hw;
 151    memset(&hw, 0, sizeof(hw));
 152    ide_init_hwif_ports(&hw, io, ctl, NULL);
 153    hw.irq = irq;
 154    hw.chipset = ide_pci;
 155    hw.dev = &handle->dev;
 156    return ide_register_hw(&hw, &ide_undecoded_slave, 0, NULL);
 157}
 158
 159/*======================================================================
 160
 161    ide_config() is scheduled to run after a CARD_INSERTION event
 162    is received, to configure the PCMCIA socket, and to make the
 163    ide device available to the system.
 164
 165======================================================================*/
 166
 167#define CS_CHECK(fn, ret) \
 168do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 169
 170static int ide_config(struct pcmcia_device *link)
 171{
 172    ide_info_t *info = link->priv;
 173    tuple_t tuple;
 174    struct {
 175        u_short         buf[128];
 176        cisparse_t      parse;
 177        config_info_t   conf;
 178        cistpl_cftable_entry_t dflt;
 179    } *stk = NULL;
 180    cistpl_cftable_entry_t *cfg;
 181    int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0;
 182    unsigned long io_base, ctl_base;
 183
 184    DEBUG(0, "ide_config(0x%p)\n", link);
 185
 186    stk = kzalloc(sizeof(*stk), GFP_KERNEL);
 187    if (!stk) goto err_mem;
 188    cfg = &stk->parse.cftable_entry;
 189
 190    tuple.TupleData = (cisdata_t *)&stk->buf;
 191    tuple.TupleOffset = 0;
 192    tuple.TupleDataMax = 255;
 193    tuple.Attributes = 0;
 194
 195    is_kme = ((link->manf_id == MANFID_KME) &&
 196              ((link->card_id == PRODID_KME_KXLC005_A) ||
 197               (link->card_id == PRODID_KME_KXLC005_B)));
 198
 199    /* Not sure if this is right... look up the current Vcc */
 200    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf));
 201
 202    pass = io_base = ctl_base = 0;
 203    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 204    tuple.Attributes = 0;
 205    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 206    while (1) {
 207        if (pcmcia_get_tuple_data(link, &tuple) != 0) goto next_entry;
 208        if (pcmcia_parse_tuple(link, &tuple, &stk->parse) != 0) goto next_entry;
 209
 210        /* Check for matching Vcc, unless we're desperate */
 211        if (!pass) {
 212            if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
 213                if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
 214                    goto next_entry;
 215            } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
 216                if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
 217                    goto next_entry;
 218            }
 219        }
 220
 221        if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
 222            link->conf.Vpp =
 223                cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
 224        else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
 225            link->conf.Vpp =
 226                stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 227
 228        if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
 229            cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
 230            link->conf.ConfigIndex = cfg->index;
 231            link->io.BasePort1 = io->win[0].base;
 232            link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
 233            if (!(io->flags & CISTPL_IO_16BIT))
 234                link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
 235            if (io->nwin == 2) {
 236                link->io.NumPorts1 = 8;
 237                link->io.BasePort2 = io->win[1].base;
 238                link->io.NumPorts2 = (is_kme) ? 2 : 1;
 239                if (pcmcia_request_io(link, &link->io) != 0)
 240                        goto next_entry;
 241                io_base = link->io.BasePort1;
 242                ctl_base = link->io.BasePort2;
 243            } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
 244                link->io.NumPorts1 = io->win[0].len;
 245                link->io.NumPorts2 = 0;
 246                if (pcmcia_request_io(link, &link->io) != 0)
 247                        goto next_entry;
 248                io_base = link->io.BasePort1;
 249                ctl_base = link->io.BasePort1 + 0x0e;
 250            } else goto next_entry;
 251            /* If we've got this far, we're done */
 252            break;
 253        }
 254
 255    next_entry:
 256        if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
 257            memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
 258        if (pass) {
 259            CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
 260        } else if (pcmcia_get_next_tuple(link, &tuple) != 0) {
 261            CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 262            memset(&stk->dflt, 0, sizeof(stk->dflt));
 263            pass++;
 264        }
 265    }
 266
 267    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 268    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 269
 270    /* disable drive interrupts during IDE probe */
 271    outb(0x02, ctl_base);
 272
 273    /* special setup for KXLC005 card */
 274    if (is_kme)
 275        outb(0x81, ctl_base+1);
 276
 277    /* retry registration in case device is still spinning up */
 278    for (hd = -1, i = 0; i < 10; i++) {
 279        hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link);
 280        if (hd >= 0) break;
 281        if (link->io.NumPorts1 == 0x20) {
 282            outb(0x02, ctl_base + 0x10);
 283            hd = idecs_register(io_base + 0x10, ctl_base + 0x10,
 284                                link->irq.AssignedIRQ, link);
 285            if (hd >= 0) {
 286                io_base += 0x10;
 287                ctl_base += 0x10;
 288                break;
 289            }
 290        }
 291        msleep(100);
 292    }
 293
 294    if (hd < 0) {
 295        printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx"
 296               ", irq %u failed\n", io_base, ctl_base,
 297               link->irq.AssignedIRQ);
 298        goto failed;
 299    }
 300
 301    info->ndev = 1;
 302    sprintf(info->node.dev_name, "hd%c", 'a' + (hd * 2));
 303    info->node.major = ide_major[hd];
 304    info->node.minor = 0;
 305    info->hd = hd;
 306    link->dev_node = &info->node;
 307    printk(KERN_INFO "ide-cs: %s: Vpp = %d.%d\n",
 308           info->node.dev_name, link->conf.Vpp / 10, link->conf.Vpp % 10);
 309
 310    kfree(stk);
 311    return 0;
 312
 313err_mem:
 314    printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n");
 315    goto failed;
 316
 317cs_failed:
 318    cs_error(link, last_fn, last_ret);
 319failed:
 320    kfree(stk);
 321    ide_release(link);
 322    return -ENODEV;
 323} /* ide_config */
 324
 325/*======================================================================
 326
 327    After a card is removed, ide_release() will unregister the net
 328    device, and release the PCMCIA configuration.  If the device is
 329    still open, this will be postponed until it is closed.
 330
 331======================================================================*/
 332
 333void ide_release(struct pcmcia_device *link)
 334{
 335    ide_info_t *info = link->priv;
 336
 337    DEBUG(0, "ide_release(0x%p)\n", link);
 338
 339    if (info->ndev) {
 340        /* FIXME: if this fails we need to queue the cleanup somehow
 341           -- need to investigate the required PCMCIA magic */
 342        ide_unregister(info->hd);
 343    }
 344    info->ndev = 0;
 345
 346    pcmcia_disable_device(link);
 347} /* ide_release */
 348
 349
 350/*======================================================================
 351
 352    The card status event handler.  Mostly, this schedules other
 353    stuff to run after an event is received.  A CARD_REMOVAL event
 354    also sets some flags to discourage the ide drivers from
 355    talking to the ports.
 356
 357======================================================================*/
 358
 359static struct pcmcia_device_id ide_ids[] = {
 360        PCMCIA_DEVICE_FUNC_ID(4),
 361        PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),        /* Corsair */
 362        PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000),        /* Hitachi */
 363        PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000),        /* I-O Data CFA */
 364        PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),        /* Mitsubishi CFA */
 365        PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
 366        PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),        /* SanDisk CFA */
 367        PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),        /* Toshiba */
 368        PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
 369        PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000),        /* Samsung */
 370        PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000),        /* Hitachi */
 371        PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
 372        PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100),        /* Viking CFA */
 373        PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200),        /* Lexar, Viking CFA */
 374        PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
 375        PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
 376        PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
 377        PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
 378        PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
 379        PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
 380        PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
 381        PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
 382        PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf),
 383        PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
 384        PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
 385        PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
 386        PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
 387        PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
 388        PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
 389        PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
 390        PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
 391        PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
 392        PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
 393        PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
 394        PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
 395        PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2      ", 0xe37be2b5, 0x8671043b),
 396        PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
 397        PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
 398        PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
 399        PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
 400        PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
 401        PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
 402        PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
 403        PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
 404        PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
 405        PCMCIA_DEVICE_PROD_ID1("TRANSCEND    512M   ", 0xd0909443),
 406        PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
 407        PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
 408        PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
 409        PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
 410        PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
 411        PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
 412        PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
 413        PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
 414        PCMCIA_DEVICE_NULL,
 415};
 416MODULE_DEVICE_TABLE(pcmcia, ide_ids);
 417
 418static struct pcmcia_driver ide_cs_driver = {
 419        .owner          = THIS_MODULE,
 420        .drv            = {
 421                .name   = "ide-cs",
 422        },
 423        .probe          = ide_probe,
 424        .remove         = ide_detach,
 425        .id_table       = ide_ids,
 426};
 427
 428static int __init init_ide_cs(void)
 429{
 430        return pcmcia_register_driver(&ide_cs_driver);
 431}
 432
 433static void __exit exit_ide_cs(void)
 434{
 435        pcmcia_unregister_driver(&ide_cs_driver);
 436}
 437
 438late_initcall(init_ide_cs);
 439module_exit(exit_ide_cs);
 440
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.