Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8185d5aa authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz
Browse files

ide: /proc/ide/hd*/settings rework



* Add struct ide_devset, S_* flags, *DEVSET() & ide*_devset_*() macros.

* Add 'const struct ide_devset **settings' to ide_driver_t.

* Use 'const struct ide_devset **settings' in ide_drive_t instead of
  'struct ide_settings_s *settings'.  Then convert core code and device
  drivers to use struct ide_devset and co.:

  - device settings are no longer allocated dynamically for each device
    but instead there is an unique struct ide_devset instance per setting

  - device driver keeps the pointer to the table of pointers to its
    settings in ide_driver_t.settings

  - generic settings are kept in ide_generic_setting[]

  - ide_proc_[un]register_driver(), ide_find_setting_by_name(),
    ide_{read,write}_setting() and proc_ide_{read,write}_settings()
    are updated accordingly

  - ide*_add_settings() are removed

* Remove no longer used __ide_add_setting(), ide_add_setting(),
  __ide_remove_setting() and auto_remove_settings().

* Remove no longer used TYPE_*, SETTING_*, ide_procset_t
  and ide_settings_t.

* ->keep_settings, ->using_dma, ->unmask, ->noflush, ->dsc_overlap,
  ->nice1, ->addressing, ->wcache and ->nowerr ide_drive_t fields
  can now be bitfield flags.

While at it:

* Rename ide_find_setting_by_name() to ide_find_setting().

* Rename write_wcache() to set_wcache().

There should be no functional changes caused by this patch.

Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 263138a0
Loading
Loading
Loading
Loading
+7 −8
Original line number Diff line number Diff line
@@ -1809,13 +1809,12 @@ static ide_proc_entry_t idecd_proc[] = {
	{ NULL, 0, NULL, NULL }
};

static void ide_cdrom_add_settings(ide_drive_t *drive)
{
	ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
			&drive->dsc_overlap, NULL);
}
#else
static inline void ide_cdrom_add_settings(ide_drive_t *drive) { ; }
ide_devset_rw(dsc_overlap, 0, 1, dsc_overlap);

static const struct ide_devset *idecd_settings[] = {
	&ide_devset_dsc_overlap,
	NULL
};
#endif

static const struct cd_list_entry ide_cd_quirks_list[] = {
@@ -1926,7 +1925,6 @@ static int ide_cdrom_setup(ide_drive_t *drive)
	}

	ide_proc_register_driver(drive, cd->driver);
	ide_cdrom_add_settings(drive);
	return 0;
}

@@ -1977,6 +1975,7 @@ static ide_driver_t ide_cdrom_driver = {
	.error			= __ide_error,
#ifdef CONFIG_IDE_PROC_FS
	.proc			= idecd_proc,
	.settings		= idecd_settings,
#endif
};

+48 −39
Original line number Diff line number Diff line
@@ -599,6 +599,8 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
	rq->special = task;
}

ide_devset_get(multcount, mult_count);

/*
 * This is tightly woven into the driver->do_special can not touch.
 * DON'T do it again until a total personality rewrite is committed.
@@ -625,6 +627,8 @@ static int set_multcount(ide_drive_t *drive, int arg)
	return (drive->mult_count == arg) ? 0 : -EIO;
}

ide_devset_get(nowerr, nowerr);

static int set_nowerr(ide_drive_t *drive, int arg)
{
	if (arg < 0 || arg > 1)
@@ -673,7 +677,9 @@ static void update_ordered(ide_drive_t *drive)
	blk_queue_ordered(drive->queue, ordered, prep_fn);
}

static int write_cache(ide_drive_t *drive, int arg)
ide_devset_get(wcache, wcache);

static int set_wcache(ide_drive_t *drive, int arg)
{
	ide_task_t args;
	int err = 1;
@@ -710,6 +716,8 @@ static int do_idedisk_flushcache(ide_drive_t *drive)
	return ide_no_data_taskfile(drive, &args);
}

ide_devset_get(acoustic, acoustic);

static int set_acoustic(ide_drive_t *drive, int arg)
{
	ide_task_t args;
@@ -727,6 +735,8 @@ static int set_acoustic(ide_drive_t *drive, int arg)
	return 0;
}

ide_devset_get(lba_addressing, addressing);

/*
 * drive->addressing:
 *	0: 28-bit
@@ -750,33 +760,33 @@ static int set_lba_addressing(ide_drive_t *drive, int arg)
}

#ifdef CONFIG_IDE_PROC_FS
static void idedisk_add_settings(ide_drive_t *drive)
{
	ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 65535, 1, 1,
			&drive->bios_cyl, NULL);
	ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
			&drive->bios_head, NULL);
	ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1,
			&drive->bios_sect, NULL);
	ide_add_setting(drive, "address", SETTING_RW, TYPE_BYTE, 0, 2, 1, 1,
			&drive->addressing, set_lba_addressing);
	ide_add_setting(drive, "multcount", SETTING_RW, TYPE_BYTE, 0, 16, 1, 1,
			&drive->mult_count, set_multcount);
	ide_add_setting(drive, "nowerr", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
			&drive->nowerr, set_nowerr);
	ide_add_setting(drive, "lun", SETTING_RW, TYPE_INT, 0, 7, 1, 1,
			&drive->lun, NULL);
	ide_add_setting(drive, "wcache", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
			&drive->wcache, write_cache);
	ide_add_setting(drive, "acoustic", SETTING_RW, TYPE_BYTE, 0, 254, 1, 1,
			&drive->acoustic, set_acoustic);
	ide_add_setting(drive, "failures", SETTING_RW, TYPE_INT, 0, 65535, 1, 1,
			&drive->failures, NULL);
	ide_add_setting(drive, "max_failures", SETTING_RW, TYPE_INT, 0, 65535,
			1, 1, &drive->max_failures, NULL);
}
#else
static inline void idedisk_add_settings(ide_drive_t *drive) { ; }
ide_devset_rw_nolock(acoustic,	0, 254, acoustic);
ide_devset_rw_nolock(address,	0,   2, lba_addressing);
ide_devset_rw_nolock(multcount,	0,  16, multcount);
ide_devset_rw_nolock(nowerr,	0,   1, nowerr);
ide_devset_rw_nolock(wcache,	0,   1, wcache);

ide_devset_rw(bios_cyl,		0, 65535, bios_cyl);
ide_devset_rw(bios_head,	0,   255, bios_head);
ide_devset_rw(bios_sect,	0,    63, bios_sect);
ide_devset_rw(failures,		0, 65535, failures);
ide_devset_rw(lun,		0,     7, lun);
ide_devset_rw(max_failures,	0, 65535, max_failures);

static const struct ide_devset *idedisk_settings[] = {
	&ide_devset_acoustic,
	&ide_devset_address,
	&ide_devset_bios_cyl,
	&ide_devset_bios_head,
	&ide_devset_bios_sect,
	&ide_devset_failures,
	&ide_devset_lun,
	&ide_devset_max_failures,
	&ide_devset_multcount,
	&ide_devset_nowerr,
	&ide_devset_wcache,
	NULL
};
#endif

static void idedisk_setup(ide_drive_t *drive)
@@ -788,7 +798,6 @@ static void idedisk_setup(ide_drive_t *drive)
	unsigned long long capacity;

	ide_proc_register_driver(drive, idkp->driver);
	idedisk_add_settings(drive);

	if (drive->id_read == 0)
		return;
@@ -880,7 +889,7 @@ static void idedisk_setup(ide_drive_t *drive)
	if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
		drive->wcache = 1;

	write_cache(drive, 1);
	set_wcache(drive, 1);
}

static void ide_cacheflush_p(ide_drive_t *drive)
@@ -976,6 +985,7 @@ static ide_driver_t idedisk_driver = {
	.error			= __ide_error,
#ifdef CONFIG_IDE_PROC_FS
	.proc			= idedisk_proc,
	.settings		= idedisk_settings,
#endif
};

@@ -1056,19 +1066,18 @@ static int idedisk_ioctl(struct inode *inode, struct file *file,
	struct block_device *bdev = inode->i_bdev;
	struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
	ide_drive_t *drive = idkp->drive;
	int err, (*setfunc)(ide_drive_t *, int);
	u8 *val;
	int err, (*getfunc)(ide_drive_t *), (*setfunc)(ide_drive_t *, int);

	switch (cmd) {
	case HDIO_GET_ADDRESS:	 val = &drive->addressing;	goto read_val;
	case HDIO_GET_MULTCOUNT: val = &drive->mult_count;	goto read_val;
	case HDIO_GET_NOWERR:	 val = &drive->nowerr;		goto read_val;
	case HDIO_GET_WCACHE:	 val = &drive->wcache;		goto read_val;
	case HDIO_GET_ACOUSTIC:	 val = &drive->acoustic;	goto read_val;
	case HDIO_GET_ADDRESS:	 getfunc = get_lba_addressing;	goto read_val;
	case HDIO_GET_MULTCOUNT: getfunc = get_multcount;	goto read_val;
	case HDIO_GET_NOWERR:	 getfunc = get_nowerr;		goto read_val;
	case HDIO_GET_WCACHE:	 getfunc = get_wcache;		goto read_val;
	case HDIO_GET_ACOUSTIC:	 getfunc = get_acoustic;	goto read_val;
	case HDIO_SET_ADDRESS:	 setfunc = set_lba_addressing;	goto set_val;
	case HDIO_SET_MULTCOUNT: setfunc = set_multcount;	goto set_val;
	case HDIO_SET_NOWERR:	 setfunc = set_nowerr;		goto set_val;
	case HDIO_SET_WCACHE:	 setfunc = write_cache;		goto set_val;
	case HDIO_SET_WCACHE:	 setfunc = set_wcache;		goto set_val;
	case HDIO_SET_ACOUSTIC:	 setfunc = set_acoustic;	goto set_val;
	}

@@ -1077,7 +1086,7 @@ static int idedisk_ioctl(struct inode *inode, struct file *file,
read_val:
	mutex_lock(&ide_setting_mtx);
	spin_lock_irqsave(&ide_lock, flags);
	err = *val;
	err = getfunc(drive);
	spin_unlock_irqrestore(&ide_lock, flags);
	mutex_unlock(&ide_setting_mtx);
	return err >= 0 ? put_user(err, (long __user *)arg) : err;
+23 −12
Original line number Diff line number Diff line
@@ -1007,21 +1007,32 @@ static int idefloppy_identify_device(ide_drive_t *drive, u16 *id)
}

#ifdef CONFIG_IDE_PROC_FS
static void idefloppy_add_settings(ide_drive_t *drive)
ide_devset_rw(bios_cyl,  0, 1023, bios_cyl);
ide_devset_rw(bios_head, 0,  255, bios_head);
ide_devset_rw(bios_sect, 0,   63, bios_sect);

static int get_ticks(ide_drive_t *drive)
{
	idefloppy_floppy_t *floppy = drive->driver_data;
	return floppy->ticks;
}

	ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 1023, 1, 1,
			&drive->bios_cyl, NULL);
	ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
			&drive->bios_head, NULL);
	ide_add_setting(drive, "bios_sect", SETTING_RW,	TYPE_BYTE, 0,  63, 1, 1,
			&drive->bios_sect, NULL);
	ide_add_setting(drive, "ticks",	   SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
			&floppy->ticks,	 NULL);
static int set_ticks(ide_drive_t *drive, int arg)
{
	idefloppy_floppy_t *floppy = drive->driver_data;
	floppy->ticks = arg;
	return 0;
}
#else
static inline void idefloppy_add_settings(ide_drive_t *drive) { ; }

IDE_DEVSET(ticks, S_RW, 0, 255, get_ticks, set_ticks);

static const struct ide_devset *idefloppy_settings[] = {
	&ide_devset_bios_cyl,
	&ide_devset_bios_head,
	&ide_devset_bios_sect,
	&ide_devset_ticks,
	NULL
};
#endif

static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
@@ -1063,7 +1074,6 @@ static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
	(void) ide_floppy_get_capacity(drive);

	ide_proc_register_driver(drive, floppy->driver);
	idefloppy_add_settings(drive);
}

static void ide_floppy_remove(ide_drive_t *drive)
@@ -1126,6 +1136,7 @@ static ide_driver_t idefloppy_driver = {
	.error			= __ide_error,
#ifdef CONFIG_IDE_PROC_FS
	.proc			= idefloppy_proc,
	.settings		= idefloppy_settings,
#endif
};

+0 −2
Original line number Diff line number Diff line
@@ -1332,8 +1332,6 @@ static void hwif_register_devices(ide_hwif_t *hwif)
		if (!drive->present)
			continue;

		ide_add_generic_settings(drive);

		snprintf(dev->bus_id, BUS_ID_SIZE, "%u.%u", hwif->index, i);
		dev->parent = &hwif->gendev;
		dev->bus = &ide_bus_type;
+87 −192
Original line number Diff line number Diff line
@@ -114,140 +114,24 @@ static int proc_ide_read_identify
}

/**
 *	__ide_add_setting	-	add an ide setting option
 *	@drive: drive to use
 *	ide_find_setting	-	find a specific setting
 *	@st: setting table pointer
 *	@name: setting name
 *	@rw: true if the function is read write
 *	@data_type: type of data
 *	@min: range minimum
 *	@max: range maximum
 *	@mul_factor: multiplication scale
 *	@div_factor: divison scale
 *	@data: private data field
 *	@set: setting
 *	@auto_remove: setting auto removal flag
 *
 *	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.
 *
 *	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.
 */

static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
{
	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;

	mutex_lock(&ide_setting_mtx);
	while ((*p) && strcmp((*p)->name, name) < 0)
		p = &((*p)->next);
	if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
		goto abort;
	if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
		goto abort;
	strcpy(setting->name, name);
	setting->rw = rw;
	setting->data_type = data_type;
	setting->min = min;
	setting->max = max;
	setting->mul_factor = mul_factor;
	setting->div_factor = div_factor;
	setting->data = data;
	setting->set = set;

	setting->next = *p;
	if (auto_remove)
		setting->auto_remove = 1;
	*p = setting;
	mutex_unlock(&ide_setting_mtx);
	return 0;
abort:
	mutex_unlock(&ide_setting_mtx);
	kfree(setting);
	return -1;
}

int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
{
	return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1);
}

EXPORT_SYMBOL(ide_add_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 caller must hold the setting semaphore.
 */

static void __ide_remove_setting(ide_drive_t *drive, char *name)
{
	ide_settings_t **p, *setting;

	p = (ide_settings_t **) &drive->settings;

	while ((*p) && strcmp((*p)->name, name))
		p = &((*p)->next);
	setting = (*p);
	if (setting == NULL)
		return;

	(*p) = setting->next;

	kfree(setting->name);
	kfree(setting);
}

/**
 *	auto_remove_settings	-	remove driver specific settings
 *	@drive: drive
 *
 *	Automatically remove all the driver specific settings for this
 *	drive. This function may not be called from IRQ context. The
 *	caller must hold ide_setting_mtx.
 */

static void auto_remove_settings(ide_drive_t *drive)
{
	ide_settings_t *setting;
repeat:
	setting = drive->settings;
	while (setting) {
		if (setting->auto_remove) {
			__ide_remove_setting(drive, setting->name);
			goto repeat;
		}
		setting = setting->next;
	}
}

/**
 *	ide_find_setting_by_name	-	find a drive specific setting
 *	@drive: drive to scan
 *	@name: setting name
 *
 *	Scan's the device setting table for a matching entry and returns
 *	Scan's the setting table for a matching entry and returns
 *	this or NULL if no entry is found. The caller must hold the
 *	setting semaphore
 */

static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
static const struct ide_devset *ide_find_setting(const struct ide_devset **st,
						 char *name)
{
	ide_settings_t *setting = drive->settings;

	while (setting) {
		if (strcmp(setting->name, name) == 0)
	while (*st) {
		if (strcmp((*st)->name, name) == 0)
			break;
		setting = setting->next;
		st++;
	}
	return setting;
	return *st;
}

/**
@@ -263,26 +147,19 @@ static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
 *	be told apart
 */

static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
static int ide_read_setting(ide_drive_t *drive,
			    const struct ide_devset *setting)
{
	int val = -EINVAL;

	if ((setting->flags & S_READ)) {
		unsigned long flags;

	if ((setting->rw & SETTING_READ)) {
		spin_lock_irqsave(&ide_lock, flags);
		switch (setting->data_type) {
		case TYPE_BYTE:
			val = *((u8 *) setting->data);
			break;
		case TYPE_SHORT:
			val = *((u16 *) setting->data);
			break;
		case TYPE_INT:
			val = *((u32 *) setting->data);
			break;
		}
		val = setting->get(drive);
		spin_unlock_irqrestore(&ide_lock, flags);
	}

	return val;
}

@@ -304,33 +181,26 @@ static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
 *	The current scheme of polling is kludgy, though safe enough.
 */

static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
static int ide_write_setting(ide_drive_t *drive,
			     const struct ide_devset *setting, int val)
{
	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;
	if (setting->set)
	if (setting->set && (setting->flags & S_NOLOCK))
		return setting->set(drive, val);
	if (!(setting->rw & SETTING_WRITE))
	if (!(setting->flags & S_WRITE))
		return -EPERM;
	if (val < setting->min || val > setting->max)
		return -EINVAL;
	if (ide_spin_wait_hwgroup(drive))
		return -EBUSY;
	switch (setting->data_type) {
	case TYPE_BYTE:
		*((u8 *) setting->data) = val;
		break;
	case TYPE_SHORT:
		*((u16 *) setting->data) = val;
		break;
	case TYPE_INT:
		*((u32 *) setting->data) = val;
		break;
	}
	setting->set(drive, val);
	spin_unlock_irq(&ide_lock);
	return 0;
}

static ide_devset_get(xfer_rate, current_speed);

static int set_xfer_rate (ide_drive_t *drive, int arg)
{
	ide_task_t task;
@@ -355,29 +225,30 @@ static int set_xfer_rate (ide_drive_t *drive, int arg)
	return err;
}

/**
 *	ide_add_generic_settings	-	generic ide settings
 *	@drive: drive being configured
 *
 *	Add the generic parts of the system settings to the /proc files.
 *	The caller must not be holding the ide_setting_mtx.
 */

void ide_add_generic_settings (ide_drive_t *drive)
{
/*
 *			  drive		setting name		read/write access				data type	min	max				mul_factor	div_factor	data pointer			set function
 */
	__ide_add_setting(drive,	"io_32bit",		SETTING_RW,					TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit,	0);
	__ide_add_setting(drive,	"keepsettings",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		set_ksettings,	0);
	__ide_add_setting(drive,	"nice1",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL,		0);
	__ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode,	0);
	__ide_add_setting(drive,	"unmaskirq",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			set_unmaskirq,	0);
	__ide_add_setting(drive,	"using_dma",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma,	0);
	__ide_add_setting(drive,	"init_speed",		SETTING_RW,					TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL,		0);
	__ide_add_setting(drive,	"current_speed",	SETTING_RW,					TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate,	0);
	__ide_add_setting(drive,	"number",		SETTING_RW,					TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL,		0);
}
ide_devset_rw_nolock(current_speed, 0, 70, xfer_rate);
ide_devset_rw_nolock(io_32bit, 0, 1 + (SUPPORT_VLB_SYNC << 1), io_32bit);
ide_devset_rw_nolock(keepsettings, 0, 1, ksettings);
ide_devset_rw_nolock(unmaskirq, 0, 1, unmaskirq);
ide_devset_rw_nolock(using_dma, 0, 1, using_dma);

ide_devset_w_nolock(pio_mode, 0, 255, pio_mode);

ide_devset_rw(init_speed, 0, 70, init_speed);
ide_devset_rw(nice1, 0, 1, nice1);
ide_devset_rw(number, 0, 3, dn);

static const struct ide_devset *ide_generic_settings[] = {
	&ide_devset_current_speed,
	&ide_devset_init_speed,
	&ide_devset_io_32bit,
	&ide_devset_keepsettings,
	&ide_devset_nice1,
	&ide_devset_number,
	&ide_devset_pio_mode,
	&ide_devset_unmaskirq,
	&ide_devset_using_dma,
	NULL
};

static void proc_ide_settings_warn(void)
{
@@ -394,19 +265,31 @@ static void proc_ide_settings_warn(void)
static int proc_ide_read_settings
	(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	const struct ide_devset *setting, **g, **d;
	ide_drive_t	*drive = (ide_drive_t *) data;
	ide_settings_t	*setting = (ide_settings_t *) drive->settings;
	char		*out = page;
	int		len, rc, mul_factor, div_factor;

	proc_ide_settings_warn();

	mutex_lock(&ide_setting_mtx);
	g = ide_generic_settings;
	d = drive->settings;
	out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
	out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
	while (setting) {
		mul_factor = setting->mul_factor;
		div_factor = setting->div_factor;
	while (*g || (d && *d)) {
		/* read settings in the alphabetical order */
		if (*g && d && *d) {
			if (strcmp((*d)->name, (*g)->name) < 0)
				setting = *d++;
			else
				setting = *g++;
		} else if (d && *d) {
			setting = *d++;
		} else
			setting = *g++;
		mul_factor = setting->mulf ? setting->mulf(drive) : 1;
		div_factor = setting->divf ? setting->divf(drive) : 1;
		out += sprintf(out, "%-24s", setting->name);
		rc = ide_read_setting(drive, setting);
		if (rc >= 0)
@@ -414,12 +297,11 @@ static int proc_ide_read_settings
		else
			out += sprintf(out, "%-16s", "write-only");
		out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
		if (setting->rw & SETTING_READ)
		if (setting->flags & S_READ)
			out += sprintf(out, "r");
		if (setting->rw & SETTING_WRITE)
		if (setting->flags & S_WRITE)
			out += sprintf(out, "w");
		out += sprintf(out, "\n");
		setting = setting->next;
	}
	len = out - page;
	mutex_unlock(&ide_setting_mtx);
@@ -433,9 +315,10 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer,
{
	ide_drive_t	*drive = (ide_drive_t *) data;
	char		name[MAX_LEN + 1];
	int		for_real = 0;
	int		for_real = 0, mul_factor, div_factor;
	unsigned long	n;
	ide_settings_t	*setting;

	const struct ide_devset *setting;
	char *buf, *s;

	if (!capable(CAP_SYS_ADMIN))
@@ -503,13 +386,21 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer,
			}

			mutex_lock(&ide_setting_mtx);
			setting = ide_find_setting_by_name(drive, name);
			/* generic settings first, then driver specific ones */
			setting = ide_find_setting(ide_generic_settings, name);
			if (!setting) {
				if (drive->settings)
					setting = ide_find_setting(drive->settings, name);
				if (!setting) {
					mutex_unlock(&ide_setting_mtx);
					goto parse_error;
				}
			if (for_real)
				ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
			}
			if (for_real) {
				mul_factor = setting->mulf ? setting->mulf(drive) : 1;
				div_factor = setting->divf ? setting->divf(drive) : 1;
				ide_write_setting(drive, setting, val * div_factor / mul_factor);
			}
			mutex_unlock(&ide_setting_mtx);
		}
	} while (!for_real++);
@@ -680,6 +571,10 @@ static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t

void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
{
	mutex_lock(&ide_setting_mtx);
	drive->settings = driver->settings;
	mutex_unlock(&ide_setting_mtx);

	ide_add_proc_entries(drive->proc, driver->proc, drive);
}

@@ -716,7 +611,7 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
	 * OTOH both ide_{read,write}_setting are only ever used under
	 * ide_setting_mtx.
	 */
	auto_remove_settings(drive);
	drive->settings = NULL;
	spin_unlock_irqrestore(&ide_lock, flags);
	mutex_unlock(&ide_setting_mtx);
}
Loading