#include <linux/cdrom.h>
#include <linux/seq_file.h>
#include <linux/device.h>
-#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm/bitops.h>
/* default maximum number of failures */
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
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
}
+/*
+ * 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
*
int ide_system_bus_speed (void)
{
- static struct pci_device_id pci_default[] = {
- { PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID) },
- { }
- };
-
if (!system_bus_speed) {
if (idebus_parameter) {
/* user supplied value */
system_bus_speed = idebus_parameter;
- } else if (pci_dev_present(pci_default)) {
+ } else if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) != NULL) {
/* safe default value for PCI */
system_bus_speed = 33;
} else {
}
/*
- * drives_lock protects the list of drives, drivers_lock the
- * list of drivers. Currently nobody takes both at once.
+ * 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);
{
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);
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)
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->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->dma_setup = tmp_hwif->dma_setup;
- hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd;
- hwif->dma_start = tmp_hwif->dma_start;
+ 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_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->INSW = tmp_hwif->INSW;
hwif->INSL = tmp_hwif->INSL;
- hwif->sg_max_nents = tmp_hwif->sg_max_nents;
-
hwif->mmio = tmp_hwif->mmio;
hwif->rqsize = tmp_hwif->rqsize;
hwif->no_lba48 = tmp_hwif->no_lba48;
}
/**
- * 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;
-
- BUG_ON(index >= MAX_HWIFS);
+ int was_present;
+ int ret = 0;
+ int index = hwif->index;
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];
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
hwif->drives[i].disk = NULL;
put_disk(disk);
}
- kfree(hwif->sg_table);
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;
/* copy original settings */
tmp_hwif = *hwif;
init_hwif_data(hwif, index);
init_hwif_default(hwif, index);
+ hwif->configured = 0;
+
ide_hwif_restore(hwif, &tmp_hwif);
+
+ spin_unlock_irq(&ide_lock);
+ return 0;
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_cfg_sem);
+ up(&ide_setting_sem);
+ return ret;
}
-EXPORT_SYMBOL(ide_unregister);
+EXPORT_SYMBOL_GPL(__ide_unregister_hwif);
+/**
+ * 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.
+ */
+
+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_GPL(ide_unregister_hwif);
/**
* ide_setup_ports - set up IDE interface ports
* ide_register_hw_with_fixup - register IDE interface
* @hw: hardware registers
* @hwifp: pointer to returned hwif
- * @fixup: fixup function
+ * @fixup function to call
*
* Register an IDE interface, specifying exactly the registers etc.
- * Set init=1 iff calling before probes have taken place.
+ * 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_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif))
+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_with_fixup(hwif, fixup);
EXPORT_SYMBOL(ide_register_hw_with_fixup);
-int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
+/**
+ * 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, hwifp, NULL);
+ return ide_register_hw_with_fixup(hw, hwif, NULL);
}
EXPORT_SYMBOL(ide_register_hw);
* @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;
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;
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);
+
+ up(&ide_setting_sem);
}
/**
* A return of zero indicates attachment to a driver, of one
* attachment to the default driver.
*
- * Takes drivers_lock.
+ * 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;
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, p, 3 * sizeof(int)))
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;
return 0; /* zero = nothing matched */
}
+#ifdef CONFIG_BLK_DEV_PDC4030
+static int __initdata probe_pdc4030;
+#endif
#ifdef CONFIG_BLK_DEV_ALI14XX
static int __initdata probe_ali14xx;
extern int ali14xx_init(void);
#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
if (!strcmp(s, "ide=nodma")) {
- printk(" : Prevented DMA\n");
+ printk("IDE: Prevented DMA\n");
noautodma = 1;
return 1;
}
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;
goto do_serialize;
case -6: /* "autotune" */
drive->autotune = IDE_TUNE_AUTO;
- goto obsolete_option;
+ goto done;
case -7: /* "noautotune" */
drive->autotune = IDE_TUNE_NOAUTO;
- goto obsolete_option;
+ goto done;
+ case -8: /* stroke */
+ drive->stroke = 1;
+ goto done;
case -9: /* "swapdata" */
case -10: /* "bswap" */
drive->bswap = 1;
"noprobe", "serialize", "autotune", "noautotune",
"reset", "dma", "ata66", "minus8", "minus9",
"minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb",
- "dtc2278", "umc8672", "ali14xx", NULL };
+ "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
hw = s[3] - '0';
hwif = &ide_hwifs[hw];
i = match_parm(&s[4], ide_words, vals, 3);
}
switch (i) {
+#ifdef CONFIG_BLK_DEV_PDC4030
+ case -18: /* "dc4030" */
+ probe_pdc4030 = 1;
+ goto done;
+#endif
#ifdef CONFIG_BLK_DEV_ALI14XX
case -17: /* "ali14xx" */
probe_ali14xx = 1;
case -7: /* ata66 */
#ifdef CONFIG_BLK_DEV_IDEPCI
hwif->udma_four = 1;
- goto obsolete_option;
+ goto done;
#else
goto bad_hwif;
#endif
case -6: /* dma */
hwif->autodma = 1;
- goto obsolete_option;
+ goto done;
case -5: /* "reset" */
hwif->reset = 1;
- goto obsolete_option;
+ goto done;
case -4: /* "noautotune" */
hwif->drives[0].autotune = IDE_TUNE_NOAUTO;
hwif->drives[1].autotune = IDE_TUNE_NOAUTO;
- goto obsolete_option;
+ goto done;
case -3: /* "autotune" */
hwif->drives[0].autotune = IDE_TUNE_AUTO;
hwif->drives[1].autotune = IDE_TUNE_AUTO;
- goto obsolete_option;
+ goto done;
case -2: /* "serialize" */
do_serialize:
hwif->mate = &ide_hwifs[hw^1];
hwif->mate->mate = hwif;
hwif->serialized = hwif->mate->serialized = 1;
- goto obsolete_option;
+ goto done;
case -1: /* "noprobe" */
hwif->noprobe = 1;
hwif->irq = vals[2];
hwif->noprobe = 0;
hwif->chipset = ide_forced;
- goto obsolete_option;
+ goto done;
case 0: goto bad_option;
default:
bad_option:
printk(" -- BAD OPTION\n");
return 1;
-obsolete_option:
- printk(" -- OBSOLETE OPTION, WILL BE REMOVED SOON!\n");
- return 1;
bad_hwif:
printk("-- NOT SUPPORTED ON ide%d", hw);
done:
ide_probe_for_cmd640x();
}
#endif /* CONFIG_BLK_DEV_CMD640 */
+#ifdef CONFIG_BLK_DEV_PDC4030
+ {
+ extern int pdc4030_init(void);
+ if (probe_pdc4030)
+ (void)pdc4030_init();
+ }
+#endif /* CONFIG_BLK_DEV_PDC4030 */
#ifdef CONFIG_BLK_DEV_IDE_PMAC
{
extern void pmac_ide_probe(void);
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;
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;
}
+ 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);
* on the IDE bus in case any should be attached to the
* driver we have just registered. If so attach them.
*
- * Takes drivers_lock and drives_lock.
+ * Takes the drivers and drives lock. Should take the
+ * ide_sem but doesn't - FIXME ??
*/
int ide_register_driver(ide_driver_t *driver)
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);
{
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);
#ifdef MODULE
char *options = NULL;
-module_param(options, charp, 0);
+MODULE_PARM(options,"s");
MODULE_LICENSE("GPL");
static void __init parse_options (char *line)
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]);
}