diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2008-10-10 16:39:28 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2008-10-10 16:39:28 -0400 |
commit | 8185d5aa93e0a5c111adc4952a5b87193a68ae5b (patch) | |
tree | 431aeb09a448b7b07a353e12f4fe931ebb8555cd /drivers/ide/ide-proc.c | |
parent | 263138a0ad6e38de7f6526b7de037ed4511308ef (diff) |
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: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/ide-proc.c')
-rw-r--r-- | drivers/ide/ide-proc.c | 279 |
1 files changed, 87 insertions, 192 deletions
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 7a64aedfa648..5634b3971d21 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c | |||
@@ -114,140 +114,24 @@ static int proc_ide_read_identify | |||
114 | } | 114 | } |
115 | 115 | ||
116 | /** | 116 | /** |
117 | * __ide_add_setting - add an ide setting option | 117 | * ide_find_setting - find a specific setting |
118 | * @drive: drive to use | 118 | * @st: setting table pointer |
119 | * @name: setting name | 119 | * @name: setting name |
120 | * @rw: true if the function is read write | ||
121 | * @data_type: type of data | ||
122 | * @min: range minimum | ||
123 | * @max: range maximum | ||
124 | * @mul_factor: multiplication scale | ||
125 | * @div_factor: divison scale | ||
126 | * @data: private data field | ||
127 | * @set: setting | ||
128 | * @auto_remove: setting auto removal flag | ||
129 | * | 120 | * |
130 | * Removes the setting named from the device if it is present. | 121 | * Scan's the setting table for a matching entry and returns |
131 | * The function takes the settings_lock to protect against | ||
132 | * parallel changes. This function must not be called from IRQ | ||
133 | * context. Returns 0 on success or -1 on failure. | ||
134 | * | ||
135 | * BUGS: This code is seriously over-engineered. There is also | ||
136 | * magic about how the driver specific features are setup. If | ||
137 | * a driver is attached we assume the driver settings are auto | ||
138 | * remove. | ||
139 | */ | ||
140 | |||
141 | 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) | ||
142 | { | ||
143 | ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; | ||
144 | |||
145 | mutex_lock(&ide_setting_mtx); | ||
146 | while ((*p) && strcmp((*p)->name, name) < 0) | ||
147 | p = &((*p)->next); | ||
148 | if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL) | ||
149 | goto abort; | ||
150 | if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL) | ||
151 | goto abort; | ||
152 | strcpy(setting->name, name); | ||
153 | setting->rw = rw; | ||
154 | setting->data_type = data_type; | ||
155 | setting->min = min; | ||
156 | setting->max = max; | ||
157 | setting->mul_factor = mul_factor; | ||
158 | setting->div_factor = div_factor; | ||
159 | setting->data = data; | ||
160 | setting->set = set; | ||
161 | |||
162 | setting->next = *p; | ||
163 | if (auto_remove) | ||
164 | setting->auto_remove = 1; | ||
165 | *p = setting; | ||
166 | mutex_unlock(&ide_setting_mtx); | ||
167 | return 0; | ||
168 | abort: | ||
169 | mutex_unlock(&ide_setting_mtx); | ||
170 | kfree(setting); | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | 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) | ||
175 | { | ||
176 | return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1); | ||
177 | } | ||
178 | |||
179 | EXPORT_SYMBOL(ide_add_setting); | ||
180 | |||
181 | /** | ||
182 | * __ide_remove_setting - remove an ide setting option | ||
183 | * @drive: drive to use | ||
184 | * @name: setting name | ||
185 | * | ||
186 | * Removes the setting named from the device if it is present. | ||
187 | * The caller must hold the setting semaphore. | ||
188 | */ | ||
189 | |||
190 | static void __ide_remove_setting(ide_drive_t *drive, char *name) | ||
191 | { | ||
192 | ide_settings_t **p, *setting; | ||
193 | |||
194 | p = (ide_settings_t **) &drive->settings; | ||
195 | |||
196 | while ((*p) && strcmp((*p)->name, name)) | ||
197 | p = &((*p)->next); | ||
198 | setting = (*p); | ||
199 | if (setting == NULL) | ||
200 | return; | ||
201 | |||
202 | (*p) = setting->next; | ||
203 | |||
204 | kfree(setting->name); | ||
205 | kfree(setting); | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * auto_remove_settings - remove driver specific settings | ||
210 | * @drive: drive | ||
211 | * | ||
212 | * Automatically remove all the driver specific settings for this | ||
213 | * drive. This function may not be called from IRQ context. The | ||
214 | * caller must hold ide_setting_mtx. | ||
215 | */ | ||
216 | |||
217 | static void auto_remove_settings(ide_drive_t *drive) | ||
218 | { | ||
219 | ide_settings_t *setting; | ||
220 | repeat: | ||
221 | setting = drive->settings; | ||
222 | while (setting) { | ||
223 | if (setting->auto_remove) { | ||
224 | __ide_remove_setting(drive, setting->name); | ||
225 | goto repeat; | ||
226 | } | ||
227 | setting = setting->next; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /** | ||
232 | * ide_find_setting_by_name - find a drive specific setting | ||
233 | * @drive: drive to scan | ||
234 | * @name: setting name | ||
235 | * | ||
236 | * Scan's the device setting table for a matching entry and returns | ||
237 | * this or NULL if no entry is found. The caller must hold the | 122 | * this or NULL if no entry is found. The caller must hold the |
238 | * setting semaphore | 123 | * setting semaphore |
239 | */ | 124 | */ |
240 | 125 | ||
241 | static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) | 126 | static const struct ide_devset *ide_find_setting(const struct ide_devset **st, |
127 | char *name) | ||
242 | { | 128 | { |
243 | ide_settings_t *setting = drive->settings; | 129 | while (*st) { |
244 | 130 | if (strcmp((*st)->name, name) == 0) | |
245 | while (setting) { | ||
246 | if (strcmp(setting->name, name) == 0) | ||
247 | break; | 131 | break; |
248 | setting = setting->next; | 132 | st++; |
249 | } | 133 | } |
250 | return setting; | 134 | return *st; |
251 | } | 135 | } |
252 | 136 | ||
253 | /** | 137 | /** |
@@ -263,26 +147,19 @@ static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) | |||
263 | * be told apart | 147 | * be told apart |
264 | */ | 148 | */ |
265 | 149 | ||
266 | static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) | 150 | static int ide_read_setting(ide_drive_t *drive, |
151 | const struct ide_devset *setting) | ||
267 | { | 152 | { |
268 | int val = -EINVAL; | 153 | int val = -EINVAL; |
269 | unsigned long flags; | 154 | |
155 | if ((setting->flags & S_READ)) { | ||
156 | unsigned long flags; | ||
270 | 157 | ||
271 | if ((setting->rw & SETTING_READ)) { | ||
272 | spin_lock_irqsave(&ide_lock, flags); | 158 | spin_lock_irqsave(&ide_lock, flags); |
273 | switch (setting->data_type) { | 159 | val = setting->get(drive); |
274 | case TYPE_BYTE: | ||
275 | val = *((u8 *) setting->data); | ||
276 | break; | ||
277 | case TYPE_SHORT: | ||
278 | val = *((u16 *) setting->data); | ||
279 | break; | ||
280 | case TYPE_INT: | ||
281 | val = *((u32 *) setting->data); | ||
282 | break; | ||
283 | } | ||
284 | spin_unlock_irqrestore(&ide_lock, flags); | 160 | spin_unlock_irqrestore(&ide_lock, flags); |
285 | } | 161 | } |
162 | |||
286 | return val; | 163 | return val; |
287 | } | 164 | } |
288 | 165 | ||
@@ -304,33 +181,26 @@ static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) | |||
304 | * The current scheme of polling is kludgy, though safe enough. | 181 | * The current scheme of polling is kludgy, though safe enough. |
305 | */ | 182 | */ |
306 | 183 | ||
307 | static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) | 184 | static int ide_write_setting(ide_drive_t *drive, |
185 | const struct ide_devset *setting, int val) | ||
308 | { | 186 | { |
309 | if (!capable(CAP_SYS_ADMIN)) | 187 | if (!capable(CAP_SYS_ADMIN)) |
310 | return -EACCES; | 188 | return -EACCES; |
311 | if (setting->set) | 189 | if (setting->set && (setting->flags & S_NOLOCK)) |
312 | return setting->set(drive, val); | 190 | return setting->set(drive, val); |
313 | if (!(setting->rw & SETTING_WRITE)) | 191 | if (!(setting->flags & S_WRITE)) |
314 | return -EPERM; | 192 | return -EPERM; |
315 | if (val < setting->min || val > setting->max) | 193 | if (val < setting->min || val > setting->max) |
316 | return -EINVAL; | 194 | return -EINVAL; |
317 | if (ide_spin_wait_hwgroup(drive)) | 195 | if (ide_spin_wait_hwgroup(drive)) |
318 | return -EBUSY; | 196 | return -EBUSY; |
319 | switch (setting->data_type) { | 197 | setting->set(drive, val); |
320 | case TYPE_BYTE: | ||
321 | *((u8 *) setting->data) = val; | ||
322 | break; | ||
323 | case TYPE_SHORT: | ||
324 | *((u16 *) setting->data) = val; | ||
325 | break; | ||
326 | case TYPE_INT: | ||
327 | *((u32 *) setting->data) = val; | ||
328 | break; | ||
329 | } | ||
330 | spin_unlock_irq(&ide_lock); | 198 | spin_unlock_irq(&ide_lock); |
331 | return 0; | 199 | return 0; |
332 | } | 200 | } |
333 | 201 | ||
202 | static ide_devset_get(xfer_rate, current_speed); | ||
203 | |||
334 | static int set_xfer_rate (ide_drive_t *drive, int arg) | 204 | static int set_xfer_rate (ide_drive_t *drive, int arg) |
335 | { | 205 | { |
336 | ide_task_t task; | 206 | ide_task_t task; |
@@ -355,29 +225,30 @@ static int set_xfer_rate (ide_drive_t *drive, int arg) | |||
355 | return err; | 225 | return err; |
356 | } | 226 | } |
357 | 227 | ||
358 | /** | 228 | ide_devset_rw_nolock(current_speed, 0, 70, xfer_rate); |
359 | * ide_add_generic_settings - generic ide settings | 229 | ide_devset_rw_nolock(io_32bit, 0, 1 + (SUPPORT_VLB_SYNC << 1), io_32bit); |
360 | * @drive: drive being configured | 230 | ide_devset_rw_nolock(keepsettings, 0, 1, ksettings); |
361 | * | 231 | ide_devset_rw_nolock(unmaskirq, 0, 1, unmaskirq); |
362 | * Add the generic parts of the system settings to the /proc files. | 232 | ide_devset_rw_nolock(using_dma, 0, 1, using_dma); |
363 | * The caller must not be holding the ide_setting_mtx. | 233 | |
364 | */ | 234 | ide_devset_w_nolock(pio_mode, 0, 255, pio_mode); |
365 | 235 | ||
366 | void ide_add_generic_settings (ide_drive_t *drive) | 236 | ide_devset_rw(init_speed, 0, 70, init_speed); |
367 | { | 237 | ide_devset_rw(nice1, 0, 1, nice1); |
368 | /* | 238 | ide_devset_rw(number, 0, 3, dn); |
369 | * drive setting name read/write access data type min max mul_factor div_factor data pointer set function | 239 | |
370 | */ | 240 | static const struct ide_devset *ide_generic_settings[] = { |
371 | __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); | 241 | &ide_devset_current_speed, |
372 | __ide_add_setting(drive, "keepsettings", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, set_ksettings, 0); | 242 | &ide_devset_init_speed, |
373 | __ide_add_setting(drive, "nice1", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL, 0); | 243 | &ide_devset_io_32bit, |
374 | __ide_add_setting(drive, "pio_mode", SETTING_WRITE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode, 0); | 244 | &ide_devset_keepsettings, |
375 | __ide_add_setting(drive, "unmaskirq", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, set_unmaskirq, 0); | 245 | &ide_devset_nice1, |
376 | __ide_add_setting(drive, "using_dma", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma, 0); | 246 | &ide_devset_number, |
377 | __ide_add_setting(drive, "init_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL, 0); | 247 | &ide_devset_pio_mode, |
378 | __ide_add_setting(drive, "current_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate, 0); | 248 | &ide_devset_unmaskirq, |
379 | __ide_add_setting(drive, "number", SETTING_RW, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL, 0); | 249 | &ide_devset_using_dma, |
380 | } | 250 | NULL |
251 | }; | ||
381 | 252 | ||
382 | static void proc_ide_settings_warn(void) | 253 | static void proc_ide_settings_warn(void) |
383 | { | 254 | { |
@@ -394,19 +265,31 @@ static void proc_ide_settings_warn(void) | |||
394 | static int proc_ide_read_settings | 265 | static int proc_ide_read_settings |
395 | (char *page, char **start, off_t off, int count, int *eof, void *data) | 266 | (char *page, char **start, off_t off, int count, int *eof, void *data) |
396 | { | 267 | { |
268 | const struct ide_devset *setting, **g, **d; | ||
397 | ide_drive_t *drive = (ide_drive_t *) data; | 269 | ide_drive_t *drive = (ide_drive_t *) data; |
398 | ide_settings_t *setting = (ide_settings_t *) drive->settings; | ||
399 | char *out = page; | 270 | char *out = page; |
400 | int len, rc, mul_factor, div_factor; | 271 | int len, rc, mul_factor, div_factor; |
401 | 272 | ||
402 | proc_ide_settings_warn(); | 273 | proc_ide_settings_warn(); |
403 | 274 | ||
404 | mutex_lock(&ide_setting_mtx); | 275 | mutex_lock(&ide_setting_mtx); |
276 | g = ide_generic_settings; | ||
277 | d = drive->settings; | ||
405 | out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); | 278 | out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); |
406 | out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); | 279 | out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); |
407 | while (setting) { | 280 | while (*g || (d && *d)) { |
408 | mul_factor = setting->mul_factor; | 281 | /* read settings in the alphabetical order */ |
409 | div_factor = setting->div_factor; | 282 | if (*g && d && *d) { |
283 | if (strcmp((*d)->name, (*g)->name) < 0) | ||
284 | setting = *d++; | ||
285 | else | ||
286 | setting = *g++; | ||
287 | } else if (d && *d) { | ||
288 | setting = *d++; | ||
289 | } else | ||
290 | setting = *g++; | ||
291 | mul_factor = setting->mulf ? setting->mulf(drive) : 1; | ||
292 | div_factor = setting->divf ? setting->divf(drive) : 1; | ||
410 | out += sprintf(out, "%-24s", setting->name); | 293 | out += sprintf(out, "%-24s", setting->name); |
411 | rc = ide_read_setting(drive, setting); | 294 | rc = ide_read_setting(drive, setting); |
412 | if (rc >= 0) | 295 | if (rc >= 0) |
@@ -414,12 +297,11 @@ static int proc_ide_read_settings | |||
414 | else | 297 | else |
415 | out += sprintf(out, "%-16s", "write-only"); | 298 | out += sprintf(out, "%-16s", "write-only"); |
416 | out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); | 299 | out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); |
417 | if (setting->rw & SETTING_READ) | 300 | if (setting->flags & S_READ) |
418 | out += sprintf(out, "r"); | 301 | out += sprintf(out, "r"); |
419 | if (setting->rw & SETTING_WRITE) | 302 | if (setting->flags & S_WRITE) |
420 | out += sprintf(out, "w"); | 303 | out += sprintf(out, "w"); |
421 | out += sprintf(out, "\n"); | 304 | out += sprintf(out, "\n"); |
422 | setting = setting->next; | ||
423 | } | 305 | } |
424 | len = out - page; | 306 | len = out - page; |
425 | mutex_unlock(&ide_setting_mtx); | 307 | mutex_unlock(&ide_setting_mtx); |
@@ -433,9 +315,10 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer, | |||
433 | { | 315 | { |
434 | ide_drive_t *drive = (ide_drive_t *) data; | 316 | ide_drive_t *drive = (ide_drive_t *) data; |
435 | char name[MAX_LEN + 1]; | 317 | char name[MAX_LEN + 1]; |
436 | int for_real = 0; | 318 | int for_real = 0, mul_factor, div_factor; |
437 | unsigned long n; | 319 | unsigned long n; |
438 | ide_settings_t *setting; | 320 | |
321 | const struct ide_devset *setting; | ||
439 | char *buf, *s; | 322 | char *buf, *s; |
440 | 323 | ||
441 | if (!capable(CAP_SYS_ADMIN)) | 324 | if (!capable(CAP_SYS_ADMIN)) |
@@ -503,13 +386,21 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer, | |||
503 | } | 386 | } |
504 | 387 | ||
505 | mutex_lock(&ide_setting_mtx); | 388 | mutex_lock(&ide_setting_mtx); |
506 | setting = ide_find_setting_by_name(drive, name); | 389 | /* generic settings first, then driver specific ones */ |
390 | setting = ide_find_setting(ide_generic_settings, name); | ||
507 | if (!setting) { | 391 | if (!setting) { |
508 | mutex_unlock(&ide_setting_mtx); | 392 | if (drive->settings) |
509 | goto parse_error; | 393 | setting = ide_find_setting(drive->settings, name); |
394 | if (!setting) { | ||
395 | mutex_unlock(&ide_setting_mtx); | ||
396 | goto parse_error; | ||
397 | } | ||
398 | } | ||
399 | if (for_real) { | ||
400 | mul_factor = setting->mulf ? setting->mulf(drive) : 1; | ||
401 | div_factor = setting->divf ? setting->divf(drive) : 1; | ||
402 | ide_write_setting(drive, setting, val * div_factor / mul_factor); | ||
510 | } | 403 | } |
511 | if (for_real) | ||
512 | ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor); | ||
513 | mutex_unlock(&ide_setting_mtx); | 404 | mutex_unlock(&ide_setting_mtx); |
514 | } | 405 | } |
515 | } while (!for_real++); | 406 | } while (!for_real++); |
@@ -680,6 +571,10 @@ static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t | |||
680 | 571 | ||
681 | void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) | 572 | void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) |
682 | { | 573 | { |
574 | mutex_lock(&ide_setting_mtx); | ||
575 | drive->settings = driver->settings; | ||
576 | mutex_unlock(&ide_setting_mtx); | ||
577 | |||
683 | ide_add_proc_entries(drive->proc, driver->proc, drive); | 578 | ide_add_proc_entries(drive->proc, driver->proc, drive); |
684 | } | 579 | } |
685 | 580 | ||
@@ -716,7 +611,7 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) | |||
716 | * OTOH both ide_{read,write}_setting are only ever used under | 611 | * OTOH both ide_{read,write}_setting are only ever used under |
717 | * ide_setting_mtx. | 612 | * ide_setting_mtx. |
718 | */ | 613 | */ |
719 | auto_remove_settings(drive); | 614 | drive->settings = NULL; |
720 | spin_unlock_irqrestore(&ide_lock, flags); | 615 | spin_unlock_irqrestore(&ide_lock, flags); |
721 | mutex_unlock(&ide_setting_mtx); | 616 | mutex_unlock(&ide_setting_mtx); |
722 | } | 617 | } |