linux/drivers/ide/arm/icside.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/ide/arm/icside.c
   3 *
   4 * Copyright (c) 1996-2004 Russell King.
   5 *
   6 * Please note that this platform does not support 32-bit IDE IO.
   7 */
   8
   9#include <linux/string.h>
  10#include <linux/module.h>
  11#include <linux/ioport.h>
  12#include <linux/slab.h>
  13#include <linux/blkdev.h>
  14#include <linux/errno.h>
  15#include <linux/hdreg.h>
  16#include <linux/ide.h>
  17#include <linux/dma-mapping.h>
  18#include <linux/device.h>
  19#include <linux/init.h>
  20#include <linux/scatterlist.h>
  21#include <linux/io.h>
  22
  23#include <asm/dma.h>
  24#include <asm/ecard.h>
  25
  26#define ICS_IDENT_OFFSET                0x2280
  27
  28#define ICS_ARCIN_V5_INTRSTAT           0x0000
  29#define ICS_ARCIN_V5_INTROFFSET         0x0004
  30#define ICS_ARCIN_V5_IDEOFFSET          0x2800
  31#define ICS_ARCIN_V5_IDEALTOFFSET       0x2b80
  32#define ICS_ARCIN_V5_IDESTEPPING        6
  33
  34#define ICS_ARCIN_V6_IDEOFFSET_1        0x2000
  35#define ICS_ARCIN_V6_INTROFFSET_1       0x2200
  36#define ICS_ARCIN_V6_INTRSTAT_1         0x2290
  37#define ICS_ARCIN_V6_IDEALTOFFSET_1     0x2380
  38#define ICS_ARCIN_V6_IDEOFFSET_2        0x3000
  39#define ICS_ARCIN_V6_INTROFFSET_2       0x3200
  40#define ICS_ARCIN_V6_INTRSTAT_2         0x3290
  41#define ICS_ARCIN_V6_IDEALTOFFSET_2     0x3380
  42#define ICS_ARCIN_V6_IDESTEPPING        6
  43
  44struct cardinfo {
  45        unsigned int dataoffset;
  46        unsigned int ctrloffset;
  47        unsigned int stepping;
  48};
  49
  50static struct cardinfo icside_cardinfo_v5 = {
  51        .dataoffset     = ICS_ARCIN_V5_IDEOFFSET,
  52        .ctrloffset     = ICS_ARCIN_V5_IDEALTOFFSET,
  53        .stepping       = ICS_ARCIN_V5_IDESTEPPING,
  54};
  55
  56static struct cardinfo icside_cardinfo_v6_1 = {
  57        .dataoffset     = ICS_ARCIN_V6_IDEOFFSET_1,
  58        .ctrloffset     = ICS_ARCIN_V6_IDEALTOFFSET_1,
  59        .stepping       = ICS_ARCIN_V6_IDESTEPPING,
  60};
  61
  62static struct cardinfo icside_cardinfo_v6_2 = {
  63        .dataoffset     = ICS_ARCIN_V6_IDEOFFSET_2,
  64        .ctrloffset     = ICS_ARCIN_V6_IDEALTOFFSET_2,
  65        .stepping       = ICS_ARCIN_V6_IDESTEPPING,
  66};
  67
  68struct icside_state {
  69        unsigned int channel;
  70        unsigned int enabled;
  71        void __iomem *irq_port;
  72        void __iomem *ioc_base;
  73        unsigned int type;
  74        /* parent device... until the IDE core gets one of its own */
  75        struct device *dev;
  76        ide_hwif_t *hwif[2];
  77};
  78
  79#define ICS_TYPE_A3IN   0
  80#define ICS_TYPE_A3USER 1
  81#define ICS_TYPE_V6     3
  82#define ICS_TYPE_V5     15
  83#define ICS_TYPE_NOTYPE ((unsigned int)-1)
  84
  85/* ---------------- Version 5 PCB Support Functions --------------------- */
  86/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
  87 * Purpose  : enable interrupts from card
  88 */
  89static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
  90{
  91        struct icside_state *state = ec->irq_data;
  92
  93        writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
  94}
  95
  96/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
  97 * Purpose  : disable interrupts from card
  98 */
  99static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
 100{
 101        struct icside_state *state = ec->irq_data;
 102
 103        readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
 104}
 105
 106static const expansioncard_ops_t icside_ops_arcin_v5 = {
 107        .irqenable      = icside_irqenable_arcin_v5,
 108        .irqdisable     = icside_irqdisable_arcin_v5,
 109};
 110
 111
 112/* ---------------- Version 6 PCB Support Functions --------------------- */
 113/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
 114 * Purpose  : enable interrupts from card
 115 */
 116static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
 117{
 118        struct icside_state *state = ec->irq_data;
 119        void __iomem *base = state->irq_port;
 120
 121        state->enabled = 1;
 122
 123        switch (state->channel) {
 124        case 0:
 125                writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
 126                readb(base + ICS_ARCIN_V6_INTROFFSET_2);
 127                break;
 128        case 1:
 129                writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
 130                readb(base + ICS_ARCIN_V6_INTROFFSET_1);
 131                break;
 132        }
 133}
 134
 135/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
 136 * Purpose  : disable interrupts from card
 137 */
 138static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
 139{
 140        struct icside_state *state = ec->irq_data;
 141
 142        state->enabled = 0;
 143
 144        readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
 145        readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
 146}
 147
 148/* Prototype: icside_irqprobe(struct expansion_card *ec)
 149 * Purpose  : detect an active interrupt from card
 150 */
 151static int icside_irqpending_arcin_v6(struct expansion_card *ec)
 152{
 153        struct icside_state *state = ec->irq_data;
 154
 155        return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
 156               readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
 157}
 158
 159static const expansioncard_ops_t icside_ops_arcin_v6 = {
 160        .irqenable      = icside_irqenable_arcin_v6,
 161        .irqdisable     = icside_irqdisable_arcin_v6,
 162        .irqpending     = icside_irqpending_arcin_v6,
 163};
 164
 165/*
 166 * Handle routing of interrupts.  This is called before
 167 * we write the command to the drive.
 168 */
 169static void icside_maskproc(ide_drive_t *drive, int mask)
 170{
 171        ide_hwif_t *hwif = HWIF(drive);
 172        struct icside_state *state = hwif->hwif_data;
 173        unsigned long flags;
 174
 175        local_irq_save(flags);
 176
 177        state->channel = hwif->channel;
 178
 179        if (state->enabled && !mask) {
 180                switch (hwif->channel) {
 181                case 0:
 182                        writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
 183                        readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
 184                        break;
 185                case 1:
 186                        writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
 187                        readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
 188                        break;
 189                }
 190        } else {
 191                readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
 192                readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
 193        }
 194
 195        local_irq_restore(flags);
 196}
 197
 198#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
 199/*
 200 * SG-DMA support.
 201 *
 202 * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
 203 * There is only one DMA controller per card, which means that only
 204 * one drive can be accessed at one time.  NOTE! We do not enforce that
 205 * here, but we rely on the main IDE driver spotting that both
 206 * interfaces use the same IRQ, which should guarantee this.
 207 */
 208
 209static void icside_build_sglist(ide_drive_t *drive, struct request *rq)
 210{
 211        ide_hwif_t *hwif = drive->hwif;
 212        struct icside_state *state = hwif->hwif_data;
 213        struct scatterlist *sg = hwif->sg_table;
 214
 215        ide_map_sg(drive, rq);
 216
 217        if (rq_data_dir(rq) == READ)
 218                hwif->sg_dma_direction = DMA_FROM_DEVICE;
 219        else
 220                hwif->sg_dma_direction = DMA_TO_DEVICE;
 221
 222        hwif->sg_nents = dma_map_sg(state->dev, sg, hwif->sg_nents,
 223                                    hwif->sg_dma_direction);
 224}
 225
 226/*
 227 * Configure the IOMD to give the appropriate timings for the transfer
 228 * mode being requested.  We take the advice of the ATA standards, and
 229 * calculate the cycle time based on the transfer mode, and the EIDE
 230 * MW DMA specs that the drive provides in the IDENTIFY command.
 231 *
 232 * We have the following IOMD DMA modes to choose from:
 233 *
 234 *      Type    Active          Recovery        Cycle
 235 *      A       250 (250)       312 (550)       562 (800)
 236 *      B       187             250             437
 237 *      C       125 (125)       125 (375)       250 (500)
 238 *      D       62              125             187
 239 *
 240 * (figures in brackets are actual measured timings)
 241 *
 242 * However, we also need to take care of the read/write active and
 243 * recovery timings:
 244 *
 245 *                      Read    Write
 246 *      Mode    Active  -- Recovery --  Cycle   IOMD type
 247 *      MW0     215     50      215     480     A
 248 *      MW1     80      50      50      150     C
 249 *      MW2     70      25      25      120     C
 250 */
 251static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
 252{
 253        int cycle_time, use_dma_info = 0;
 254
 255        switch (xfer_mode) {
 256        case XFER_MW_DMA_2:
 257                cycle_time = 250;
 258                use_dma_info = 1;
 259                break;
 260
 261        case XFER_MW_DMA_1:
 262                cycle_time = 250;
 263                use_dma_info = 1;
 264                break;
 265
 266        case XFER_MW_DMA_0:
 267                cycle_time = 480;
 268                break;
 269
 270        case XFER_SW_DMA_2:
 271        case XFER_SW_DMA_1:
 272        case XFER_SW_DMA_0:
 273                cycle_time = 480;
 274                break;
 275        default:
 276                return;
 277        }
 278
 279        /*
 280         * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should
 281         * take care to note the values in the ID...
 282         */
 283        if (use_dma_info && drive->id->eide_dma_time > cycle_time)
 284                cycle_time = drive->id->eide_dma_time;
 285
 286        drive->drive_data = cycle_time;
 287
 288        printk("%s: %s selected (peak %dMB/s)\n", drive->name,
 289                ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
 290}
 291
 292static void icside_dma_host_off(ide_drive_t *drive)
 293{
 294}
 295
 296static void icside_dma_off_quietly(ide_drive_t *drive)
 297{
 298        drive->using_dma = 0;
 299}
 300
 301static void icside_dma_host_on(ide_drive_t *drive)
 302{
 303}
 304
 305static int icside_dma_on(ide_drive_t *drive)
 306{
 307        drive->using_dma = 1;
 308
 309        return 0;
 310}
 311
 312static int icside_dma_end(ide_drive_t *drive)
 313{
 314        ide_hwif_t *hwif = HWIF(drive);
 315        struct icside_state *state = hwif->hwif_data;
 316
 317        drive->waiting_for_dma = 0;
 318
 319        disable_dma(ECARD_DEV(state->dev)->dma);
 320
 321        /* Teardown mappings after DMA has completed. */
 322        dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents,
 323                     hwif->sg_dma_direction);
 324
 325        return get_dma_residue(ECARD_DEV(state->dev)->dma) != 0;
 326}
 327
 328static void icside_dma_start(ide_drive_t *drive)
 329{
 330        ide_hwif_t *hwif = HWIF(drive);
 331        struct icside_state *state = hwif->hwif_data;
 332
 333        /* We can not enable DMA on both channels simultaneously. */
 334        BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma));
 335        enable_dma(ECARD_DEV(state->dev)->dma);
 336}
 337
 338static int icside_dma_setup(ide_drive_t *drive)
 339{
 340        ide_hwif_t *hwif = HWIF(drive);
 341        struct icside_state *state = hwif->hwif_data;
 342        struct request *rq = hwif->hwgroup->rq;
 343        unsigned int dma_mode;
 344
 345        if (rq_data_dir(rq))
 346                dma_mode = DMA_MODE_WRITE;
 347        else
 348                dma_mode = DMA_MODE_READ;
 349
 350        /*
 351         * We can not enable DMA on both channels.
 352         */
 353        BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma));
 354
 355        icside_build_sglist(drive, rq);
 356
 357        /*
 358         * Ensure that we have the right interrupt routed.
 359         */
 360        icside_maskproc(drive, 0);
 361
 362        /*
 363         * Route the DMA signals to the correct interface.
 364         */
 365        writeb(hwif->select_data, hwif->config_data);
 366
 367        /*
 368         * Select the correct timing for this drive.
 369         */
 370        set_dma_speed(ECARD_DEV(state->dev)->dma, drive->drive_data);
 371
 372        /*
 373         * Tell the DMA engine about the SG table and
 374         * data direction.
 375         */
 376        set_dma_sg(ECARD_DEV(state->dev)->dma, hwif->sg_table, hwif->sg_nents);
 377        set_dma_mode(ECARD_DEV(state->dev)->dma, dma_mode);
 378
 379        drive->waiting_for_dma = 1;
 380
 381        return 0;
 382}
 383
 384static void icside_dma_exec_cmd(ide_drive_t *drive, u8 cmd)
 385{
 386        /* issue cmd to drive */
 387        ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD, NULL);
 388}
 389
 390static int icside_dma_test_irq(ide_drive_t *drive)
 391{
 392        ide_hwif_t *hwif = HWIF(drive);
 393        struct icside_state *state = hwif->hwif_data;
 394
 395        return readb(state->irq_port +
 396                     (hwif->channel ?
 397                        ICS_ARCIN_V6_INTRSTAT_2 :
 398                        ICS_ARCIN_V6_INTRSTAT_1)) & 1;
 399}
 400
 401static void icside_dma_timeout(ide_drive_t *drive)
 402{
 403        printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
 404
 405        if (icside_dma_test_irq(drive))
 406                return;
 407
 408        ide_dump_status(drive, "DMA timeout", HWIF(drive)->INB(IDE_STATUS_REG));
 409
 410        icside_dma_end(drive);
 411}
 412
 413static void icside_dma_lost_irq(ide_drive_t *drive)
 414{
 415        printk(KERN_ERR "%s: IRQ lost\n", drive->name);
 416}
 417
 418static void icside_dma_init(ide_hwif_t *hwif)
 419{
 420        hwif->mwdma_mask        = 7; /* MW0..2 */
 421        hwif->swdma_mask        = 7; /* SW0..2 */
 422
 423        hwif->dmatable_cpu      = NULL;
 424        hwif->dmatable_dma      = 0;
 425        hwif->set_dma_mode      = icside_set_dma_mode;
 426
 427        hwif->dma_host_off      = icside_dma_host_off;
 428        hwif->dma_off_quietly   = icside_dma_off_quietly;
 429        hwif->dma_host_on       = icside_dma_host_on;
 430        hwif->ide_dma_on        = icside_dma_on;
 431        hwif->dma_setup         = icside_dma_setup;
 432        hwif->dma_exec_cmd      = icside_dma_exec_cmd;
 433        hwif->dma_start         = icside_dma_start;
 434        hwif->ide_dma_end       = icside_dma_end;
 435        hwif->ide_dma_test_irq  = icside_dma_test_irq;
 436        hwif->dma_timeout       = icside_dma_timeout;
 437        hwif->dma_lost_irq      = icside_dma_lost_irq;
 438}
 439#else
 440#define icside_dma_init(hwif)   (0)
 441#endif
 442
 443static ide_hwif_t *
 444icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *ec)
 445{
 446        unsigned long port = (unsigned long)base + info->dataoffset;
 447        ide_hwif_t *hwif;
 448
 449        hwif = ide_find_port(port);
 450        if (hwif) {
 451                int i;
 452
 453                /*
 454                 * Ensure we're using MMIO
 455                 */
 456                default_hwif_mmiops(hwif);
 457                hwif->mmio = 1;
 458
 459                for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
 460                        hwif->io_ports[i] = port;
 461                        port += 1 << info->stepping;
 462                }
 463                hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)base + info->ctrloffset;
 464                hwif->irq     = ec->irq;
 465                hwif->noprobe = 0;
 466                hwif->chipset = ide_acorn;
 467                hwif->gendev.parent = &ec->dev;
 468        }
 469
 470        return hwif;
 471}
 472
 473static int __init
 474icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 475{
 476        ide_hwif_t *hwif;
 477        void __iomem *base;
 478        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 479
 480        base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
 481        if (!base)
 482                return -ENOMEM;
 483
 484        state->irq_port = base;
 485
 486        ec->irqaddr  = base + ICS_ARCIN_V5_INTRSTAT;
 487        ec->irqmask  = 1;
 488
 489        ecard_setirq(ec, &icside_ops_arcin_v5, state);
 490
 491        /*
 492         * Be on the safe side - disable interrupts
 493         */
 494        icside_irqdisable_arcin_v5(ec, 0);
 495
 496        hwif = icside_setup(base, &icside_cardinfo_v5, ec);
 497        if (!hwif)
 498                return -ENODEV;
 499
 500        state->hwif[0] = hwif;
 501
 502        idx[0] = hwif->index;
 503
 504        ide_device_add(idx);
 505
 506        return 0;
 507}
 508
 509static int __init
 510icside_register_v6(struct icside_state *state, struct expansion_card *ec)
 511{
 512        ide_hwif_t *hwif, *mate;
 513        void __iomem *ioc_base, *easi_base;
 514        unsigned int sel = 0;
 515        int ret;
 516        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 517
 518        ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
 519        if (!ioc_base) {
 520                ret = -ENOMEM;
 521                goto out;
 522        }
 523
 524        easi_base = ioc_base;
 525
 526        if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
 527                easi_base = ecardm_iomap(ec, ECARD_RES_EASI, 0, 0);
 528                if (!easi_base) {
 529                        ret = -ENOMEM;
 530                        goto out;
 531                }
 532
 533                /*
 534                 * Enable access to the EASI region.
 535                 */
 536                sel = 1 << 5;
 537        }
 538
 539        writeb(sel, ioc_base);
 540
 541        ecard_setirq(ec, &icside_ops_arcin_v6, state);
 542
 543        state->irq_port   = easi_base;
 544        state->ioc_base   = ioc_base;
 545
 546        /*
 547         * Be on the safe side - disable interrupts
 548         */
 549        icside_irqdisable_arcin_v6(ec, 0);
 550
 551        /*
 552         * Find and register the interfaces.
 553         */
 554        hwif = icside_setup(easi_base, &icside_cardinfo_v6_1, ec);
 555        mate = icside_setup(easi_base, &icside_cardinfo_v6_2, ec);
 556
 557        if (!hwif || !mate) {
 558                ret = -ENODEV;
 559                goto out;
 560        }
 561
 562        state->hwif[0]    = hwif;
 563        state->hwif[1]    = mate;
 564
 565        hwif->maskproc    = icside_maskproc;
 566        hwif->channel     = 0;
 567        hwif->hwif_data   = state;
 568        hwif->mate        = mate;
 569        hwif->serialized  = 1;
 570        hwif->config_data = (unsigned long)ioc_base;
 571        hwif->select_data = sel;
 572
 573        mate->maskproc    = icside_maskproc;
 574        mate->channel     = 1;
 575        mate->hwif_data   = state;
 576        mate->mate        = hwif;
 577        mate->serialized  = 1;
 578        mate->config_data = (unsigned long)ioc_base;
 579        mate->select_data = sel | 1;
 580
 581        if (ec->dma != NO_DMA && !request_dma(ec->dma, hwif->name)) {
 582                icside_dma_init(hwif);
 583                icside_dma_init(mate);
 584        }
 585
 586        idx[0] = hwif->index;
 587        idx[1] = mate->index;
 588
 589        ide_device_add(idx);
 590
 591        return 0;
 592
 593 out:
 594        return ret;
 595}
 596
 597static int __devinit
 598icside_probe(struct expansion_card *ec, const struct ecard_id *id)
 599{
 600        struct icside_state *state;
 601        void __iomem *idmem;
 602        int ret;
 603
 604        ret = ecard_request_resources(ec);
 605        if (ret)
 606                goto out;
 607
 608        state = kzalloc(sizeof(struct icside_state), GFP_KERNEL);
 609        if (!state) {
 610                ret = -ENOMEM;
 611                goto release;
 612        }
 613
 614        state->type     = ICS_TYPE_NOTYPE;
 615        state->dev      = &ec->dev;
 616
 617        idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
 618        if (idmem) {
 619                unsigned int type;
 620
 621                type = readb(idmem + ICS_IDENT_OFFSET) & 1;
 622                type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;
 623                type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;
 624                type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;
 625                ecardm_iounmap(ec, idmem);
 626
 627                state->type = type;
 628        }
 629
 630        switch (state->type) {
 631        case ICS_TYPE_A3IN:
 632                dev_warn(&ec->dev, "A3IN unsupported\n");
 633                ret = -ENODEV;
 634                break;
 635
 636        case ICS_TYPE_A3USER:
 637                dev_warn(&ec->dev, "A3USER unsupported\n");
 638                ret = -ENODEV;
 639                break;
 640
 641        case ICS_TYPE_V5:
 642                ret = icside_register_v5(state, ec);
 643                break;
 644
 645        case ICS_TYPE_V6:
 646                ret = icside_register_v6(state, ec);
 647                break;
 648
 649        default:
 650                dev_warn(&ec->dev, "unknown interface type\n");
 651                ret = -ENODEV;
 652                break;
 653        }
 654
 655        if (ret == 0) {
 656                ecard_set_drvdata(ec, state);
 657                goto out;
 658        }
 659
 660        kfree(state);
 661 release:
 662        ecard_release_resources(ec);
 663 out:
 664        return ret;
 665}
 666
 667static void __devexit icside_remove(struct expansion_card *ec)
 668{
 669        struct icside_state *state = ecard_get_drvdata(ec);
 670
 671        switch (state->type) {
 672        case ICS_TYPE_V5:
 673                /* FIXME: tell IDE to stop using the interface */
 674
 675                /* Disable interrupts */
 676                icside_irqdisable_arcin_v5(ec, 0);
 677                break;
 678
 679        case ICS_TYPE_V6:
 680                /* FIXME: tell IDE to stop using the interface */
 681                if (ec->dma != NO_DMA)
 682                        free_dma(ec->dma);
 683
 684                /* Disable interrupts */
 685                icside_irqdisable_arcin_v6(ec, 0);
 686
 687                /* Reset the ROM pointer/EASI selection */
 688                writeb(0, state->ioc_base);
 689                break;
 690        }
 691
 692        ecard_set_drvdata(ec, NULL);
 693
 694        kfree(state);
 695        ecard_release_resources(ec);
 696}
 697
 698static void icside_shutdown(struct expansion_card *ec)
 699{
 700        struct icside_state *state = ecard_get_drvdata(ec);
 701        unsigned long flags;
 702
 703        /*
 704         * Disable interrupts from this card.  We need to do
 705         * this before disabling EASI since we may be accessing
 706         * this register via that region.
 707         */
 708        local_irq_save(flags);
 709        ec->ops->irqdisable(ec, 0);
 710        local_irq_restore(flags);
 711
 712        /*
 713         * Reset the ROM pointer so that we can read the ROM
 714         * after a soft reboot.  This also disables access to
 715         * the IDE taskfile via the EASI region.
 716         */
 717        if (state->ioc_base)
 718                writeb(0, state->ioc_base);
 719}
 720
 721static const struct ecard_id icside_ids[] = {
 722        { MANU_ICS,  PROD_ICS_IDE  },
 723        { MANU_ICS2, PROD_ICS2_IDE },
 724        { 0xffff, 0xffff }
 725};
 726
 727static struct ecard_driver icside_driver = {
 728        .probe          = icside_probe,
 729        .remove         = __devexit_p(icside_remove),
 730        .shutdown       = icside_shutdown,
 731        .id_table       = icside_ids,
 732        .drv = {
 733                .name   = "icside",
 734        },
 735};
 736
 737static int __init icside_init(void)
 738{
 739        return ecard_register_driver(&icside_driver);
 740}
 741
 742MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 743MODULE_LICENSE("GPL");
 744MODULE_DESCRIPTION("ICS IDE driver");
 745
 746module_init(icside_init);
 747
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.