aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-proc.c
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2007-05-09 18:01:10 -0400
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2007-05-09 18:01:10 -0400
commit7662d046df09e80680b77b68de896beab45e675e (patch)
treeea2281c59399b3867fb37e1005a0f0e0d2170c5d /drivers/ide/ide-proc.c
parent1497943ee692aa7519fa972d0e3a339649bf3a96 (diff)
ide: move IDE settings handling to ide-proc.c
* move __ide_add_setting() ide_add_setting() __ide_remove_setting() auto_remove_settings() ide_find_setting_by_name() ide_read_setting() ide_write_setting() set_xfer_rate() ide_add_generic_settings() ide_register_subdriver() ide_unregister_subdriver() from ide.c to ide-proc.c * set_{io_32bit,pio_mode,using_dma}() cannot be marked static now, fix it * rename ide_[un]register_subdriver() to ide_proc_[un]register_driver(), update device drivers to use new names * add CONFIG_IDE_PROC_FS=n versions of ide_proc_[un]register_driver() and ide_add_generic_settings() * make ide_find_setting_by_name(), ide_{read,write}_setting() and ide_{add,remove}_proc_entries() static * cover IDE settings code in device drivers with CONFIG_IDE_PROC_FS #ifdef, also while at it cover with CONFIG_IDE_PROC_FS #ifdef ide_driver_t.proc * remove bogus comment from ide.h * cover with CONFIG_IDE_PROC_FS #ifdef .proc and .settings in ide_drive_t Besides saner code this patch results in the IDE core smaller by ~2 kB (on x86-32) and IDE disk driver by ~1 kB (ditto) when CONFIG_IDE_PROC_FS=n. Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/ide-proc.c')
-rw-r--r--drivers/ide/ide-proc.c310
1 files changed, 308 insertions, 2 deletions
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index a9e0b30fb1f2..949a6f609d84 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -3,6 +3,8 @@
3 * 3 *
4 * Copyright (C) 1997-1998 Mark Lord 4 * Copyright (C) 1997-1998 Mark Lord
5 * Copyright (C) 2003 Red Hat <alan@redhat.com> 5 * Copyright (C) 2003 Red Hat <alan@redhat.com>
6 *
7 * Some code was moved here from ide.c, see it for original copyrights.
6 */ 8 */
7 9
8/* 10/*
@@ -121,6 +123,265 @@ static int proc_ide_read_identify
121 PROC_IDE_READ_RETURN(page,start,off,count,eof,len); 123 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
122} 124}
123 125
126/**
127 * __ide_add_setting - add an ide setting option
128 * @drive: drive to use
129 * @name: setting name
130 * @rw: true if the function is read write
131 * @data_type: type of data
132 * @min: range minimum
133 * @max: range maximum
134 * @mul_factor: multiplication scale
135 * @div_factor: divison scale
136 * @data: private data field
137 * @set: setting
138 * @auto_remove: setting auto removal flag
139 *
140 * Removes the setting named from the device if it is present.
141 * The function takes the settings_lock to protect against
142 * parallel changes. This function must not be called from IRQ
143 * context. Returns 0 on success or -1 on failure.
144 *
145 * BUGS: This code is seriously over-engineered. There is also
146 * magic about how the driver specific features are setup. If
147 * a driver is attached we assume the driver settings are auto
148 * remove.
149 */
150
151static 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)
152{
153 ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
154
155 down(&ide_setting_sem);
156 while ((*p) && strcmp((*p)->name, name) < 0)
157 p = &((*p)->next);
158 if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
159 goto abort;
160 if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
161 goto abort;
162 strcpy(setting->name, name);
163 setting->rw = rw;
164 setting->data_type = data_type;
165 setting->min = min;
166 setting->max = max;
167 setting->mul_factor = mul_factor;
168 setting->div_factor = div_factor;
169 setting->data = data;
170 setting->set = set;
171
172 setting->next = *p;
173 if (auto_remove)
174 setting->auto_remove = 1;
175 *p = setting;
176 up(&ide_setting_sem);
177 return 0;
178abort:
179 up(&ide_setting_sem);
180 kfree(setting);
181 return -1;
182}
183
184int 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)
185{
186 return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1);
187}
188
189EXPORT_SYMBOL(ide_add_setting);
190
191/**
192 * __ide_remove_setting - remove an ide setting option
193 * @drive: drive to use
194 * @name: setting name
195 *
196 * Removes the setting named from the device if it is present.
197 * The caller must hold the setting semaphore.
198 */
199
200static void __ide_remove_setting (ide_drive_t *drive, char *name)
201{
202 ide_settings_t **p, *setting;
203
204 p = (ide_settings_t **) &drive->settings;
205
206 while ((*p) && strcmp((*p)->name, name))
207 p = &((*p)->next);
208 if ((setting = (*p)) == NULL)
209 return;
210
211 (*p) = setting->next;
212
213 kfree(setting->name);
214 kfree(setting);
215}
216
217/**
218 * auto_remove_settings - remove driver specific settings
219 * @drive: drive
220 *
221 * Automatically remove all the driver specific settings for this
222 * drive. This function may not be called from IRQ context. The
223 * caller must hold ide_setting_sem.
224 */
225
226static void auto_remove_settings (ide_drive_t *drive)
227{
228 ide_settings_t *setting;
229repeat:
230 setting = drive->settings;
231 while (setting) {
232 if (setting->auto_remove) {
233 __ide_remove_setting(drive, setting->name);
234 goto repeat;
235 }
236 setting = setting->next;
237 }
238}
239
240/**
241 * ide_find_setting_by_name - find a drive specific setting
242 * @drive: drive to scan
243 * @name: setting name
244 *
245 * Scan's the device setting table for a matching entry and returns
246 * this or NULL if no entry is found. The caller must hold the
247 * setting semaphore
248 */
249
250static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
251{
252 ide_settings_t *setting = drive->settings;
253
254 while (setting) {
255 if (strcmp(setting->name, name) == 0)
256 break;
257 setting = setting->next;
258 }
259 return setting;
260}
261
262/**
263 * ide_read_setting - read an IDE setting
264 * @drive: drive to read from
265 * @setting: drive setting
266 *
267 * Read a drive setting and return the value. The caller
268 * must hold the ide_setting_sem when making this call.
269 *
270 * BUGS: the data return and error are the same return value
271 * so an error -EINVAL and true return of the same value cannot
272 * be told apart
273 */
274
275static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
276{
277 int val = -EINVAL;
278 unsigned long flags;
279
280 if ((setting->rw & SETTING_READ)) {
281 spin_lock_irqsave(&ide_lock, flags);
282 switch(setting->data_type) {
283 case TYPE_BYTE:
284 val = *((u8 *) setting->data);
285 break;
286 case TYPE_SHORT:
287 val = *((u16 *) setting->data);
288 break;
289 case TYPE_INT:
290 val = *((u32 *) setting->data);
291 break;
292 }
293 spin_unlock_irqrestore(&ide_lock, flags);
294 }
295 return val;
296}
297
298/**
299 * ide_write_setting - read an IDE setting
300 * @drive: drive to read from
301 * @setting: drive setting
302 * @val: value
303 *
304 * Write a drive setting if it is possible. The caller
305 * must hold the ide_setting_sem when making this call.
306 *
307 * BUGS: the data return and error are the same return value
308 * so an error -EINVAL and true return of the same value cannot
309 * be told apart
310 *
311 * FIXME: This should be changed to enqueue a special request
312 * to the driver to change settings, and then wait on a sema for completion.
313 * The current scheme of polling is kludgy, though safe enough.
314 */
315
316static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
317{
318 if (!capable(CAP_SYS_ADMIN))
319 return -EACCES;
320 if (setting->set)
321 return setting->set(drive, val);
322 if (!(setting->rw & SETTING_WRITE))
323 return -EPERM;
324 if (val < setting->min || val > setting->max)
325 return -EINVAL;
326 if (ide_spin_wait_hwgroup(drive))
327 return -EBUSY;
328 switch (setting->data_type) {
329 case TYPE_BYTE:
330 *((u8 *) setting->data) = val;
331 break;
332 case TYPE_SHORT:
333 *((u16 *) setting->data) = val;
334 break;
335 case TYPE_INT:
336 *((u32 *) setting->data) = val;
337 break;
338 }
339 spin_unlock_irq(&ide_lock);
340 return 0;
341}
342
343static int set_xfer_rate (ide_drive_t *drive, int arg)
344{
345 int err;
346
347 if (arg < 0 || arg > 70)
348 return -EINVAL;
349
350 err = ide_wait_cmd(drive,
351 WIN_SETFEATURES, (u8) arg,
352 SETFEATURES_XFER, 0, NULL);
353
354 if (!err && arg) {
355 ide_set_xfer_rate(drive, (u8) arg);
356 ide_driveid_update(drive);
357 }
358 return err;
359}
360
361/**
362 * ide_add_generic_settings - generic ide settings
363 * @drive: drive being configured
364 *
365 * Add the generic parts of the system settings to the /proc files.
366 * The caller must not be holding the ide_setting_sem.
367 */
368
369void ide_add_generic_settings (ide_drive_t *drive)
370{
371/*
372 * drive setting name read/write access data type min max mul_factor div_factor data pointer set function
373 */
374 __ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit, 0);
375 __ide_add_setting(drive, "keepsettings", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL, 0);
376 __ide_add_setting(drive, "nice1", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL, 0);
377 __ide_add_setting(drive, "pio_mode", SETTING_WRITE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode, 0);
378 __ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL, 0);
379 __ide_add_setting(drive, "using_dma", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma, 0);
380 __ide_add_setting(drive, "init_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL, 0);
381 __ide_add_setting(drive, "current_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate, 0);
382 __ide_add_setting(drive, "number", SETTING_RW, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL, 0);
383}
384
124static void proc_ide_settings_warn(void) 385static void proc_ide_settings_warn(void)
125{ 386{
126 static int warned = 0; 387 static int warned = 0;
@@ -399,7 +660,7 @@ static ide_proc_entry_t generic_drive_entries[] = {
399 { NULL, 0, NULL, NULL } 660 { NULL, 0, NULL, NULL }
400}; 661};
401 662
402void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data) 663static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
403{ 664{
404 struct proc_dir_entry *ent; 665 struct proc_dir_entry *ent;
405 666
@@ -415,7 +676,7 @@ void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void
415 } 676 }
416} 677}
417 678
418void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p) 679static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
419{ 680{
420 if (!dir || !p) 681 if (!dir || !p)
421 return; 682 return;
@@ -425,6 +686,51 @@ void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
425 } 686 }
426} 687}
427 688
689void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
690{
691 ide_add_proc_entries(drive->proc, driver->proc, drive);
692}
693
694EXPORT_SYMBOL(ide_proc_register_driver);
695
696/**
697 * ide_proc_unregister_driver - remove driver specific data
698 * @drive: drive
699 * @driver: driver
700 *
701 * Clean up the driver specific /proc files and IDE settings
702 * for a given drive.
703 *
704 * Takes ide_setting_sem and ide_lock.
705 * Caller must hold none of the locks.
706 */
707
708void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
709{
710 unsigned long flags;
711
712 ide_remove_proc_entries(drive->proc, driver->proc);
713
714 down(&ide_setting_sem);
715 spin_lock_irqsave(&ide_lock, flags);
716 /*
717 * ide_setting_sem protects the settings list
718 * ide_lock protects the use of settings
719 *
720 * so we need to hold both, ide_settings_sem because we want to
721 * modify the settings list, and ide_lock because we cannot take
722 * a setting out that is being used.
723 *
724 * OTOH both ide_{read,write}_setting are only ever used under
725 * ide_setting_sem.
726 */
727 auto_remove_settings(drive);
728 spin_unlock_irqrestore(&ide_lock, flags);
729 up(&ide_setting_sem);
730}
731
732EXPORT_SYMBOL(ide_proc_unregister_driver);
733
428static void create_proc_ide_drives(ide_hwif_t *hwif) 734static void create_proc_ide_drives(ide_hwif_t *hwif)
429{ 735{
430 int d; 736 int d;