linux/drivers/ide/ide-cs.c
<<
>>
Prefs
   1/*======================================================================
   2
   3    A driver for PCMCIA IDE/ATA disk cards
   4
   5    The contents of this file are subject to the Mozilla Public
   6    License Version 1.1 (the "License"); you may not use this file
   7    except in compliance with the License. You may obtain a copy of
   8    the License at http://www.mozilla.org/MPL/
   9
  10    Software distributed under the License is distributed on an "AS
  11    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  12    implied. See the License for the specific language governing
  13    rights and limitations under the License.
  14
  15    The initial developer of the original code is David A. Hinds
  16    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  17    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  18
  19    Alternatively, the contents of this file may be used under the
  20    terms of the GNU General Public License version 2 (the "GPL"), in
  21    which case the provisions of the GPL are applicable instead of the
  22    above.  If you wish to allow the use of your version of this file
  23    only under the terms of the GPL and not to allow others to use
  24    your version of this file under the MPL, indicate your decision
  25    by deleting the provisions above and replace them with the notice
  26    and other provisions required by the GPL.  If you do not delete
  27    the provisions above, a recipient may use your version of this
  28    file under either the MPL or the GPL.
  29
  30======================================================================*/
  31
  32#include <linux/module.h>
  33#include <linux/kernel.h>
  34#include <linux/init.h>
  35#include <linux/ptrace.h>
  36#include <linux/slab.h>
  37#include <linux/string.h>
  38#include <linux/timer.h>
  39#include <linux/ioport.h>
  40#include <linux/ide.h>
  41#include <linux/major.h>
  42#include <linux/delay.h>
  43#include <asm/io.h>
  44
  45#include <pcmcia/cistpl.h>
  46#include <pcmcia/ds.h>
  47#include <pcmcia/cisreg.h>
  48#include <pcmcia/ciscode.h>
  49
  50#define DRV_NAME "ide-cs"
  51
  52/*====================================================================*/
  53
  54/* Module parameters */
  55
  56MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
  57MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver");
  58MODULE_LICENSE("Dual MPL/GPL");
  59
  60/*====================================================================*/
  61
  62typedef struct ide_info_t {
  63        struct pcmcia_device    *p_dev;
  64        struct ide_host         *host;
  65        int                     ndev;
  66} ide_info_t;
  67
  68static void ide_release(struct pcmcia_device *);
  69static int ide_config(struct pcmcia_device *);
  70
  71static void ide_detach(struct pcmcia_device *p_dev);
  72
  73static int ide_probe(struct pcmcia_device *link)
  74{
  75    ide_info_t *info;
  76
  77    dev_dbg(&link->dev, "ide_attach()\n");
  78
  79    /* Create new ide device */
  80    info = kzalloc(sizeof(*info), GFP_KERNEL);
  81    if (!info)
  82        return -ENOMEM;
  83
  84    info->p_dev = link;
  85    link->priv = info;
  86
  87    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
  88            CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
  89
  90    return ide_config(link);
  91} /* ide_attach */
  92
  93static void ide_detach(struct pcmcia_device *link)
  94{
  95    ide_info_t *info = link->priv;
  96
  97    dev_dbg(&link->dev, "ide_detach(0x%p)\n", link);
  98
  99    ide_release(link);
 100
 101    kfree(info);
 102} /* ide_detach */
 103
 104static const struct ide_port_ops idecs_port_ops = {
 105        .quirkproc              = ide_undecoded_slave,
 106};
 107
 108static const struct ide_port_info idecs_port_info = {
 109        .port_ops               = &idecs_port_ops,
 110        .host_flags             = IDE_HFLAG_NO_DMA,
 111        .irq_flags              = IRQF_SHARED,
 112        .chipset                = ide_pci,
 113};
 114
 115static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
 116                                unsigned long irq, struct pcmcia_device *handle)
 117{
 118    struct ide_host *host;
 119    ide_hwif_t *hwif;
 120    int i, rc;
 121    struct ide_hw hw, *hws[] = { &hw };
 122
 123    if (!request_region(io, 8, DRV_NAME)) {
 124        printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
 125                        DRV_NAME, io, io + 7);
 126        return NULL;
 127    }
 128
 129    if (!request_region(ctl, 1, DRV_NAME)) {
 130        printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
 131                        DRV_NAME, ctl);
 132        release_region(io, 8);
 133        return NULL;
 134    }
 135
 136    memset(&hw, 0, sizeof(hw));
 137    ide_std_init_ports(&hw, io, ctl);
 138    hw.irq = irq;
 139    hw.dev = &handle->dev;
 140
 141    rc = ide_host_add(&idecs_port_info, hws, 1, &host);
 142    if (rc)
 143        goto out_release;
 144
 145    hwif = host->ports[0];
 146
 147    if (hwif->present)
 148        return host;
 149
 150    /* retry registration in case device is still spinning up */
 151    for (i = 0; i < 10; i++) {
 152        msleep(100);
 153        ide_port_scan(hwif);
 154        if (hwif->present)
 155            return host;
 156    }
 157
 158    return host;
 159
 160out_release:
 161    release_region(ctl, 1);
 162    release_region(io, 8);
 163    return NULL;
 164}
 165
 166static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
 167{
 168        int *is_kme = priv_data;
 169
 170        if ((pdev->resource[0]->flags & IO_DATA_PATH_WIDTH)
 171            != IO_DATA_PATH_WIDTH_8) {
 172                pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
 173                pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
 174        }
 175        pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
 176        pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
 177
 178        if (pdev->resource[1]->end) {
 179                pdev->resource[0]->end = 8;
 180                pdev->resource[1]->end = (*is_kme) ? 2 : 1;
 181        } else {
 182                if (pdev->resource[0]->end < 16)
 183                        return -ENODEV;
 184        }
 185
 186        return pcmcia_request_io(pdev);
 187}
 188
 189static int ide_config(struct pcmcia_device *link)
 190{
 191    ide_info_t *info = link->priv;
 192    int ret = 0, is_kme = 0;
 193    unsigned long io_base, ctl_base;
 194    struct ide_host *host;
 195
 196    dev_dbg(&link->dev, "ide_config(0x%p)\n", link);
 197
 198    is_kme = ((link->manf_id == MANFID_KME) &&
 199              ((link->card_id == PRODID_KME_KXLC005_A) ||
 200               (link->card_id == PRODID_KME_KXLC005_B)));
 201
 202    if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) {
 203            link->config_flags &= ~CONF_AUTO_CHECK_VCC;
 204            if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme))
 205                    goto failed; /* No suitable config found */
 206    }
 207    io_base = link->resource[0]->start;
 208    if (link->resource[1]->end)
 209            ctl_base = link->resource[1]->start;
 210    else
 211            ctl_base = link->resource[0]->start + 0x0e;
 212
 213    if (!link->irq)
 214            goto failed;
 215
 216    ret = pcmcia_enable_device(link);
 217    if (ret)
 218            goto failed;
 219
 220    /* disable drive interrupts during IDE probe */
 221    outb(0x02, ctl_base);
 222
 223    /* special setup for KXLC005 card */
 224    if (is_kme)
 225        outb(0x81, ctl_base+1);
 226
 227     host = idecs_register(io_base, ctl_base, link->irq, link);
 228     if (host == NULL && resource_size(link->resource[0]) == 0x20) {
 229            outb(0x02, ctl_base + 0x10);
 230            host = idecs_register(io_base + 0x10, ctl_base + 0x10,
 231                                  link->irq, link);
 232    }
 233
 234    if (host == NULL)
 235        goto failed;
 236
 237    info->ndev = 1;
 238    info->host = host;
 239    dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n",
 240            'a' + host->ports[0]->index * 2,
 241            link->vpp / 10, link->vpp % 10);
 242
 243    return 0;
 244
 245failed:
 246    ide_release(link);
 247    return -ENODEV;
 248} /* ide_config */
 249
 250static void ide_release(struct pcmcia_device *link)
 251{
 252    ide_info_t *info = link->priv;
 253    struct ide_host *host = info->host;
 254
 255    dev_dbg(&link->dev, "ide_release(0x%p)\n", link);
 256
 257    if (info->ndev) {
 258        ide_hwif_t *hwif = host->ports[0];
 259        unsigned long data_addr, ctl_addr;
 260
 261        data_addr = hwif->io_ports.data_addr;
 262        ctl_addr = hwif->io_ports.ctl_addr;
 263
 264        ide_host_remove(host);
 265        info->ndev = 0;
 266
 267        release_region(ctl_addr, 1);
 268        release_region(data_addr, 8);
 269    }
 270
 271    pcmcia_disable_device(link);
 272} /* ide_release */
 273
 274
 275static const struct pcmcia_device_id ide_ids[] = {
 276        PCMCIA_DEVICE_FUNC_ID(4),
 277        PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),        /* Corsair */
 278        PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000),        /* Hitachi */
 279        PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000),        /* I-O Data CFA */
 280        PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),        /* Mitsubishi CFA */
 281        PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
 282        PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
 283        PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),        /* SanDisk CFA */
 284        PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000),        /* Kingston */
 285        PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620),        /* TI emulated */
 286        PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),        /* Toshiba */
 287        PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
 288        PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000),        /* Samsung */
 289        PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000),        /* Hitachi */
 290        PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
 291        PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100),        /* Viking CFA */
 292        PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200),        /* Lexar, Viking CFA */
 293        PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
 294        PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
 295        PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
 296        PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
 297        PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
 298        PCMCIA_DEVICE_PROD_ID12("CNF   ", "CD-ROM", 0x46d7db81, 0x66536591),
 299        PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
 300        PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
 301        PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
 302        PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf),
 303        PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
 304        PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
 305        PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
 306        PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
 307        PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
 308        PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
 309        PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
 310        PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
 311        PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb),
 312        PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10),
 313        PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
 314        PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
 315        PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
 316        PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
 317        PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2      ", 0xe37be2b5, 0x8671043b),
 318        PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
 319        PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
 320        PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
 321        PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
 322        PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
 323        PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
 324        PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
 325        PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
 326        PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
 327        PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
 328        PCMCIA_DEVICE_PROD_ID1("TRANSCEND    512M   ", 0xd0909443),
 329        PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
 330        PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
 331        PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
 332        PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
 333        PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133),
 334        PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47),
 335        PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
 336        PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
 337        PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
 338        PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
 339        PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
 340        PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506),
 341        PCMCIA_DEVICE_NULL,
 342};
 343MODULE_DEVICE_TABLE(pcmcia, ide_ids);
 344
 345static struct pcmcia_driver ide_cs_driver = {
 346        .owner          = THIS_MODULE,
 347        .name           = "ide-cs",
 348        .probe          = ide_probe,
 349        .remove         = ide_detach,
 350        .id_table       = ide_ids,
 351};
 352
 353static int __init init_ide_cs(void)
 354{
 355        return pcmcia_register_driver(&ide_cs_driver);
 356}
 357
 358static void __exit exit_ide_cs(void)
 359{
 360        pcmcia_unregister_driver(&ide_cs_driver);
 361}
 362
 363late_initcall(init_ide_cs);
 364module_exit(exit_ide_cs);
 365