/*
 *  Mostly written by Mark Lord  <[EMAIL PROTECTED]>
 *                and Gadi Oxman <[EMAIL PROTECTED]>
 *                and Andre Hedrick <[EMAIL PROTECTED]>
 *
 *  See linux/MAINTAINERS for address of current maintainer.
 *
 * This is the multiple IDE interface driver, as evolved from hd.c.
 * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
 *   (usually 14 & 15).
 * There can be up to two drives per interface, as per the ATA-2 spec.
 *
 * ...
 *
 *  From hd.c:
 *  |
 *  | It traverses the request-list, using interrupts to jump between functions.
 *  | As nearly all functions can be called within interrupts, we may not sleep.
 *  | Special care is recommended.  Have Fun!
 *  |
 *  | modified by Drew Eckhardt to check nr of hd's from the CMOS.
 *  |
 *  | Thanks to Branko Lankester, [EMAIL PROTECTED], who found a bug
 *  | in the early extended-partition checks and added DM partitions.
 *  |
 *  | Early work on error handling by Mika Liljeberg ([EMAIL PROTECTED]).
 *  |
 *  | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
 *  | and general streamlining by Mark Lord ([EMAIL PROTECTED]).
 *
 *  October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
 *
 *    Mark Lord    ([EMAIL PROTECTED])        (IDE Perf.Pkg)
 *    Delman Lee    ([EMAIL PROTECTED])        ("Mr. atdisk2")
 *    Scott Snyder    ([EMAIL PROTECTED])    (ATAPI IDE cd-rom)
 *

/**
 *    ide_unregister        -    free an IDE interface
 *    @index: index of interface (will change soon to a pointer)
 *    @init_default: init default hwif flag
 *    @restore: restore hwif flag
 *
 *    Perform the final unregister of an IDE interface. At the moment
 *    we don't refcount interfaces so this will also get split up.
 *
 *    Locking:
 *    The caller must not hold the IDE locks
 *    The drive present/vanishing is not yet properly locked
 *    Take care with the callbacks. These have been split to avoid
 *    deadlocking the IDE layer. The shutdown callback is called
 *    before we take the lock and free resources. It is up to the
 *    caller to be sure there is no pending I/O here, and that
 *    the interface will not be reopened (present/vanishing locking
 *    isn't yet done BTW). After we commit to the final kill we
 *    call the cleanup callback with the ide locks held.
 *
 *    Unregister restores the hwif structures to the default state.
 *    This is raving bonkers.
 */

void ide_unregister(unsigned int index, int init_default, int restore)
{
    ide_drive_t *drive;
    ide_hwif_t *hwif, *g;
    static ide_hwif_t tmp_hwif; /* protected by ide_cfg_mtx */
    ide_hwgroup_t *hwgroup;
    int irq_count = 0, unit;

    BUG_ON(index >= MAX_HWIFS);

    BUG_ON(in_interrupt());
    BUG_ON(irqs_disabled());
    mutex_lock(&ide_cfg_mtx);
    spin_lock_irq(&ide_lock);
    hwif = &ide_hwifs[index];
    if (!hwif->present)
        goto abort;
    for (unit = 0; unit < MAX_DRIVES; ++unit) {
        drive = &hwif->drives[unit];
        if (!drive->present)
            continue;
        spin_unlock_irq(&ide_lock);
        device_unregister(&drive->gendev);
        wait_for_completion(&drive->gendev_rel_comp);
        spin_lock_irq(&ide_lock);
    }
    hwif->present = 0;

    spin_unlock_irq(&ide_lock);

    ide_proc_unregister_port(hwif);

    hwgroup = hwif->hwgroup;
    /*
     * free the irq if we were the only hwif using it
     */
    g = hwgroup->hwif;
    do {
        if (g->irq == hwif->irq)
            ++irq_count;
        g = g->next;
    } while (g != hwgroup->hwif);
    if (irq_count == 1)
        free_irq(hwif->irq, hwgroup);

    ide_remove_port_from_hwgroup(hwif);

    device_unregister(&hwif->gendev);
    wait_for_completion(&hwif->gendev_rel_comp);

    /*
     * Remove us from the kernel's knowledge
     */
    blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS);
    kfree(hwif->sg_table);
    unregister_blkdev(hwif->major, hwif->name);
    spin_lock_irq(&ide_lock);

    if (hwif->dma_base) {
        (void) ide_release_dma(hwif);

        hwif->dma_base = 0;
        hwif->dma_command = 0;
        hwif->dma_vendor1 = 0;
        hwif->dma_status = 0;
        hwif->dma_vendor3 = 0;
        hwif->dma_prdtable = 0;

        hwif->extra_base  = 0;
        hwif->extra_ports = 0;
    }

    ide_hwif_release_regions(hwif);

    /* copy original settings */
    tmp_hwif = *hwif;

    /* restore hwif data to pristine status */
    ide_init_port_data(hwif, index);

    if (init_default)
        init_hwif_default(hwif, index);

    if (restore)
        ide_hwif_restore(hwif, &tmp_hwif);

abort:
    spin_unlock_irq(&ide_lock);
    mutex_unlock(&ide_cfg_mtx);
}

EXPORT_SYMBOL(ide_unregister);

Reply via email to