#define _IDE_C /* Tell ide.h it's really us */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ide.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/completion.h>
#include <linux/reboot.h>
#include <linux/cdrom.h>
hwif->mwdma_mask = 0x80; /* disable all mwdma */
hwif->swdma_mask = 0x80; /* disable all swdma */
- sema_init(&hwif->gendev_rel_sem, 0);
+ init_completion(&hwif->gendev_rel_comp);
default_hwif_iops(hwif);
default_hwif_transport(hwif);
drive->name[2] = 'a' + (index * MAX_DRIVES) + unit;
drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
drive->using_dma = 0;
- drive->is_flash = 0;
drive->vdma = 0;
INIT_LIST_HEAD(&drive->list);
- sema_init(&drive->gendev_rel_sem, 0);
+ init_completion(&drive->gendev_rel_comp);
}
}
* @hwif: hwif to update
* @tmp_hwif: template
*
- * Restore hwif to a previous state by copying most settngs
+ * Restore hwif to a previous state by copying most settings
* from the template.
*/
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_clear_irq = tmp_hwif->ide_dma_clear_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_lostirq = tmp_hwif->ide_dma_lostirq;
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->extra_base = tmp_hwif->extra_base;
+ hwif->extra_ports = tmp_hwif->extra_ports;
hwif->autodma = tmp_hwif->autodma;
hwif->udma_four = tmp_hwif->udma_four;
hwif->no_dsc = tmp_hwif->no_dsc;
}
/**
- * ide_unregister - free an ide interface
+ * ide_unregister - free an IDE interface
* @index: index of interface (will change soon to a pointer)
*
* Perform the final unregister of an IDE interface. At the moment
* 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 interfce will not be reopened (present/vanishing locking
- * isnt yet done btw). After we commit to the final kill we
+ * 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.
goto abort;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
- if (!drive->present) {
- if (drive->devfs_name[0] != '\0') {
- devfs_remove(drive->devfs_name);
- drive->devfs_name[0] = '\0';
- }
+ if (!drive->present)
continue;
- }
spin_unlock_irq(&ide_lock);
device_unregister(&drive->gendev);
- down(&drive->gendev_rel_sem);
+ wait_for_completion(&drive->gendev_rel_comp);
spin_lock_irq(&ide_lock);
}
hwif->present = 0;
/* More messed up locking ... */
spin_unlock_irq(&ide_lock);
device_unregister(&hwif->gendev);
- down(&hwif->gendev_rel_sem);
+ wait_for_completion(&hwif->gendev_rel_comp);
/*
* Remove us from the kernel's knowledge
hwif->dma_status = 0;
hwif->dma_vendor3 = 0;
hwif->dma_prdtable = 0;
+
+ hwif->extra_base = 0;
+ hwif->extra_ports = 0;
}
/* copy original settings */
{
int i;
+ memset(hw, 0, sizeof(hw_regs_t));
for (i = 0; i < IDE_NR_PORTS; i++) {
if (offsets[i] == -1) {
switch(i) {
hwif->irq = hw->irq;
hwif->noprobe = 0;
hwif->chipset = hw->chipset;
+ hwif->gendev.parent = hw->dev;
if (!initializing) {
probe_hwif_init_with_fixup(hwif, fixup);
down(&ide_setting_sem);
while ((*p) && strcmp((*p)->name, name) < 0)
p = &((*p)->next);
- if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
+ if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
goto abort;
- memset(setting, 0, sizeof(*setting));
if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
goto abort;
strcpy(setting->name, name);
return 0;
abort:
up(&ide_setting_sem);
- if (setting)
- kfree(setting);
+ kfree(setting);
return -1;
}
* @drive: drive
*
* Automatically remove all the driver specific settings for this
- * drive. This function may sleep and must not be called from IRQ
- * context. The caller must hold ide_setting_sem.
+ * drive. This function may not be called from IRQ context. The
+ * caller must hold ide_setting_sem.
*/
static void auto_remove_settings (ide_drive_t *drive)
EXPORT_SYMBOL(system_bus_clock);
-static int generic_ide_suspend(struct device *dev, pm_message_t state)
+static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
{
ide_drive_t *drive = dev->driver_data;
struct request rq;
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
- rq.flags = REQ_PM_SUSPEND;
+ rq.cmd_type = REQ_TYPE_PM_SUSPEND;
rq.special = &args;
- rq.pm = &rqpm;
+ rq.data = &rqpm;
rqpm.pm_step = ide_pm_state_start_suspend;
- rqpm.pm_state = state;
+ if (mesg.event == PM_EVENT_PRETHAW)
+ mesg.event = PM_EVENT_FREEZE;
+ rqpm.pm_state = mesg.event;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
- rq.flags = REQ_PM_RESUME;
+ rq.cmd_type = REQ_TYPE_PM_RESUME;
rq.special = &args;
- rq.pm = &rqpm;
+ rq.data = &rqpm;
rqpm.pm_step = ide_pm_state_start_resume;
- rqpm.pm_state = 0;
+ rqpm.pm_state = PM_EVENT_ON;
return ide_do_drive_cmd(drive, &rq, ide_head_wait);
}
up(&ide_setting_sem);
switch (cmd) {
- case HDIO_GETGEO:
- {
- 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;
- }
-
case HDIO_OBSOLETE_IDENTITY:
case HDIO_GET_IDENTITY:
if (bdev != bdev->bd_contains)
spin_lock_irqsave(&ide_lock, flags);
+ if (HWGROUP(drive)->resetting) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return -EBUSY;
+ }
+
ide_abort(drive, "drive reset");
- if(HWGROUP(drive)->handler)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler);
/* Ensure nothing gets queued after we
drop the lock. Reset will clear the busy */
const char *hd_words[] = {
"none", "noprobe", "nowerr", "cdrom", "serialize",
"autotune", "noautotune", "minus8", "swapdata", "bswap",
- "minus11", "remap", "remap63", "scsi", NULL };
+ "noflush", "remap", "remap63", "scsi", NULL };
unit = s[2] - 'a';
hw = unit / MAX_DRIVES;
unit = unit % MAX_DRIVES;
case -10: /* "bswap" */
drive->bswap = 1;
goto done;
+ case -11: /* noflush */
+ drive->noflush = 1;
+ goto done;
case -12: /* "remap" */
drive->remap_0_to_1 = 1;
goto done;
return 1;
}
-extern void pnpide_init(void);
-extern void h8300_ide_init(void);
+extern void __init pnpide_init(void);
+extern void __exit pnpide_exit(void);
+extern void __init h8300_ide_init(void);
/*
* probe_for_hwifs() finds/initializes "known" IDE interfaces
{
unsigned long flags;
- down(&ide_setting_sem);
- spin_lock_irqsave(&ide_lock, flags);
#ifdef CONFIG_PROC_FS
ide_remove_proc_entries(drive->proc, driver->proc);
#endif
+ down(&ide_setting_sem);
+ spin_lock_irqsave(&ide_lock, flags);
+ /*
+ * ide_setting_sem protects the settings list
+ * ide_lock protects the use of settings
+ *
+ * so we need to hold both, ide_settings_sem because we want to
+ * modify the settings list, and ide_lock because we cannot take
+ * a setting out that is being used.
+ *
+ * OTOH both ide_{read,write}_setting are only ever used under
+ * ide_setting_sem.
+ */
auto_remove_settings(drive);
spin_unlock_irqrestore(&ide_lock, flags);
up(&ide_setting_sem);
return 1;
}
+static char *media_string(ide_drive_t *drive)
+{
+ switch (drive->media) {
+ case ide_disk:
+ return "disk";
+ case ide_cdrom:
+ return "cdrom";
+ case ide_tape:
+ return "tape";
+ case ide_floppy:
+ return "floppy";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static ssize_t media_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "%s\n", media_string(drive));
+}
+
+static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "%s\n", drive->name);
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "ide:m-%s\n", media_string(drive));
+}
+
+static struct device_attribute ide_dev_attrs[] = {
+ __ATTR_RO(media),
+ __ATTR_RO(drivename),
+ __ATTR_RO(modalias),
+ __ATTR_NULL
+};
+
+static int ide_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ int i = 0;
+ int length = 0;
+
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "MEDIA=%s", media_string(drive));
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "DRIVENAME=%s", drive->name);
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "MODALIAS=ide:m-%s", media_string(drive));
+ envp[i] = NULL;
+ return 0;
+}
+
+static int generic_ide_probe(struct device *dev)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ ide_driver_t *drv = to_ide_driver(dev->driver);
+
+ return drv->probe ? drv->probe(drive) : -ENODEV;
+}
+
+static int generic_ide_remove(struct device *dev)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ ide_driver_t *drv = to_ide_driver(dev->driver);
+
+ if (drv->remove)
+ drv->remove(drive);
+
+ return 0;
+}
+
+static void generic_ide_shutdown(struct device *dev)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ ide_driver_t *drv = to_ide_driver(dev->driver);
+
+ if (dev->driver && drv->shutdown)
+ drv->shutdown(drive);
+}
+
struct bus_type ide_bus_type = {
.name = "ide",
.match = ide_bus_match,
+ .uevent = ide_uevent,
+ .probe = generic_ide_probe,
+ .remove = generic_ide_remove,
+ .shutdown = generic_ide_shutdown,
+ .dev_attrs = ide_dev_attrs,
.suspend = generic_ide_suspend,
.resume = generic_ide_resume,
};
*/
static int __init ide_init(void)
{
+ int ret;
+
printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
- devfs_mk_dir("ide");
system_bus_speed = ide_system_bus_speed();
- bus_register(&ide_bus_type);
+ ret = bus_register(&ide_bus_type);
+ if (ret < 0) {
+ printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
+ return ret;
+ }
init_ide_data();
}
}
-int init_module (void)
+int __init init_module (void)
{
parse_options(options);
return ide_init();
}
-void cleanup_module (void)
+void __exit cleanup_module (void)
{
int index;
for (index = 0; index < MAX_HWIFS; ++index)
ide_unregister(index);
+#ifdef CONFIG_BLK_DEV_IDEPNP
+ pnpide_exit();
+#endif
+
#ifdef CONFIG_PROC_FS
proc_ide_destroy();
#endif
- devfs_remove("ide");
bus_unregister(&ide_bus_type);
}