static int initializing; /* set while initializing built-in drivers */
DECLARE_MUTEX(ide_cfg_sem);
+EXPORT_SYMBOL_GPL(ide_cfg_sem);
spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
#ifdef CONFIG_BLK_DEV_IDEPCI
#endif
EXPORT_SYMBOL(noautodma);
-EXPORT_SYMBOL(ide_bus_type);
/*
* This is declared extern in ide.h, for access by other IDE modules:
static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
{
unsigned int unit;
+ unsigned int key = hwif->key;
/* bulk initialize hwif & drive info with zeros */
memset(hwif, 0, sizeof(ide_hwif_t));
/* fill in any non-zero initial values */
+ hwif->key = key + 1; /* Protected by ide_cfg_sem */
hwif->index = index;
hwif->major = ide_hwif_to_major[index];
#endif
}
+extern void ide_arm_init(void);
+
/*
* init_ide_data() sets reasonable default values into all fields
* of all instances of the hwifs and drives, but only on the first call.
ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
#endif
}
-
-/* OBSOLETE: still needed on arm26 and arm */
-#ifdef CONFIG_ARM
- /* Add default hw interfaces */
+#ifdef CONFIG_IDE_ARM
initializing = 1;
- ide_init_default_hwifs();
+ ide_arm_init();
initializing = 0;
#endif
}
/*
- * ide_system_bus_speed() returns what we think is the system VESA/PCI
- * bus speed (in MHz). This is used for calculating interface PIO timings.
- * The default is 40 for known PCI systems, 50 otherwise.
- * The "idebus=xx" parameter can be used to override this value.
- * The actual value to be used is computed/displayed the first time through.
+ * ide_drive_from_key - turn key into drive
+ * @kval: persistent key
+ *
+ * Convert a key into a drive. Currently the key is packed as
+ * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold
+ * ide_settings_sem for the duration of the returned reference
+ */
+
+ide_drive_t *ide_drive_from_key(void *kval)
+{
+ unsigned long key = (unsigned long) kval;
+ int idx = (key >> 8) & 0xFF;
+ int drive = key & 3;
+ ide_hwif_t *hwif = &ide_hwifs[idx];
+ ide_drive_t *ret;
+
+ key >>= 16;
+
+ if(hwif->configured == 0 || hwif->present == 0 || hwif->drives[drive].dead || hwif->key != key)
+ ret = NULL;
+ else
+ ret = &ide_hwifs[idx].drives[drive];
+
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(ide_drive_from_key);
+
+/*
+ * ide_drive_to_key - turn drive to persistent key
+ * @drive: drive to use
+ *
+ * Convert drive into a key. Currently the key is packed as
+ * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold
+ * ide_settings_sem for the duration of the returned reference
*/
+
+void *ide_drive_to_key(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long val;
+
+ val = (hwif->index << 8) | (hwif->key << 16) | drive->select.b.unit;
+ return (void *)val;
+}
+
+/*
+ * ide_hwif_from_key - turn key into hwif
+ * @kval: persistent key
+ *
+ * Convert a key into a drive. Currently the key is packed as
+ * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold
+ * ide_settings_sem for the duration of the returned reference
+ */
+
+ide_hwif_t *ide_hwif_from_key(void *kval)
+{
+ unsigned long key = (unsigned long) kval;
+ int idx = (key >> 8) & 0xFF;
+ ide_hwif_t *hwif = &ide_hwifs[idx];
+
+ key >>= 16;
+
+ if(hwif->configured == 0 || hwif->present == 0 || hwif->key != key)
+ return NULL;
+ return hwif;
+}
+
+/*
+ * ide_hwif_to_key - turn drive to persistent key
+ * @hwif: hwif to use
+ *
+ * Convert drive into a key. Currently the key is packed as
+ * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold
+ * ide_settings_sem for the duration of the returned reference
+ */
+
+void *ide_hwif_to_key(ide_hwif_t *hwif)
+{
+ unsigned long val;
+
+ val = (hwif->index << 8) | (hwif->key << 16);
+ return (void *)val;
+}
+
+/**
+ * ide_system_bus_speed - guess bus speed
+ *
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in MHz). This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ * The actual value to be used is computed/displayed the first time
+ * through. Drivers should only use this as a last resort.
+ *
+ * Returns a guessed speed in MHz.
+ */
+
int ide_system_bus_speed (void)
{
if (!system_bus_speed) {
return system_bus_speed;
}
-/*
- * current_capacity() returns the capacity (in sectors) of a drive
- * according to its current geometry/LBA settings.
+/**
+ * current_capacity - drive capacity
+ * @drive: drive to query
+ *
+ * Return the current capacity (in sectors) of a drive according to
+ * its current geometry/LBA settings. Empty removables are reported
+ * as size zero.
*/
+
sector_t current_capacity (ide_drive_t *drive)
{
if (!drive->present)
EXPORT_SYMBOL(current_capacity);
-/*
- * Error reporting, in human readable form (luxurious, but a memory hog).
+/**
+ * ide_dump_status - translate ATA error
+ * @drive: drive the error occured on
+ * @msg: information string
+ * @stat: status byte
+ *
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ * Combines the drive name, message and status byte to provide a
+ * user understandable explanation of the device error.
*/
+
u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
{
ide_hwif_t *hwif = HWIF(drive);
local_irq_set(flags);
printk(KERN_WARNING "%s: %s: status=0x%02x", drive->name, msg, stat);
-#if FANCY_STATUS_DUMPS
printk(" { ");
if (stat & BUSY_STAT) {
printk("Busy ");
if (stat & ERR_STAT) printk("Error ");
}
printk("}");
-#endif /* FANCY_STATUS_DUMPS */
printk("\n");
if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
err = hwif->INB(IDE_ERROR_REG);
printk("%s: %s: error=0x%02x", drive->name, msg, err);
-#if FANCY_STATUS_DUMPS
if (drive->media == ide_disk) {
printk(" { ");
if (err & ABRT_ERR) printk("DriveStatusError ");
printk(", sector=%llu", (unsigned long long)HWGROUP(drive)->rq->sector);
}
}
-#endif /* FANCY_STATUS_DUMPS */
printk("\n");
}
+ {
+ struct request *rq;
+ int opcode = 0x100;
+
+ spin_lock(&ide_lock);
+ rq = NULL;
+ if (HWGROUP(drive))
+ rq = HWGROUP(drive)->rq;
+ spin_unlock(&ide_lock);
+ if (!rq)
+ goto out;
+ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
+ char *args = rq->buffer;
+ if (args)
+ opcode = args[0];
+ } else if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *args = rq->special;
+ if (args) {
+ task_struct_t *tf = (task_struct_t *) args->tfRegister;
+ opcode = tf->command;
+ }
+ }
+
+ printk("ide: failed opcode was %x\n", opcode);
+ }
+out:
local_irq_restore(flags);
return err;
}
return -ENXIO;
}
+/*
+ * drives_lock protects the list of drives, drivers lock the
+ * list of drivers. Currently nobody takes both at once.
+ * drivers_sem guards the drivers_list for readers that may
+ * sleep. It must be taken before drivers_lock. Take drivers_sem
+ * before ide_setting_sem and idecfg_sem before either of the
+ * others.
+ */
+
static spinlock_t drives_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_MUTEX(drivers_sem);
static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(drivers);
-/* Iterator */
+/* Iterator for the driver list. */
+
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct list_head *p;
loff_t l = *pos;
- spin_lock(&drivers_lock);
+ down(&drivers_sem);
list_for_each(p, &drivers)
if (!l--)
return list_entry(p, ide_driver_t, drivers);
return NULL;
}
+
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
struct list_head *p = ((ide_driver_t *)v)->drivers.next;
(*pos)++;
return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers);
}
+
static void m_stop(struct seq_file *m, void *v)
{
- spin_unlock(&drivers_lock);
+ up(&drivers_sem);
}
+
static int show_driver(struct seq_file *m, void *v)
{
ide_driver_t *driver = v;
seq_printf(m, "%s version %s\n", driver->name, driver->version);
return 0;
}
+
struct seq_operations ide_drivers_op = {
.start = m_start,
.next = m_next,
* MMIO leaves it to the controller driver,
* PIO will migrate this way over time.
*/
+
int ide_hwif_request_regions(ide_hwif_t *hwif)
{
unsigned long addr;
return -EBUSY;
}
-EXPORT_SYMBOL(ide_hwif_request_regions);
-
/**
* ide_hwif_release_regions - free IDE resources
*
* importantly our caller should be doing this so we need to
* restructure this as a helper function for drivers.
*/
+
void ide_hwif_release_regions(ide_hwif_t *hwif)
{
u32 i = 0;
release_region(hwif->io_ports[i], 1);
}
-EXPORT_SYMBOL(ide_hwif_release_regions);
+/**
+ * ide_hwif_restore - restore hwif to template
+ * @hwif: hwif to update
+ * @tmp_hwif: template
+ *
+ * Restore hwif to a previous state by copying most settngs
+ * from the template.
+ */
+
+static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+{
+ hwif->hwgroup = tmp_hwif->hwgroup;
+
+ hwif->gendev.parent = tmp_hwif->gendev.parent;
+
+ hwif->proc = tmp_hwif->proc;
+
+ hwif->major = tmp_hwif->major;
+ hwif->straight8 = tmp_hwif->straight8;
+ hwif->bus_state = tmp_hwif->bus_state;
+
+ hwif->atapi_dma = tmp_hwif->atapi_dma;
+ hwif->ultra_mask = tmp_hwif->ultra_mask;
+ hwif->mwdma_mask = tmp_hwif->mwdma_mask;
+ hwif->swdma_mask = tmp_hwif->swdma_mask;
+
+ hwif->chipset = tmp_hwif->chipset;
+ hwif->hold = tmp_hwif->hold;
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ hwif->pci_dev = tmp_hwif->pci_dev;
+ hwif->cds = tmp_hwif->cds;
+#endif
+
+ hwif->identify = tmp_hwif->identify;
+ hwif->tuneproc = tmp_hwif->tuneproc;
+ hwif->speedproc = tmp_hwif->speedproc;
+ hwif->selectproc = tmp_hwif->selectproc;
+ hwif->reset_poll = tmp_hwif->reset_poll;
+ hwif->pre_reset = tmp_hwif->pre_reset;
+ hwif->resetproc = tmp_hwif->resetproc;
+ hwif->intrproc = tmp_hwif->intrproc;
+ hwif->maskproc = tmp_hwif->maskproc;
+ hwif->quirkproc = tmp_hwif->quirkproc;
+ hwif->busproc = tmp_hwif->busproc;
+ hwif->raw_taskfile = tmp_hwif->raw_taskfile;
+
+ hwif->ata_input_data = tmp_hwif->ata_input_data;
+ hwif->ata_output_data = tmp_hwif->ata_output_data;
+ hwif->atapi_input_bytes = tmp_hwif->atapi_input_bytes;
+ hwif->atapi_output_bytes = tmp_hwif->atapi_output_bytes;
+
+ hwif->ide_dma_read = tmp_hwif->ide_dma_read;
+ hwif->ide_dma_write = tmp_hwif->ide_dma_write;
+ hwif->ide_dma_begin = tmp_hwif->ide_dma_begin;
+ hwif->ide_dma_end = tmp_hwif->ide_dma_end;
+ hwif->ide_dma_check = tmp_hwif->ide_dma_check;
+ hwif->ide_dma_on = tmp_hwif->ide_dma_on;
+ hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly;
+ hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq;
+ hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on;
+ hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off;
+ hwif->ide_dma_verbose = tmp_hwif->ide_dma_verbose;
+ hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq;
+ hwif->ide_dma_timeout = tmp_hwif->ide_dma_timeout;
+
+ hwif->OUTB = tmp_hwif->OUTB;
+ hwif->OUTBSYNC = tmp_hwif->OUTBSYNC;
+ hwif->OUTW = tmp_hwif->OUTW;
+ hwif->OUTL = tmp_hwif->OUTL;
+ hwif->OUTSW = tmp_hwif->OUTSW;
+ hwif->OUTSL = tmp_hwif->OUTSL;
+
+ hwif->INB = tmp_hwif->INB;
+ hwif->INW = tmp_hwif->INW;
+ hwif->INL = tmp_hwif->INL;
+ hwif->INSW = tmp_hwif->INSW;
+ hwif->INSL = tmp_hwif->INSL;
+
+ hwif->mmio = tmp_hwif->mmio;
+ hwif->rqsize = tmp_hwif->rqsize;
+ hwif->no_lba48 = tmp_hwif->no_lba48;
+
+#ifndef CONFIG_BLK_DEV_IDECS
+ hwif->irq = tmp_hwif->irq;
+#endif
+
+ hwif->dma_base = tmp_hwif->dma_base;
+ hwif->dma_master = tmp_hwif->dma_master;
+ hwif->dma_command = tmp_hwif->dma_command;
+ hwif->dma_vendor1 = tmp_hwif->dma_vendor1;
+ hwif->dma_status = tmp_hwif->dma_status;
+ hwif->dma_vendor3 = tmp_hwif->dma_vendor3;
+ hwif->dma_prdtable = tmp_hwif->dma_prdtable;
+
+ hwif->dma_extra = tmp_hwif->dma_extra;
+ hwif->config_data = tmp_hwif->config_data;
+ hwif->select_data = tmp_hwif->select_data;
+ hwif->autodma = tmp_hwif->autodma;
+ hwif->udma_four = tmp_hwif->udma_four;
+ hwif->no_dsc = tmp_hwif->no_dsc;
+
+ hwif->hwif_data = tmp_hwif->hwif_data;
+}
/**
- * ide_unregister - free an ide interface
- * @index: index of interface (will change soon to a pointer)
+ * __ide_unregister_hwif - free an ide interface
+ * @hwif: interface to unregister
*
* 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 caller must not hold the IDE locks except for ide_cfg_sem
+ * which must be held.
+ *
* 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
* isnt yet done btw). After we commit to the final kill we
* call the cleanup callback with the ide locks held.
*
+ * An interface can be in four states we care about
+ * - It can be busy (drive or driver thinks its active). No unload
+ * - It can be unconfigured - which means its already gone
+ * - It can be configured and present - a full interface
+ * - It can be configured and not present - pci configured but no drives
+ * so logically absent.
+ *
* Unregister restores the hwif structures to the default state.
- * This is raving bonkers.
*/
-
-void ide_unregister (unsigned int index)
+
+int __ide_unregister_hwif(ide_hwif_t *hwif)
{
- ide_drive_t *drive;
- ide_hwif_t *hwif, *g;
+ ide_drive_t *drive = NULL; /* keep compiler happy */
+ ide_hwif_t *g;
+ static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */
ide_hwgroup_t *hwgroup;
int irq_count = 0, unit, i;
- ide_hwif_t old_hwif;
+ int was_present;
+ int ret = 0;
+ int index = hwif->index;
- if (index >= MAX_HWIFS)
- BUG();
-
BUG_ON(in_interrupt());
BUG_ON(irqs_disabled());
- down(&ide_cfg_sem);
+
+ /* Make sure nobody sneaks in via the proc interface */
+ down(&ide_setting_sem);
+
+ /* Now ensure nobody gets in for I/O while we clean up and
+ do the busy check. If busy is set then the device is still
+ open and we must stop */
spin_lock_irq(&ide_lock);
- hwif = &ide_hwifs[index];
- if (!hwif->present)
+
+ if (!hwif->configured)
goto abort;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
goto abort;
drive->dead = 1;
}
+ /*
+ * Protect against new users. From this point the hwif
+ * is not present so cannot be opened by a new I/O source.
+ * This also invalidates key driven access from procfs
+ */
+
+ was_present = hwif->present;
hwif->present = 0;
-
+
spin_unlock_irq(&ide_lock);
+ up(&ide_setting_sem);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
continue;
DRIVER(drive)->cleanup(drive);
}
-
+
#ifdef CONFIG_PROC_FS
destroy_proc_ide_drives(hwif);
+ destroy_proc_ide_interface(hwif);
#endif
+ spin_lock_irq(&ide_lock);
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)
+ if(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);
+ }
+ spin_unlock_irq(&ide_lock);
+
+ if (irq_count == 1 && hwgroup)
free_irq(hwif->irq, hwgroup);
- spin_lock_irq(&ide_lock);
/*
* Note that we only release the standard ports,
* and do not even try to handle any extra ports
* allocated for weird IDE interface chipsets.
+ *
+ * FIXME: should defer this I think
*/
- ide_hwif_release_regions(hwif);
+
+ if(was_present)
+ ide_hwif_release_regions(hwif);
/*
* Remove us from the hwgroup, and free
}
if (!drive->present)
continue;
+
+ /*
+ * The hwgroup chain is IRQ touched. We must protect
+ * walking this from an IDE event for another device
+ * in the chain
+ */
+
+ spin_lock_irq(&ide_lock);
if (drive == drive->next) {
/* special case: last drive from hwgroup. */
BUG_ON(hwgroup->drive != drive);
hwgroup->hwif = HWIF(hwgroup->drive);
}
}
+ spin_unlock_irq(&ide_lock);
+
+ /*
+ * The rest of the cleanup is private
+ */
+
BUG_ON(hwgroup->drive == drive);
if (drive->id != NULL) {
kfree(drive->id);
drive->id = NULL;
}
drive->present = 0;
- /* Messed up locking ... */
- spin_unlock_irq(&ide_lock);
blk_cleanup_queue(drive->queue);
device_unregister(&drive->gendev);
down(&drive->gendev_rel_sem);
- spin_lock_irq(&ide_lock);
drive->queue = NULL;
}
- if (hwif->next == hwif) {
- BUG_ON(hwgroup->hwif != hwif);
- kfree(hwgroup);
- } else {
- /* There is another interface in hwgroup.
- * Unlink us, and set hwgroup->drive and ->hwif to
- * something sane.
- */
- g = hwgroup->hwif;
- while (g->next != hwif)
- g = g->next;
- g->next = hwif->next;
- if (hwgroup->hwif == hwif) {
- /* Chose a random hwif for hwgroup->hwif.
- * It's guaranteed that there are no drives
- * left in the hwgroup.
+ /*
+ * Lock against hwgroup walkers including interrupts off other
+ * IDE devices wile we unhook ourselves.
+ */
+
+ spin_lock_irq(&ide_lock);
+
+ if (hwgroup)
+ {
+ if (hwif->next == hwif) {
+ BUG_ON(hwgroup->hwif != hwif);
+ kfree(hwgroup);
+ } else {
+ /* There is another interface in hwgroup.
+ * Unlink us, and set hwgroup->drive and ->hwif to
+ * something sane.
*/
- BUG_ON(hwgroup->drive != NULL);
- hwgroup->hwif = g;
+ g = hwgroup->hwif;
+ while (g->next != hwif)
+ g = g->next;
+ g->next = hwif->next;
+ if (hwgroup->hwif == hwif) {
+ /* Chose a random hwif for hwgroup->hwif.
+ * It's guaranteed that there are no drives
+ * left in the hwgroup.
+ */
+ BUG_ON(hwgroup->drive != NULL);
+ hwgroup->hwif = g;
+ }
+ BUG_ON(hwgroup->hwif == hwif);
}
- BUG_ON(hwgroup->hwif == hwif);
}
-
- /* More messed up locking ... */
spin_unlock_irq(&ide_lock);
- device_unregister(&hwif->gendev);
- down(&hwif->gendev_rel_sem);
+
+ /*
+ * PCI interfaces with no devices don't exist in the device
+ * tree so don't unregister them.
+ */
+
+ if(was_present)
+ {
+ device_unregister(&hwif->gendev);
+ down(&hwif->gendev_rel_sem);
+ }
/*
* Remove us from the kernel's knowledge
unregister_blkdev(hwif->major, hwif->name);
spin_lock_irq(&ide_lock);
+ /*
+ * Let the driver free up private objects
+ */
+
+ if(hwif->remove)
+ hwif->remove(hwif);
+
if (hwif->dma_base) {
(void) ide_release_dma(hwif);
hwif->dma_vendor3 = 0;
hwif->dma_prdtable = 0;
}
+ hwif->chipset = ide_unknown;
- old_hwif = *hwif;
+ /* copy original settings */
+ tmp_hwif = *hwif;
- init_hwif_data(hwif, index); /* restore hwif data to pristine status */
+ /* restore hwif data to pristine status */
+ init_hwif_data(hwif, index);
init_hwif_default(hwif, index);
- hwif->hwgroup = old_hwif.hwgroup;
+ hwif->configured = 0;
- hwif->gendev.parent = old_hwif.gendev.parent;
-
- hwif->proc = old_hwif.proc;
-
- hwif->major = old_hwif.major;
-// hwif->index = old_hwif.index;
-// hwif->channel = old_hwif.channel;
- hwif->straight8 = old_hwif.straight8;
- hwif->bus_state = old_hwif.bus_state;
-
- hwif->atapi_dma = old_hwif.atapi_dma;
- hwif->ultra_mask = old_hwif.ultra_mask;
- hwif->mwdma_mask = old_hwif.mwdma_mask;
- hwif->swdma_mask = old_hwif.swdma_mask;
-
- hwif->chipset = old_hwif.chipset;
- hwif->hold = old_hwif.hold;
-
-#ifdef CONFIG_BLK_DEV_IDEPCI
- hwif->pci_dev = old_hwif.pci_dev;
- hwif->cds = old_hwif.cds;
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-
-#if 0
- hwif->hwifops = old_hwif.hwifops;
-#else
- hwif->identify = old_hwif.identify;
- hwif->tuneproc = old_hwif.tuneproc;
- hwif->speedproc = old_hwif.speedproc;
- hwif->selectproc = old_hwif.selectproc;
- hwif->reset_poll = old_hwif.reset_poll;
- hwif->pre_reset = old_hwif.pre_reset;
- hwif->resetproc = old_hwif.resetproc;
- hwif->intrproc = old_hwif.intrproc;
- hwif->maskproc = old_hwif.maskproc;
- hwif->quirkproc = old_hwif.quirkproc;
- hwif->busproc = old_hwif.busproc;
-#endif
+ ide_hwif_restore(hwif, &tmp_hwif);
+
+ spin_unlock_irq(&ide_lock);
+ return 0;
-#if 0
- hwif->pioops = old_hwif.pioops;
-#else
- hwif->ata_input_data = old_hwif.ata_input_data;
- hwif->ata_output_data = old_hwif.ata_output_data;
- hwif->atapi_input_bytes = old_hwif.atapi_input_bytes;
- hwif->atapi_output_bytes = old_hwif.atapi_output_bytes;
-#endif
+abort:
+ if(hwif->configured)
+ {
+ printk("Unregister %d fail %d %d\n", index, drive->usage, DRIVER(drive)->busy);
+ ret = -EBUSY;
+ }
+ else
+ {
+ printk("No such hwif!\n");
+ ret = -ENOENT;
+ }
+ spin_unlock_irq(&ide_lock);
+ up(&ide_setting_sem);
+ return ret;
+}
-#if 0
- hwif->dmaops = old_hwif.dmaops;
-#else
- hwif->ide_dma_read = old_hwif.ide_dma_read;
- hwif->ide_dma_write = old_hwif.ide_dma_write;
- hwif->ide_dma_begin = old_hwif.ide_dma_begin;
- hwif->ide_dma_end = old_hwif.ide_dma_end;
- hwif->ide_dma_check = old_hwif.ide_dma_check;
- hwif->ide_dma_on = old_hwif.ide_dma_on;
- hwif->ide_dma_off_quietly = old_hwif.ide_dma_off_quietly;
- hwif->ide_dma_test_irq = old_hwif.ide_dma_test_irq;
- hwif->ide_dma_host_on = old_hwif.ide_dma_host_on;
- hwif->ide_dma_host_off = old_hwif.ide_dma_host_off;
- hwif->ide_dma_verbose = old_hwif.ide_dma_verbose;
- hwif->ide_dma_lostirq = old_hwif.ide_dma_lostirq;
- hwif->ide_dma_timeout = old_hwif.ide_dma_timeout;
-#endif
+EXPORT_SYMBOL_GPL(__ide_unregister_hwif);
-#if 0
- hwif->iops = old_hwif.iops;
-#else
- hwif->OUTB = old_hwif.OUTB;
- hwif->OUTBSYNC = old_hwif.OUTBSYNC;
- hwif->OUTW = old_hwif.OUTW;
- hwif->OUTL = old_hwif.OUTL;
- hwif->OUTSW = old_hwif.OUTSW;
- hwif->OUTSL = old_hwif.OUTSL;
-
- hwif->INB = old_hwif.INB;
- hwif->INW = old_hwif.INW;
- hwif->INL = old_hwif.INL;
- hwif->INSW = old_hwif.INSW;
- hwif->INSL = old_hwif.INSL;
-#endif
+/**
+ * ide_unregister_hwif - free an ide interface
+ * @hwif: interface to unregister
+ *
+ * Perform the final unregister of an IDE interface. At the moment
+ * we don't refcount interfaces so this will also get split up.
+ * Unregister restores the hwif structures to the default state.
+ *
+ * No locks should be held on entry. When an unregister must
+ * be done atomically with a register see __ide_unregister_hwif
+ * and hold the ide_cfg_sem yourself.
+ */
- hwif->mmio = old_hwif.mmio;
- hwif->rqsize = old_hwif.rqsize;
- hwif->no_lba48 = old_hwif.no_lba48;
-#ifndef CONFIG_BLK_DEV_IDECS
- hwif->irq = old_hwif.irq;
-#endif /* CONFIG_BLK_DEV_IDECS */
-
- hwif->dma_base = old_hwif.dma_base;
- hwif->dma_master = old_hwif.dma_master;
- hwif->dma_command = old_hwif.dma_command;
- hwif->dma_vendor1 = old_hwif.dma_vendor1;
- hwif->dma_status = old_hwif.dma_status;
- hwif->dma_vendor3 = old_hwif.dma_vendor3;
- hwif->dma_prdtable = old_hwif.dma_prdtable;
-
- hwif->dma_extra = old_hwif.dma_extra;
- hwif->config_data = old_hwif.config_data;
- hwif->select_data = old_hwif.select_data;
- hwif->autodma = old_hwif.autodma;
- hwif->udma_four = old_hwif.udma_four;
- hwif->no_dsc = old_hwif.no_dsc;
-
- hwif->hwif_data = old_hwif.hwif_data;
-abort:
- spin_unlock_irq(&ide_lock);
+int ide_unregister_hwif(ide_hwif_t *hwif)
+{
+ int ret;
+
+ /* This protects two things. Firstly it serializes the
+ shutdown sequence, secondly it protects us from
+ races while we are killing off a device */
+ down(&ide_cfg_sem);
+ ret = __ide_unregister_hwif(hwif);
up(&ide_cfg_sem);
+ return ret;
}
-EXPORT_SYMBOL(ide_unregister);
-
+EXPORT_SYMBOL_GPL(ide_unregister_hwif);
/**
* ide_setup_ports - set up IDE interface ports
*/
}
-EXPORT_SYMBOL(ide_setup_ports);
-
-/*
- * Register an IDE interface, specifying exactly the registers etc
- * Set init=1 iff calling before probes have taken place.
+/**
+ * ide_register_hw_with_fixup - register IDE interface
+ * @hw: hardware registers
+ * @hwifp: pointer to returned hwif
+ * @fixup function to call
+ *
+ * Register an IDE interface, specifying exactly the registers etc.
+ * Set init=1 iff calling before probes have taken place. The
+ * ide_cfg_sem protects this against races.
+ *
+ * Invokes a fixup function after the probe and before device attachment
+ * that can be used by the driver to amend settings or to work around
+ * hardware funnies.
+ *
+ * Returns -1 on error.
*/
-int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp)
+
+int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void (*fixup)(ide_hwif_t *hwif))
{
int index, retry = 1;
ide_hwif_t *hwif;
+ down(&ide_cfg_sem);
+
do {
for (index = 0; index < MAX_HWIFS; ++index) {
hwif = &ide_hwifs[index];
hwif = &ide_hwifs[index];
if (hwif->hold)
continue;
- if ((!hwif->present && !hwif->mate && !initializing) ||
+ if ((!hwif->configured && !hwif->mate && !initializing) ||
(!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
goto found;
}
+ /* FIXME- this check should die as should the retry loop */
for (index = 0; index < MAX_HWIFS; index++)
- ide_unregister(index);
+ {
+ hwif = &ide_hwifs[index];
+ __ide_unregister_hwif(hwif);
+ }
} while (retry--);
+
+ up(&ide_cfg_sem);
return -1;
found:
- if (hwif->present)
- ide_unregister(index);
+ /* FIXME: do we really need this case */
+ if (hwif->configured)
+ __ide_unregister_hwif(hwif);
else if (!hwif->hold) {
init_hwif_data(hwif, index);
init_hwif_default(hwif, index);
}
- if (hwif->present)
+ if (hwif->configured)
return -1;
+ hwif->configured = 1;
memcpy(&hwif->hw, hw, sizeof(*hw));
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
hwif->irq = hw->irq;
hwif->noprobe = 0;
hwif->chipset = hw->chipset;
+ up(&ide_cfg_sem);
if (!initializing) {
- probe_hwif_init(hwif);
+ probe_hwif_init_with_fixup(hwif, fixup);
create_proc_ide_interfaces();
}
return (initializing || hwif->present) ? index : -1;
}
+EXPORT_SYMBOL(ide_register_hw_with_fixup);
+
+/**
+ * ide_register_hw - register new IDE hardware
+ * @hw: hardware registers
+ * @hwifp: pointer to returned hwif
+ *
+ * Register an IDE interface, specifying exactly the registers etc.
+ * Set init=1 iff calling before probes have taken place. The
+ * ide_cfg_sem protects this against races.
+ *
+ * Returns -1 on error.
+ */
+
+int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwif)
+{
+ return ide_register_hw_with_fixup(hw, hwif, NULL);
+}
+
EXPORT_SYMBOL(ide_register_hw);
/*
*/
DECLARE_MUTEX(ide_setting_sem);
-EXPORT_SYMBOL(ide_setting_sem);
/**
* ide_add_setting - add an ide setting option
* @set: setting
*
* Removes the setting named from the device if it is present.
- * The function takes the settings_lock to protect against
- * parallel changes. This function must not be called from IRQ
- * context. Returns 0 on success or -1 on failure.
+ * This function must not be called from IRQ context. Returns 0
+ * on success or -1 on failure.
*
* BUGS: This code is seriously over-engineered. There is also
* magic about how the driver specific features are setup. If
* a driver is attached we assume the driver settings are auto
* remove.
+ *
+ * The caller must hold settings_lock
*/
int ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
{
ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
- down(&ide_setting_sem);
while ((*p) && strcmp((*p)->name, name) < 0)
p = &((*p)->next);
if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
if (drive->driver != &idedefault_driver)
setting->auto_remove = 1;
*p = setting;
- up(&ide_setting_sem);
return 0;
abort:
- up(&ide_setting_sem);
if (setting)
kfree(setting);
return -1;
EXPORT_SYMBOL(ide_add_setting);
/**
- * __ide_remove_setting - remove an ide setting option
+ * ide_remove_setting - remove an ide setting option
* @drive: drive to use
* @name: setting name
*
* The caller must hold the setting semaphore.
*/
-static void __ide_remove_setting (ide_drive_t *drive, char *name)
+static void ide_remove_setting (ide_drive_t *drive, char *name)
{
ide_settings_t **p, *setting;
kfree(setting);
}
-/**
- * ide_remove_setting - remove an ide setting option
- * @drive: drive to use
- * @name: setting name
- *
- * Removes the setting named from the device if it is present.
- * The function takes the settings_lock to protect against
- * parallel changes. This function must not be called from IRQ
- * context.
- */
-
-void ide_remove_setting (ide_drive_t *drive, char *name)
-{
- down(&ide_setting_sem);
- __ide_remove_setting(drive, name);
- up(&ide_setting_sem);
-}
-
-EXPORT_SYMBOL(ide_remove_setting);
-
/**
* ide_find_setting_by_ioctl - find a drive specific ioctl
* @drive: drive to scan
setting = drive->settings;
while (setting) {
if (setting->auto_remove) {
- __ide_remove_setting(drive, setting->name);
+ ide_remove_setting(drive, setting->name);
goto repeat;
}
setting = setting->next;
return val;
}
+/**
+ * ide_spin_wait_hwgroup - wait for group
+ * @drive: drive in the group
+ *
+ * Wait for an IDE device group to go non busy and then return
+ * holding the ide_lock which guards the hwgroup->busy status
+ * and right to use it.
+ */
+
int ide_spin_wait_hwgroup (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
* to the driver to change settings, and then wait on a sema for completion.
* The current scheme of polling is kludgy, though safe enough.
*/
+
int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
{
int i;
return 0;
}
-EXPORT_SYMBOL(ide_write_setting);
-
static int set_io_32bit(ide_drive_t *drive, int arg)
{
drive->io_32bit = arg;
return err;
}
-int ide_atapi_to_scsi (ide_drive_t *drive, int arg)
-{
- if (drive->media == ide_disk) {
- drive->scsi = 0;
- return 0;
- }
-
- if (DRIVER(drive)->cleanup(drive)) {
- drive->scsi = 0;
- return 0;
- }
-
- drive->scsi = (u8) arg;
- ata_attach(drive);
- return 0;
-}
+/**
+ * ide_add_generic_settings - generic ide settings
+ * @drive: drive being configured
+ *
+ * Add the generic parts of the system settings to the /proc files and
+ * ioctls for this IDE device. The caller must not be holding the
+ * ide_setting_sem.
+ */
void ide_add_generic_settings (ide_drive_t *drive)
{
+ down(&ide_setting_sem);
/*
* drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function
*/
ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL);
ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate);
ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL);
- if (drive->media != ide_disk)
- ide_add_setting(drive, "ide-scsi", SETTING_RW, -1, HDIO_SET_IDE_SCSI, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, ide_atapi_to_scsi);
+
+ up(&ide_setting_sem);
}
-/*
- * Delay for *at least* 50ms. As we don't know how much time is left
- * until the next tick occurs, we wait an extra tick to be safe.
- * This is used only during the probing/polling for drives at boot time.
+/**
+ * system_bus_clock - clock guess
*
- * However, its usefullness may be needed in other places, thus we export it now.
- * The future may change this to a millisecond setable delay.
+ * External version of the bus clock guess used by very old IDE drivers
+ * for things like VLB timings. Should not be used.
*/
-void ide_delay_50ms (void)
-{
-#ifndef CONFIG_BLK_DEV_IDECS
- mdelay(50);
-#else
- __set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1+HZ/20);
-#endif /* CONFIG_BLK_DEV_IDECS */
-}
-
-EXPORT_SYMBOL(ide_delay_50ms);
int system_bus_clock (void)
{
return 1;
}
-EXPORT_SYMBOL(ide_replace_subdriver);
+/**
+ * ata_attach - attach an ATA/ATAPI device
+ * @drive: drive to attach
+ *
+ * Takes a drive that is as yet not assigned to any midlayer IDE
+ * driver (or is assigned to the default driver) and figures out
+ * which driver would like to own it. If nobody claims the drive
+ * then it is automatically attached to the default driver used for
+ * unclaimed objects.
+ *
+ * A return of zero indicates attachment to a driver, of one
+ * attachment to the default driver.
+ *
+ * Takes the driver list lock and the ide_settings semaphore.
+ */
int ata_attach(ide_drive_t *drive)
{
struct list_head *p;
- spin_lock(&drivers_lock);
+ down(&drivers_sem);
+ down(&ide_setting_sem);
list_for_each(p, &drivers) {
ide_driver_t *driver = list_entry(p, ide_driver_t, drivers);
if (!try_module_get(driver->owner))
continue;
- spin_unlock(&drivers_lock);
if (driver->attach(drive) == 0) {
module_put(driver->owner);
drive->gendev.driver = &driver->gen_driver;
+ up(&ide_setting_sem);
+ up(&drivers_sem);
return 0;
}
- spin_lock(&drivers_lock);
module_put(driver->owner);
}
drive->gendev.driver = &idedefault_driver.gen_driver;
- spin_unlock(&drivers_lock);
+ up(&ide_setting_sem);
+ up(&drivers_sem);
if(idedefault_driver.attach(drive) != 0)
panic("ide: default attach failed");
return 1;
}
-EXPORT_SYMBOL(ata_attach);
-
static int generic_ide_suspend(struct device *dev, u32 state)
{
ide_drive_t *drive = dev->driver_data;
return ide_do_drive_cmd(drive, &rq, ide_head_wait);
}
-int generic_ide_ioctl(struct block_device *bdev, unsigned int cmd,
- unsigned long arg)
+int generic_ide_ioctl(struct file *file, struct block_device *bdev,
+ unsigned int cmd, unsigned long arg)
{
ide_drive_t *drive = bdev->bd_disk->private_data;
ide_settings_t *setting;
int err = 0;
+ void __user *p = (void __user *)arg;
down(&ide_setting_sem);
if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
if (cmd == setting->read_ioctl) {
err = ide_read_setting(drive, setting);
up(&ide_setting_sem);
- return err >= 0 ? put_user(err, (long *) arg) : err;
+ return err >= 0 ? put_user(err, (long __user *)arg) : err;
} else {
if (bdev != bdev->bd_contains)
err = -EINVAL;
switch (cmd) {
case HDIO_GETGEO:
{
- struct hd_geometry *loc = (struct hd_geometry *) arg;
- u16 bios_cyl = drive->bios_cyl; /* truncate */
- if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
- if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT;
- if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT;
- if (put_user(bios_cyl, (u16 *) &loc->cylinders)) return -EFAULT;
- if (put_user((unsigned)get_start_sect(bdev),
- (unsigned long *) &loc->start)) return -EFAULT;
+ struct hd_geometry geom;
+ if (!p || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+ geom.heads = drive->bios_head;
+ geom.sectors = drive->bios_sect;
+ geom.cylinders = (u16)drive->bios_cyl; /* truncate */
+ geom.start = get_start_sect(bdev);
+ if (copy_to_user(p, &geom, sizeof(struct hd_geometry)))
+ return -EFAULT;
return 0;
}
return -EINVAL;
if (drive->id_read == 0)
return -ENOMSG;
- if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
+ if (copy_to_user(p, drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
return -EFAULT;
return 0;
drive->nice0 << IDE_NICE_0 |
drive->nice1 << IDE_NICE_1 |
drive->nice2 << IDE_NICE_2,
- (long *) arg);
+ (long __user *) arg);
#ifdef CONFIG_IDE_TASK_IOCTL
case HDIO_DRIVE_TASKFILE:
case HDIO_SCAN_HWIF:
{
hw_regs_t hw;
+ ide_hwif_t *hwif;
int args[3];
if (!capable(CAP_SYS_RAWIO)) return -EACCES;
- if (copy_from_user(args, (void *)arg, 3 * sizeof(int)))
+ if (copy_from_user(args, p, 3 * sizeof(int)))
return -EFAULT;
memset(&hw, 0, sizeof(hw));
ide_init_hwif_ports(&hw, (unsigned long) args[0],
(unsigned long) args[1], NULL);
hw.irq = args[2];
- if (ide_register_hw(&hw, NULL) == -1)
+ if (ide_register_hw(&hw, &hwif) == -1)
return -EIO;
+ hwif->user_dev = 1;
return 0;
}
case HDIO_UNREGISTER_HWIF:
if (!capable(CAP_SYS_RAWIO)) return -EACCES;
- /* (arg > MAX_HWIFS) checked in function */
- ide_unregister(arg);
+ if(arg > MAX_HWIFS || arg < 0)
+ return -EINVAL;
+ if(!ide_hwifs[arg].user_dev)
+ return -EINVAL;
+ return ide_unregister_hwif(&ide_hwifs[arg]);
return 0;
case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
case CDROMEJECT:
case CDROMCLOSETRAY:
- return scsi_cmd_ioctl(bdev->bd_disk, cmd, arg);
+ return scsi_cmd_ioctl(file, bdev->bd_disk, cmd, p);
case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (put_user(HWIF(drive)->bus_state, (long *)arg))
+ if (put_user(HWIF(drive)->bus_state, (long __user *)arg))
return -EFAULT;
return 0;
if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
const char *hd_words[] = {
"none", "noprobe", "nowerr", "cdrom", "serialize",
- "autotune", "noautotune", "minus8", "swapdata", "bswap",
+ "autotune", "noautotune", "stroke", "swapdata", "bswap",
"minus11", "remap", "remap63", "scsi", NULL };
unit = s[2] - 'a';
hw = unit / MAX_DRIVES;
case -7: /* "noautotune" */
drive->autotune = IDE_TUNE_NOAUTO;
goto done;
+ case -8: /* stroke */
+ drive->stroke = 1;
+ goto done;
case -9: /* "swapdata" */
case -10: /* "bswap" */
drive->bswap = 1;
return 1;
}
+extern void pnpide_init(void);
+extern void h8300_ide_init(void);
+
/*
* probe_for_hwifs() finds/initializes "known" IDE interfaces
*/
pmac_ide_probe();
}
#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#ifdef CONFIG_BLK_DEV_IDE_SWARM
- {
- extern void swarm_ide_probe(void);
- swarm_ide_probe();
- }
-#endif /* CONFIG_BLK_DEV_IDE_SWARM */
#ifdef CONFIG_BLK_DEV_GAYLE
{
extern void gayle_init(void);
buddha_init();
}
#endif /* CONFIG_BLK_DEV_BUDDHA */
-#if defined(CONFIG_BLK_DEV_IDEPNP) && defined(CONFIG_PNP)
- {
- extern void pnpide_init(int enable);
- pnpide_init(1);
- }
-#endif /* CONFIG_BLK_DEV_IDEPNP */
+#ifdef CONFIG_BLK_DEV_IDEPNP
+ pnpide_init();
+#endif
+#ifdef CONFIG_H8300
+ h8300_ide_init();
+#endif
}
/*
drive->suspend_reset = 0;
#ifdef CONFIG_PROC_FS
if (drive->driver != &idedefault_driver) {
- ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
- ide_add_proc_entries(drive->proc, driver->proc, drive);
+ ide_add_proc_entries(drive->proc, generic_subdriver_entries, ide_drive_to_key(drive));
+ ide_add_proc_entries(drive->proc, driver->proc, ide_drive_to_key(drive));
}
#endif
return 0;
EXPORT_SYMBOL(ide_register_subdriver);
+/**
+ * ide_unregister_subdriver - disconnect drive from driver
+ * @drive: drive to unplug
+ *
+ * Disconnect a drive from the driver it was attached to and then
+ * clean up the various proc files and other objects attached to it.
+ *
+ * Takes ide_setting_sem, ide_lock and drives_lock.
+ * Caller must hold none of the locks.
+ *
+ * No locking versus subdriver unload because we are moving to the
+ * default driver anyway. Wants double checking.
+ */
+
int ide_unregister_subdriver (ide_drive_t *drive)
{
unsigned long flags;
+ ide_proc_entry_t *dir;
down(&ide_setting_sem);
spin_lock_irqsave(&ide_lock, flags);
up(&ide_setting_sem);
return 1;
}
-#if defined(CONFIG_BLK_DEV_IDEPNP) && defined(CONFIG_PNP) && defined(MODULE)
- pnpide_init(0);
-#endif /* CONFIG_BLK_DEV_IDEPNP */
+ dir = DRIVER(drive)->proc;
+ drive->driver = &idedefault_driver;
+ spin_unlock_irqrestore(&ide_lock, flags);
#ifdef CONFIG_PROC_FS
- ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
+ ide_remove_proc_entries(drive->proc, dir);
ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
#endif
auto_remove_settings(drive);
- drive->driver = &idedefault_driver;
- spin_unlock_irqrestore(&ide_lock, flags);
up(&ide_setting_sem);
spin_lock(&drives_lock);
list_del_init(&drive->list);
return 0;
}
+/**
+ * ide_register_driver - register IDE device driver
+ * @driver: the IDE device driver
+ *
+ * Register a new device driver and then scan the devices
+ * on the IDE bus in case any should be attached to the
+ * driver we have just registered. If so attach them.
+ *
+ * Takes the drivers and drives lock. Should take the
+ * ide_sem but doesn't - FIXME ??
+ */
+
int ide_register_driver(ide_driver_t *driver)
{
struct list_head list;
setup_driver_defaults(driver);
+ down(&drivers_sem);
spin_lock(&drivers_lock);
list_add(&driver->drivers, &drivers);
spin_unlock(&drivers_lock);
+ up(&drivers_sem);
INIT_LIST_HEAD(&list);
spin_lock(&drives_lock);
EXPORT_SYMBOL(ide_register_driver);
+/**
+ * ide_unregister_driver - unregister IDE device driver
+ * @driver: the IDE device driver
+ *
+ * Called when a driver module is being unloaded. We reattach any
+ * devices to whatever driver claims them next (typically the default
+ * driver).
+ *
+ * Takes drivers_lock and called functions will take ide_setting_sem.
+ */
+
void ide_unregister_driver(ide_driver_t *driver)
{
ide_drive_t *drive;
+ down(&drivers_sem);
spin_lock(&drivers_lock);
list_del(&driver->drivers);
spin_unlock(&drivers_lock);
+ up(&drivers_sem);
driver_unregister(&driver->gen_driver);
init_ide_data();
#ifdef CONFIG_PROC_FS
- proc_ide_root = proc_mkdir("ide", 0);
+ proc_ide_root = proc_mkdir("ide", NULL);
#endif
#ifdef CONFIG_BLK_DEV_ALI14XX
int index;
for (index = 0; index < MAX_HWIFS; ++index) {
- ide_unregister(index);
+ if(ide_unregister_hwif(&ide_hwifs[index]))
+ printk(KERN_ERR "ide: unload yet busy!\n");
if (ide_hwifs[index].dma_base)
(void) ide_release_dma(&ide_hwifs[index]);
}