diff options
Diffstat (limited to 'drivers/ide/ide-proc.c')
-rw-r--r-- | drivers/ide/ide-proc.c | 306 |
1 files changed, 93 insertions, 213 deletions
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index f66c9c3f6fc6..e7030a491463 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c | |||
@@ -12,14 +12,6 @@ | |||
12 | * "settings" files. e.g. "cat /proc/ide0/hda/settings" | 12 | * "settings" files. e.g. "cat /proc/ide0/hda/settings" |
13 | * To write a new value "val" into a specific setting "name", use: | 13 | * To write a new value "val" into a specific setting "name", use: |
14 | * echo "name:val" >/proc/ide/ide0/hda/settings | 14 | * echo "name:val" >/proc/ide/ide0/hda/settings |
15 | * | ||
16 | * Also useful, "cat /proc/ide0/hda/[identify, smart_values, | ||
17 | * smart_thresholds, capabilities]" will issue an IDENTIFY / | ||
18 | * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS / | ||
19 | * SENSE CAPABILITIES command to /dev/hda, and then dump out the | ||
20 | * returned data as 256 16-bit words. The "hdparm" utility will | ||
21 | * be updated someday soon to use this mechanism. | ||
22 | * | ||
23 | */ | 15 | */ |
24 | 16 | ||
25 | #include <linux/module.h> | 17 | #include <linux/module.h> |
@@ -31,7 +23,6 @@ | |||
31 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
32 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
33 | #include <linux/ctype.h> | 25 | #include <linux/ctype.h> |
34 | #include <linux/hdreg.h> | ||
35 | #include <linux/ide.h> | 26 | #include <linux/ide.h> |
36 | #include <linux/seq_file.h> | 27 | #include <linux/seq_file.h> |
37 | 28 | ||
@@ -109,13 +100,14 @@ static int proc_ide_read_identify | |||
109 | 100 | ||
110 | err = taskfile_lib_get_identify(drive, page); | 101 | err = taskfile_lib_get_identify(drive, page); |
111 | if (!err) { | 102 | if (!err) { |
112 | char *out = ((char *)page) + (SECTOR_WORDS * 4); | 103 | char *out = (char *)page + SECTOR_SIZE; |
104 | |||
113 | page = out; | 105 | page = out; |
114 | do { | 106 | do { |
115 | out += sprintf(out, "%04x%c", | 107 | out += sprintf(out, "%04x%c", |
116 | le16_to_cpup(val), (++i & 7) ? ' ' : '\n'); | 108 | le16_to_cpup(val), (++i & 7) ? ' ' : '\n'); |
117 | val += 1; | 109 | val += 1; |
118 | } while (i < (SECTOR_WORDS * 2)); | 110 | } while (i < SECTOR_SIZE / 2); |
119 | len = out - page; | 111 | len = out - page; |
120 | } | 112 | } |
121 | } | 113 | } |
@@ -123,140 +115,25 @@ static int proc_ide_read_identify | |||
123 | } | 115 | } |
124 | 116 | ||
125 | /** | 117 | /** |
126 | * __ide_add_setting - add an ide setting option | 118 | * ide_find_setting - find a specific setting |
127 | * @drive: drive to use | 119 | * @st: setting table pointer |
128 | * @name: setting name | ||
129 | * @rw: true if the function is read write | ||
130 | * @data_type: type of data | ||
131 | * @min: range minimum | ||
132 | * @max: range maximum | ||
133 | * @mul_factor: multiplication scale | ||
134 | * @div_factor: divison scale | ||
135 | * @data: private data field | ||
136 | * @set: setting | ||
137 | * @auto_remove: setting auto removal flag | ||
138 | * | ||
139 | * Removes the setting named from the device if it is present. | ||
140 | * The function takes the settings_lock to protect against | ||
141 | * parallel changes. This function must not be called from IRQ | ||
142 | * context. Returns 0 on success or -1 on failure. | ||
143 | * | ||
144 | * BUGS: This code is seriously over-engineered. There is also | ||
145 | * magic about how the driver specific features are setup. If | ||
146 | * a driver is attached we assume the driver settings are auto | ||
147 | * remove. | ||
148 | */ | ||
149 | |||
150 | 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) | ||
151 | { | ||
152 | ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; | ||
153 | |||
154 | mutex_lock(&ide_setting_mtx); | ||
155 | while ((*p) && strcmp((*p)->name, name) < 0) | ||
156 | p = &((*p)->next); | ||
157 | if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL) | ||
158 | goto abort; | ||
159 | if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL) | ||
160 | goto abort; | ||
161 | strcpy(setting->name, name); | ||
162 | setting->rw = rw; | ||
163 | setting->data_type = data_type; | ||
164 | setting->min = min; | ||
165 | setting->max = max; | ||
166 | setting->mul_factor = mul_factor; | ||
167 | setting->div_factor = div_factor; | ||
168 | setting->data = data; | ||
169 | setting->set = set; | ||
170 | |||
171 | setting->next = *p; | ||
172 | if (auto_remove) | ||
173 | setting->auto_remove = 1; | ||
174 | *p = setting; | ||
175 | mutex_unlock(&ide_setting_mtx); | ||
176 | return 0; | ||
177 | abort: | ||
178 | mutex_unlock(&ide_setting_mtx); | ||
179 | kfree(setting); | ||
180 | return -1; | ||
181 | } | ||
182 | |||
183 | 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) | ||
184 | { | ||
185 | return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1); | ||
186 | } | ||
187 | |||
188 | EXPORT_SYMBOL(ide_add_setting); | ||
189 | |||
190 | /** | ||
191 | * __ide_remove_setting - remove an ide setting option | ||
192 | * @drive: drive to use | ||
193 | * @name: setting name | ||
194 | * | ||
195 | * Removes the setting named from the device if it is present. | ||
196 | * The caller must hold the setting semaphore. | ||
197 | */ | ||
198 | |||
199 | static void __ide_remove_setting(ide_drive_t *drive, char *name) | ||
200 | { | ||
201 | ide_settings_t **p, *setting; | ||
202 | |||
203 | p = (ide_settings_t **) &drive->settings; | ||
204 | |||
205 | while ((*p) && strcmp((*p)->name, name)) | ||
206 | p = &((*p)->next); | ||
207 | setting = (*p); | ||
208 | if (setting == 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_mtx. | ||
224 | */ | ||
225 | |||
226 | static void auto_remove_settings(ide_drive_t *drive) | ||
227 | { | ||
228 | ide_settings_t *setting; | ||
229 | repeat: | ||
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 | 120 | * @name: setting name |
244 | * | 121 | * |
245 | * Scan's the device setting table for a matching entry and returns | 122 | * Scan's the setting table for a matching entry and returns |
246 | * this or NULL if no entry is found. The caller must hold the | 123 | * this or NULL if no entry is found. The caller must hold the |
247 | * setting semaphore | 124 | * setting semaphore |
248 | */ | 125 | */ |
249 | 126 | ||
250 | static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) | 127 | static |
128 | const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st, | ||
129 | char *name) | ||
251 | { | 130 | { |
252 | ide_settings_t *setting = drive->settings; | 131 | while (st->name) { |
253 | 132 | if (strcmp(st->name, name) == 0) | |
254 | while (setting) { | ||
255 | if (strcmp(setting->name, name) == 0) | ||
256 | break; | 133 | break; |
257 | setting = setting->next; | 134 | st++; |
258 | } | 135 | } |
259 | return setting; | 136 | return st->name ? st : NULL; |
260 | } | 137 | } |
261 | 138 | ||
262 | /** | 139 | /** |
@@ -272,26 +149,20 @@ static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) | |||
272 | * be told apart | 149 | * be told apart |
273 | */ | 150 | */ |
274 | 151 | ||
275 | static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) | 152 | static int ide_read_setting(ide_drive_t *drive, |
153 | const struct ide_proc_devset *setting) | ||
276 | { | 154 | { |
277 | int val = -EINVAL; | 155 | const struct ide_devset *ds = setting->setting; |
278 | unsigned long flags; | 156 | int val = -EINVAL; |
157 | |||
158 | if (ds->get) { | ||
159 | unsigned long flags; | ||
279 | 160 | ||
280 | if ((setting->rw & SETTING_READ)) { | ||
281 | spin_lock_irqsave(&ide_lock, flags); | 161 | spin_lock_irqsave(&ide_lock, flags); |
282 | switch (setting->data_type) { | 162 | val = ds->get(drive); |
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); | 163 | spin_unlock_irqrestore(&ide_lock, flags); |
294 | } | 164 | } |
165 | |||
295 | return val; | 166 | return val; |
296 | } | 167 | } |
297 | 168 | ||
@@ -313,33 +184,23 @@ static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) | |||
313 | * The current scheme of polling is kludgy, though safe enough. | 184 | * The current scheme of polling is kludgy, though safe enough. |
314 | */ | 185 | */ |
315 | 186 | ||
316 | static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) | 187 | static int ide_write_setting(ide_drive_t *drive, |
188 | const struct ide_proc_devset *setting, int val) | ||
317 | { | 189 | { |
190 | const struct ide_devset *ds = setting->setting; | ||
191 | |||
318 | if (!capable(CAP_SYS_ADMIN)) | 192 | if (!capable(CAP_SYS_ADMIN)) |
319 | return -EACCES; | 193 | return -EACCES; |
320 | if (setting->set) | 194 | if (!ds->set) |
321 | return setting->set(drive, val); | ||
322 | if (!(setting->rw & SETTING_WRITE)) | ||
323 | return -EPERM; | 195 | return -EPERM; |
324 | if (val < setting->min || val > setting->max) | 196 | if ((ds->flags & DS_SYNC) |
197 | && (val < setting->min || val > setting->max)) | ||
325 | return -EINVAL; | 198 | return -EINVAL; |
326 | if (ide_spin_wait_hwgroup(drive)) | 199 | return ide_devset_execute(drive, ds, val); |
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 | } | 200 | } |
342 | 201 | ||
202 | ide_devset_get(xfer_rate, current_speed); | ||
203 | |||
343 | static int set_xfer_rate (ide_drive_t *drive, int arg) | 204 | static int set_xfer_rate (ide_drive_t *drive, int arg) |
344 | { | 205 | { |
345 | ide_task_t task; | 206 | ide_task_t task; |
@@ -349,7 +210,7 @@ static int set_xfer_rate (ide_drive_t *drive, int arg) | |||
349 | return -EINVAL; | 210 | return -EINVAL; |
350 | 211 | ||
351 | memset(&task, 0, sizeof(task)); | 212 | memset(&task, 0, sizeof(task)); |
352 | task.tf.command = WIN_SETFEATURES; | 213 | task.tf.command = ATA_CMD_SET_FEATURES; |
353 | task.tf.feature = SETFEATURES_XFER; | 214 | task.tf.feature = SETFEATURES_XFER; |
354 | task.tf.nsect = (u8)arg; | 215 | task.tf.nsect = (u8)arg; |
355 | task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT | | 216 | task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT | |
@@ -364,29 +225,23 @@ static int set_xfer_rate (ide_drive_t *drive, int arg) | |||
364 | return err; | 225 | return err; |
365 | } | 226 | } |
366 | 227 | ||
367 | /** | 228 | ide_devset_rw(current_speed, xfer_rate); |
368 | * ide_add_generic_settings - generic ide settings | 229 | ide_devset_rw_field(init_speed, init_speed); |
369 | * @drive: drive being configured | 230 | ide_devset_rw_field(nice1, nice1); |
370 | * | 231 | ide_devset_rw_field(number, dn); |
371 | * Add the generic parts of the system settings to the /proc files. | 232 | |
372 | * The caller must not be holding the ide_setting_mtx. | 233 | static const struct ide_proc_devset ide_generic_settings[] = { |
373 | */ | 234 | IDE_PROC_DEVSET(current_speed, 0, 70), |
374 | 235 | IDE_PROC_DEVSET(init_speed, 0, 70), | |
375 | void ide_add_generic_settings (ide_drive_t *drive) | 236 | IDE_PROC_DEVSET(io_32bit, 0, 1 + (SUPPORT_VLB_SYNC << 1)), |
376 | { | 237 | IDE_PROC_DEVSET(keepsettings, 0, 1), |
377 | /* | 238 | IDE_PROC_DEVSET(nice1, 0, 1), |
378 | * drive setting name read/write access data type min max mul_factor div_factor data pointer set function | 239 | IDE_PROC_DEVSET(number, 0, 3), |
379 | */ | 240 | IDE_PROC_DEVSET(pio_mode, 0, 255), |
380 | __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); | 241 | IDE_PROC_DEVSET(unmaskirq, 0, 1), |
381 | __ide_add_setting(drive, "keepsettings", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL, 0); | 242 | IDE_PROC_DEVSET(using_dma, 0, 1), |
382 | __ide_add_setting(drive, "nice1", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL, 0); | 243 | { 0 }, |
383 | __ide_add_setting(drive, "pio_mode", SETTING_WRITE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode, 0); | 244 | }; |
384 | __ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL, 0); | ||
385 | __ide_add_setting(drive, "using_dma", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma, 0); | ||
386 | __ide_add_setting(drive, "init_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL, 0); | ||
387 | __ide_add_setting(drive, "current_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate, 0); | ||
388 | __ide_add_setting(drive, "number", SETTING_RW, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL, 0); | ||
389 | } | ||
390 | 245 | ||
391 | static void proc_ide_settings_warn(void) | 246 | static void proc_ide_settings_warn(void) |
392 | { | 247 | { |
@@ -403,19 +258,32 @@ static void proc_ide_settings_warn(void) | |||
403 | static int proc_ide_read_settings | 258 | static int proc_ide_read_settings |
404 | (char *page, char **start, off_t off, int count, int *eof, void *data) | 259 | (char *page, char **start, off_t off, int count, int *eof, void *data) |
405 | { | 260 | { |
261 | const struct ide_proc_devset *setting, *g, *d; | ||
262 | const struct ide_devset *ds; | ||
406 | ide_drive_t *drive = (ide_drive_t *) data; | 263 | ide_drive_t *drive = (ide_drive_t *) data; |
407 | ide_settings_t *setting = (ide_settings_t *) drive->settings; | ||
408 | char *out = page; | 264 | char *out = page; |
409 | int len, rc, mul_factor, div_factor; | 265 | int len, rc, mul_factor, div_factor; |
410 | 266 | ||
411 | proc_ide_settings_warn(); | 267 | proc_ide_settings_warn(); |
412 | 268 | ||
413 | mutex_lock(&ide_setting_mtx); | 269 | mutex_lock(&ide_setting_mtx); |
270 | g = ide_generic_settings; | ||
271 | d = drive->settings; | ||
414 | out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); | 272 | out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); |
415 | out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); | 273 | out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); |
416 | while (setting) { | 274 | while (g->name || (d && d->name)) { |
417 | mul_factor = setting->mul_factor; | 275 | /* read settings in the alphabetical order */ |
418 | div_factor = setting->div_factor; | 276 | if (g->name && d && d->name) { |
277 | if (strcmp(d->name, g->name) < 0) | ||
278 | setting = d++; | ||
279 | else | ||
280 | setting = g++; | ||
281 | } else if (d && d->name) { | ||
282 | setting = d++; | ||
283 | } else | ||
284 | setting = g++; | ||
285 | mul_factor = setting->mulf ? setting->mulf(drive) : 1; | ||
286 | div_factor = setting->divf ? setting->divf(drive) : 1; | ||
419 | out += sprintf(out, "%-24s", setting->name); | 287 | out += sprintf(out, "%-24s", setting->name); |
420 | rc = ide_read_setting(drive, setting); | 288 | rc = ide_read_setting(drive, setting); |
421 | if (rc >= 0) | 289 | if (rc >= 0) |
@@ -423,12 +291,12 @@ static int proc_ide_read_settings | |||
423 | else | 291 | else |
424 | out += sprintf(out, "%-16s", "write-only"); | 292 | out += sprintf(out, "%-16s", "write-only"); |
425 | out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); | 293 | out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); |
426 | if (setting->rw & SETTING_READ) | 294 | ds = setting->setting; |
295 | if (ds->get) | ||
427 | out += sprintf(out, "r"); | 296 | out += sprintf(out, "r"); |
428 | if (setting->rw & SETTING_WRITE) | 297 | if (ds->set) |
429 | out += sprintf(out, "w"); | 298 | out += sprintf(out, "w"); |
430 | out += sprintf(out, "\n"); | 299 | out += sprintf(out, "\n"); |
431 | setting = setting->next; | ||
432 | } | 300 | } |
433 | len = out - page; | 301 | len = out - page; |
434 | mutex_unlock(&ide_setting_mtx); | 302 | mutex_unlock(&ide_setting_mtx); |
@@ -442,9 +310,10 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer, | |||
442 | { | 310 | { |
443 | ide_drive_t *drive = (ide_drive_t *) data; | 311 | ide_drive_t *drive = (ide_drive_t *) data; |
444 | char name[MAX_LEN + 1]; | 312 | char name[MAX_LEN + 1]; |
445 | int for_real = 0; | 313 | int for_real = 0, mul_factor, div_factor; |
446 | unsigned long n; | 314 | unsigned long n; |
447 | ide_settings_t *setting; | 315 | |
316 | const struct ide_proc_devset *setting; | ||
448 | char *buf, *s; | 317 | char *buf, *s; |
449 | 318 | ||
450 | if (!capable(CAP_SYS_ADMIN)) | 319 | if (!capable(CAP_SYS_ADMIN)) |
@@ -512,13 +381,21 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer, | |||
512 | } | 381 | } |
513 | 382 | ||
514 | mutex_lock(&ide_setting_mtx); | 383 | mutex_lock(&ide_setting_mtx); |
515 | setting = ide_find_setting_by_name(drive, name); | 384 | /* generic settings first, then driver specific ones */ |
385 | setting = ide_find_setting(ide_generic_settings, name); | ||
516 | if (!setting) { | 386 | if (!setting) { |
517 | mutex_unlock(&ide_setting_mtx); | 387 | if (drive->settings) |
518 | goto parse_error; | 388 | setting = ide_find_setting(drive->settings, name); |
389 | if (!setting) { | ||
390 | mutex_unlock(&ide_setting_mtx); | ||
391 | goto parse_error; | ||
392 | } | ||
393 | } | ||
394 | if (for_real) { | ||
395 | mul_factor = setting->mulf ? setting->mulf(drive) : 1; | ||
396 | div_factor = setting->divf ? setting->divf(drive) : 1; | ||
397 | ide_write_setting(drive, setting, val * div_factor / mul_factor); | ||
519 | } | 398 | } |
520 | if (for_real) | ||
521 | ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor); | ||
522 | mutex_unlock(&ide_setting_mtx); | 399 | mutex_unlock(&ide_setting_mtx); |
523 | } | 400 | } |
524 | } while (!for_real++); | 401 | } while (!for_real++); |
@@ -561,11 +438,10 @@ static int proc_ide_read_dmodel | |||
561 | (char *page, char **start, off_t off, int count, int *eof, void *data) | 438 | (char *page, char **start, off_t off, int count, int *eof, void *data) |
562 | { | 439 | { |
563 | ide_drive_t *drive = (ide_drive_t *) data; | 440 | ide_drive_t *drive = (ide_drive_t *) data; |
564 | struct hd_driveid *id = drive->id; | 441 | char *m = (char *)&drive->id[ATA_ID_PROD]; |
565 | int len; | 442 | int len; |
566 | 443 | ||
567 | len = sprintf(page, "%.40s\n", | 444 | len = sprintf(page, "%.40s\n", m[0] ? m : "(none)"); |
568 | (id && id->model[0]) ? (char *)id->model : "(none)"); | ||
569 | PROC_IDE_READ_RETURN(page, start, off, count, eof, len); | 445 | PROC_IDE_READ_RETURN(page, start, off, count, eof, len); |
570 | } | 446 | } |
571 | 447 | ||
@@ -690,6 +566,10 @@ static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t | |||
690 | 566 | ||
691 | void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) | 567 | void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) |
692 | { | 568 | { |
569 | mutex_lock(&ide_setting_mtx); | ||
570 | drive->settings = driver->settings; | ||
571 | mutex_unlock(&ide_setting_mtx); | ||
572 | |||
693 | ide_add_proc_entries(drive->proc, driver->proc, drive); | 573 | ide_add_proc_entries(drive->proc, driver->proc, drive); |
694 | } | 574 | } |
695 | 575 | ||
@@ -726,7 +606,7 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) | |||
726 | * OTOH both ide_{read,write}_setting are only ever used under | 606 | * OTOH both ide_{read,write}_setting are only ever used under |
727 | * ide_setting_mtx. | 607 | * ide_setting_mtx. |
728 | */ | 608 | */ |
729 | auto_remove_settings(drive); | 609 | drive->settings = NULL; |
730 | spin_unlock_irqrestore(&ide_lock, flags); | 610 | spin_unlock_irqrestore(&ide_lock, flags); |
731 | mutex_unlock(&ide_setting_mtx); | 611 | mutex_unlock(&ide_setting_mtx); |
732 | } | 612 | } |