Commit 179b6179 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] update ide.c

Remove ide_ioreg_t
Add locking on the ide setting lists
parent 15e51b0a
...@@ -833,8 +833,8 @@ EXPORT_SYMBOL(ide_unregister); ...@@ -833,8 +833,8 @@ EXPORT_SYMBOL(ide_unregister);
*/ */
void ide_setup_ports ( hw_regs_t *hw, void ide_setup_ports ( hw_regs_t *hw,
ide_ioreg_t base, int *offsets, unsigned long base, int *offsets,
ide_ioreg_t ctrl, ide_ioreg_t intr, unsigned long ctrl, unsigned long intr,
ide_ack_intr_t *ack_intr, ide_ack_intr_t *ack_intr,
/* /*
* ide_io_ops_t *iops, * ide_io_ops_t *iops,
...@@ -930,38 +930,52 @@ EXPORT_SYMBOL(ide_register_hw); ...@@ -930,38 +930,52 @@ EXPORT_SYMBOL(ide_register_hw);
int ide_register (int arg1, int arg2, int irq) int ide_register (int arg1, int arg2, int irq)
{ {
hw_regs_t hw; hw_regs_t hw;
ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL); ide_init_hwif_ports(&hw, (unsigned long) arg1, (unsigned long) arg2, NULL);
hw.irq = irq; hw.irq = irq;
return ide_register_hw(&hw, NULL); return ide_register_hw(&hw, NULL);
} }
EXPORT_SYMBOL(ide_register); EXPORT_SYMBOL(ide_register);
/*
* Locks for IDE setting functionality
*/
DECLARE_MUTEX(ide_setting_sem);
EXPORT_SYMBOL(ide_setting_sem);
/** /**
* ide_add_setting - attach an IDE setting * ide_add_setting - add an ide setting option
* drive: drive the setting is for * @drive: drive to use
* name: name of setting * @name: setting name
* rw: set if writable * @rw: true if the function is read write
* read_ioctl: read function * @read_ioctl: function to call on read
* write_ioctl: write function * @write_ioctl: function to call on write
* data_type: form expected * @data_type: type of data
* min: minimum * @min: range minimum
* max: maximum * @max: range maximum
* mul_factor: multiply by * @mul_factor: multiplication scale
* div_factor: divide by * @div_factor: divison scale
* data: value * @data: private data field
* set: handling for setting * @set: setting
* *
* Add a setting to the IDE drive. Support automatic removal and allow * Removes the setting named from the device if it is present.
* all the work to be done by plugged in handlers. This code is also * The function takes the settings_lock to protect against
* rather short on locking, but the current plan is to do the locking * parallel changes. This function must not be called from IRQ
* internally to the function. * 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.
*/ */
void 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) 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; ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
down(&ide_setting_sem);
while ((*p) && strcmp((*p)->name, name) < 0) while ((*p) && strcmp((*p)->name, name) < 0)
p = &((*p)->next); p = &((*p)->next);
if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL) if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
...@@ -980,49 +994,76 @@ void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioc ...@@ -980,49 +994,76 @@ void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioc
setting->div_factor = div_factor; setting->div_factor = div_factor;
setting->data = data; setting->data = data;
setting->set = set; setting->set = set;
setting->next = *p; setting->next = *p;
if (drive->driver) if (drive->driver)
setting->auto_remove = 1; setting->auto_remove = 1;
*p = setting; *p = setting;
return; up(&ide_setting_sem);
return 0;
abort: abort:
up(&ide_setting_sem);
if (setting) if (setting)
kfree(setting); kfree(setting);
return -1;
} }
EXPORT_SYMBOL(ide_add_setting); EXPORT_SYMBOL(ide_add_setting);
/** /**
* ide_remove_setting - remove an ioctl setting * __ide_remove_setting - remove an ide setting option
* @name: name of the property * @drive: drive to use
* @name: setting name
* *
* Remove a drive ioctl setting that was created by ide_add_setting. * Removes the setting named from the device if it is present.
* Again this needs the locking fixed * The caller must hold the setting semaphore.
*/ */
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 = (ide_settings_t **) &drive->settings, *setting; ide_settings_t **p, *setting;
p = (ide_settings_t **) &drive->settings;
while ((*p) && strcmp((*p)->name, name)) while ((*p) && strcmp((*p)->name, name))
p = &((*p)->next); p = &((*p)->next);
if ((setting = (*p)) == NULL) if ((setting = (*p)) == NULL)
return; return;
(*p) = setting->next; (*p) = setting->next;
kfree(setting->name); kfree(setting->name);
kfree(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); EXPORT_SYMBOL(ide_remove_setting);
/** /**
* ide_find_setting_by_ioctl - find a setting handler by its command * ide_find_setting_by_ioctl - find a drive specific ioctl
* @drive: drive to act for * @drive: drive to scan
* @cmd: ioctl command code * @cmd: ioctl command to handle
* *
* Scan the drive handlers for an ioctl handler for this function. * Scan's the device setting table for a matching entry and returns
* The handlers vary by drive and sometimes by drive state. * this or NULL if no entry is found. The caller must hold the
* Needs locking fixes. * setting semaphore
*/ */
static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd) static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
...@@ -1034,17 +1075,18 @@ static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd) ...@@ -1034,17 +1075,18 @@ static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
break; break;
setting = setting->next; setting = setting->next;
} }
return setting; return setting;
} }
/** /**
* ide_find_setting_by_name - find a setting handler by its name * ide_find_setting_by_name - find a drive specific setting
* @drive: drive to act for * @drive: drive to scan
* @cmd: ioctl command code * @name: setting name
* *
* Scan the drive handlers handler matching the name for this function. * Scan's the device setting table for a matching entry and returns
* The handlers vary by drive and sometimes by drive state. * this or NULL if no entry is found. The caller must hold the
* Needs locking fixes. * setting semaphore
*/ */
ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name) ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
...@@ -1060,30 +1102,43 @@ ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name) ...@@ -1060,30 +1102,43 @@ ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
} }
/** /**
* auto_remove_settings - remove driver settings on a device * auto_remove_settings - remove driver specific settings
* @drive: drive to clean * @drive: drive
* *
* Called when we change the driver bindings for a device, for * Automatically remove all the driver specific settings for this
* example if the device is hot plugged. We must scrub the driver * drive. This function may sleep and must not be called from IRQ
* bindings that are thus no longer relevant to the device in case * context. Takes the settings_lock
* it changes from say a CD-ROM to a disk
* Needs locking fixes
*/ */
static void auto_remove_settings (ide_drive_t *drive) static void auto_remove_settings (ide_drive_t *drive)
{ {
ide_settings_t *setting; ide_settings_t *setting;
down(&ide_setting_sem);
repeat: repeat:
setting = drive->settings; setting = drive->settings;
while (setting) { while (setting) {
if (setting->auto_remove) { if (setting->auto_remove) {
ide_remove_setting(drive, setting->name); __ide_remove_setting(drive, setting->name);
goto repeat; goto repeat;
} }
setting = setting->next; setting = setting->next;
} }
up(&ide_setting_sem);
} }
/**
* ide_read_setting - read an IDE setting
* @drive: drive to read from
* @setting: drive setting
*
* Read a drive setting and return the value. The caller
* must hold the ide_setting_sem when making this call.
*
* BUGS: the data return and error are the same return value
* so an error -EINVAL and true return of the same value cannot
* be told apart
*/
int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting) int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
{ {
int val = -EINVAL; int val = -EINVAL;
...@@ -1132,10 +1187,22 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive) ...@@ -1132,10 +1187,22 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive)
EXPORT_SYMBOL(ide_spin_wait_hwgroup); EXPORT_SYMBOL(ide_spin_wait_hwgroup);
/* /**
* FIXME: This should be changed to enqueue a special request * ide_write_setting - read an IDE setting
* to the driver to change settings, and then wait on a sema for completion. * @drive: drive to read from
* The current scheme of polling is kludgey, though safe enough. * @setting: drive setting
* @val: value
*
* Write a drive setting if it is possible. The caller
* must hold the ide_setting_sem when making this call.
*
* BUGS: the data return and error are the same return value
* so an error -EINVAL and true return of the same value cannot
* be told apart
*
* FIXME: This should be changed to enqueue a special request
* 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 ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
{ {
...@@ -1360,16 +1427,22 @@ int generic_ide_ioctl(struct block_device *bdev, unsigned int cmd, ...@@ -1360,16 +1427,22 @@ int generic_ide_ioctl(struct block_device *bdev, unsigned int cmd,
ide_settings_t *setting; ide_settings_t *setting;
int err = 0; int err = 0;
down(&ide_setting_sem);
if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) { if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
if (cmd == setting->read_ioctl) { if (cmd == setting->read_ioctl) {
err = ide_read_setting(drive, setting); 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 *) arg) : err;
} else { } else {
if (bdev != bdev->bd_contains) if (bdev != bdev->bd_contains)
return -EINVAL; err = -EINVAL;
return ide_write_setting(drive, setting, arg); else
err = ide_write_setting(drive, setting, arg);
up(&ide_setting_sem);
return err;
} }
} }
up(&ide_setting_sem);
switch (cmd) { switch (cmd) {
case HDIO_GETGEO: case HDIO_GETGEO:
...@@ -1976,7 +2049,7 @@ int __init ide_setup (char *s) ...@@ -1976,7 +2049,7 @@ int __init ide_setup (char *s)
vals[2] = 0; /* default irq = probe for it */ vals[2] = 0; /* default irq = probe for it */
case 3: /* base,ctl,irq */ case 3: /* base,ctl,irq */
hwif->hw.irq = vals[2]; hwif->hw.irq = vals[2];
ide_init_hwif_ports(&hwif->hw, (ide_ioreg_t) vals[0], (ide_ioreg_t) vals[1], &hwif->irq); ide_init_hwif_ports(&hwif->hw, (unsigned long) vals[0], (unsigned long) vals[1], &hwif->irq);
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
hwif->irq = vals[2]; hwif->irq = vals[2];
hwif->noprobe = 0; hwif->noprobe = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment