1 /*
2 * linux/drivers/ide/ide-proc.c Version 1.03 January 2, 1998
3 *
4 * Copyright (C) 1997-1998 Mark Lord
5 */
6
7 /*
8 * This is the /proc/ide/ filesystem implementation.
9 *
10 * The major reason this exists is to provide sufficient access
11 * to driver and config data, such that user-mode programs can
12 * be developed to handle chipset tuning for most PCI interfaces.
13 * This should provide better utilities, and less kernel bloat.
14 *
15 * The entire pci config space for a PCI interface chipset can be
16 * retrieved by just reading it. e.g. "cat /proc/ide3/config"
17 *
18 * To modify registers *safely*, do something like:
19 * echo "P40:88" >/proc/ide/ide3/config
20 * That expression writes 0x88 to pci config register 0x40
21 * on the chip which controls ide3. Multiple tuples can be issued,
22 * and the writes will be completed as an atomic set:
23 * echo "P40:88 P41:35 P42:00 P43:00" >/proc/ide/ide3/config
24 *
25 * All numbers must be specified using pairs of ascii hex digits.
26 * It is important to note that these writes will be performed
27 * after waiting for the IDE controller (both interfaces)
28 * to be completely idle, to ensure no corruption of I/O in progress.
29 *
30 * Non-PCI registers can also be written, using "R" in place of "P"
31 * in the above examples. The size of the port transfer is determined
32 * by the number of pairs of hex digits given for the data. If a two
33 * digit value is given, the write will be a byte operation; if four
34 * digits are used, the write will be performed as a 16-bit operation;
35 * and if eight digits are specified, a 32-bit "dword" write will be
36 * performed. Odd numbers of digits are not permitted.
37 *
38 * If there is an error *anywhere* in the string of registers/data
39 * then *none* of the writes will be performed.
40 *
41 * Drive/Driver settings can be retrieved by reading the drive's
42 * "settings" files. e.g. "cat /proc/ide0/hda/settings"
43 * To write a new value "val" into a specific setting "name", use:
44 * echo "name:val" >/proc/ide/ide0/hda/settings
45 *
46 * Also useful, "cat /proc/ide0/hda/[identify, smart_values,
47 * smart_thresholds, capabilities]" will issue an IDENTIFY /
48 * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS /
49 * SENSE CAPABILITIES command to /dev/hda, and then dump out the
50 * returned data as 256 16-bit words. The "hdparm" utility will
51 * be updated someday soon to use this mechanism.
52 *
53 * Feel free to develop and distribute fancy GUI configuration
54 * utilities for your favorite PCI chipsets. I'll be working on
55 * one for the Promise 20246 someday soon. -ml
56 *
57 */
58
59 #include <linux/config.h>
60 #include <asm/uaccess.h>
61 #include <linux/errno.h>
62 #include <linux/sched.h>
63 #include <linux/proc_fs.h>
64 #include <linux/stat.h>
65 #include <linux/mm.h>
66 #include <linux/pci.h>
67 #include <linux/ctype.h>
68 #include <linux/ide.h>
69
70 #include <asm/io.h>
71
72 #ifndef MIN
73 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
74 #endif
75
76 #ifdef CONFIG_BLK_DEV_AEC62XX
77 extern byte aec62xx_proc;
78 int (*aec62xx_display_info)(char *, char **, off_t, int) = NULL;
79 #endif /* CONFIG_BLK_DEV_AEC62XX */
80 #ifdef CONFIG_BLK_DEV_ALI15X3
81 extern byte ali_proc;
82 int (*ali_display_info)(char *, char **, off_t, int) = NULL;
83 #endif /* CONFIG_BLK_DEV_ALI15X3 */
84 #ifdef CONFIG_BLK_DEV_AMD7409
85 extern byte amd7409_proc;
86 int (*amd7409_display_info)(char *, char **, off_t, int) = NULL;
87 #endif /* CONFIG_BLK_DEV_AMD7409 */
88 #ifdef CONFIG_BLK_DEV_CMD64X
89 extern byte cmd64x_proc;
90 int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL;
91 #endif /* CONFIG_BLK_DEV_CMD64X */
92 #ifdef CONFIG_BLK_DEV_CS5530
93 extern byte cs5530_proc;
94 int (*cs5530_display_info)(char *, char **, off_t, int) = NULL;
95 #endif /* CONFIG_BLK_DEV_CS5530 */
96 #ifdef CONFIG_BLK_DEV_HPT34X
97 extern byte hpt34x_proc;
98 int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL;
99 #endif /* CONFIG_BLK_DEV_HPT34X */
100 #ifdef CONFIG_BLK_DEV_HPT366
101 extern byte hpt366_proc;
102 int (*hpt366_display_info)(char *, char **, off_t, int) = NULL;
103 #endif /* CONFIG_BLK_DEV_HPT366 */
104 #ifdef CONFIG_BLK_DEV_OSB4
105 extern byte osb4_proc;
106 int (*osb4_display_info)(char *, char **, off_t, int) = NULL;
107 #endif /* CONFIG_BLK_DEV_OSB4 */
108 #ifdef CONFIG_BLK_DEV_PDC202XX
109 extern byte pdc202xx_proc;
110 int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL;
111 #endif /* CONFIG_BLK_DEV_PDC202XX */
112 #ifdef CONFIG_BLK_DEV_PIIX
113 extern byte piix_proc;
114 int (*piix_display_info)(char *, char **, off_t, int) = NULL;
115 #endif /* CONFIG_BLK_DEV_PIIX */
116 #ifdef CONFIG_BLK_DEV_SIS5513
117 extern byte sis_proc;
118 int (*sis_display_info)(char *, char **, off_t, int) = NULL;
119 #endif /* CONFIG_BLK_DEV_SIS5513 */
120 #ifdef CONFIG_BLK_DEV_SLC90E66
121 extern byte slc90e66_proc;
122 int (*slc90e66_display_info)(char *, char **, off_t, int) = NULL;
123 #endif /* CONFIG_BLK_DEV_SLC90E66 */
124 #ifdef CONFIG_BLK_DEV_VIA82CXXX
125 extern byte via_proc;
126 int (*via_display_info)(char *, char **, off_t, int) = NULL;
127 #endif /* CONFIG_BLK_DEV_VIA82CXXX */
128
129 static int ide_getxdigit(char c)
130 {
131 int digit;
132 if (isdigit(c))
133 digit = c - '';
134 else if (isxdigit(c))
135 digit = tolower(c) - 'a' + 10;
136 else
137 digit = -1;
138 return digit;
139 }
140
141 static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg)
142 {
143 char errbuf[16];
144 int i;
145 if (len >= sizeof(errbuf))
146 len = sizeof(errbuf) - 1;
147 for (i = 0; i < len; ++i) {
148 char c = data[i];
149 if (!c || c == '\n')
150 c = '\0';
151 else if (iscntrl(c))
152 c = '?';
153 errbuf[i] = c;
154 }
155 errbuf[i] = '\0';
156 printk("proc_ide: error: %s: '%s'\n", msg, errbuf);
157 return -EINVAL;
158 }
159
160 static struct proc_dir_entry * proc_ide_root = NULL;
161
162 static int proc_ide_write_config
163 (struct file *file, const char *buffer, unsigned long count, void *data)
164 {
165 ide_hwif_t *hwif = (ide_hwif_t *)data;
166 int for_real = 0;
167 unsigned long startn = 0, n, flags;
168 const char *start = NULL, *msg = NULL;
169
170 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
171 return -EACCES;
172 /*
173 * Skip over leading whitespace
174 */
175 while (count && isspace(*buffer)) {
176 --count;
177 ++buffer;
178 }
179 /*
180 * Do one full pass to verify all parameters,
181 * then do another to actually write the regs.
182 */
183 save_flags(flags); /* all CPUs */
184 do {
185 const char *p;
186 if (for_real) {
187 unsigned long timeout = jiffies + (3 * HZ);
188 ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup);
189 ide_hwgroup_t *mategroup = NULL;
190 if (hwif->mate && hwif->mate->hwgroup)
191 mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
192 cli(); /* all CPUs; ensure all writes are done together */
193 while (mygroup->busy || (mategroup && mategroup->busy)) {
194 sti(); /* all CPUs */
195 if (0 < (signed long)(jiffies - timeout)) {
196 printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
197 restore_flags(flags); /* all CPUs */
198 return -EBUSY;
199 }
200 cli(); /* all CPUs */
201 }
202 }
203 p = buffer;
204 n = count;
205 while (n > 0) {
206 int d, digits;
207 unsigned int reg = 0, val = 0, is_pci;
208 start = p;
209 startn = n--;
210 switch (*p++) {
211 case 'R': is_pci = 0;
212 break;
213 case 'P': is_pci = 1;
214 #ifdef CONFIG_BLK_DEV_IDEPCI
215 if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
216 break;
217 #endif /* CONFIG_BLK_DEV_IDEPCI */
218 msg = "not a PCI device";
219 goto parse_error;
220 default: msg = "expected 'R' or 'P'";
221 goto parse_error;
222 }
223 digits = 0;
224 while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
225 reg = (reg << 4) | d;
226 --n;
227 ++p;
228 ++digits;
229 }
230 if (!digits || (digits > 4) || (is_pci && reg > 0xff)) {
231 msg = "bad/missing register number";
232 goto parse_error;
233 }
234 if (n-- == 0 || *p++ != ':') {
235 msg = "missing ':'";
236 goto parse_error;
237 }
238 digits = 0;
239 while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
240 val = (val << 4) | d;
241 --n;
242 ++p;
243 ++digits;
244 }
245 if (digits != 2 && digits != 4 && digits != 8) {
246 msg = "bad data, 2/4/8 digits required";
247 goto parse_error;
248 }
249 if (n > 0 && !isspace(*p)) {
250 msg = "expected whitespace after data";
251 goto parse_error;
252 }
253 while (n > 0 && isspace(*p)) {
254 --n;
255 ++p;
256 }
257 #ifdef CONFIG_BLK_DEV_IDEPCI
258 if (is_pci && (reg & ((digits >> 1) - 1))) {
259 msg = "misaligned access";
260 goto parse_error;
261 }
262 #endif /* CONFIG_BLK_DEV_IDEPCI */
263 if (for_real) {
264 #if 0
265 printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits);
266 #endif
267 if (is_pci) {
268 #ifdef CONFIG_BLK_DEV_IDEPCI
269 int rc = 0;
270 struct pci_dev *dev = hwif->pci_dev;
271 switch (digits) {
272 case 2: msg = "byte";
273 rc = pci_write_config_byte(dev, reg, val);
274 break;
275 case 4: msg = "word";
276 rc = pci_write_config_word(dev, reg, val);
277 break;
278 case 8: msg = "dword";
279 rc = pci_write_config_dword(dev, reg, val);
280 break;
281 }
282 if (rc) {
283 restore_flags(flags); /* all CPUs */
284 printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
285 msg, dev->bus->number, dev->devfn, reg, val);
286 printk("proc_ide_write_config: error %d\n", rc);
287 return -EIO;
288 }
289 #endif /* CONFIG_BLK_DEV_IDEPCI */
290 } else { /* not pci */
291 #if !defined(__mc68000__) && !defined(CONFIG_APUS)
292
293 /*
294 * Geert Uytterhoeven
295 *
296 * unless you can explain me what it really does.
297 * On m68k, we don't have outw() and outl() yet,
298 * and I need a good reason to implement it.
299 *
300 * BTW, IMHO the main remaining portability problem with the IDE driver
301 * is that it mixes IO (ioport) and MMIO (iomem) access on different platforms.
302 *
303 * I think all accesses should be done using
304 *
305 * ide_in[bwl](ide_device_instance, offset)
306 * ide_out[bwl](ide_device_instance, value, offset)
307 *
308 * so the architecture specific code can #define ide_{in,out}[bwl] to the
309 * appropriate function.
310 *
311 */
312 switch (digits) {
313 case 2: outb(val, reg);
314 break;
315 case 4: outw(val, reg);
316 break;
317 case 8: outl(val, reg);
318 break;
319 }
320 #endif /* !__mc68000__ && !CONFIG_APUS */
321 }
322 }
323 }
324 } while (!for_real++);
325 restore_flags(flags); /* all CPUs */
326 return count;
327 parse_error:
328 restore_flags(flags); /* all CPUs */
329 printk("parse error\n");
330 return xx_xx_parse_error(start, startn, msg);
331 }
332
333 static int proc_ide_read_config
334 (char *page, char **start, off_t off, int count, int *eof, void *data)
335 {
336 char *out = page;
337 int len;
338
339 #ifdef CONFIG_BLK_DEV_IDEPCI
340 ide_hwif_t *hwif = (ide_hwif_t *)data;
341 struct pci_dev *dev = hwif->pci_dev;
342 if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) {
343 int reg = 0;
344
345 out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n",
346 dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
347 do {
348 byte val;
349 int rc = pci_read_config_byte(dev, reg, &val);
350 if (rc) {
351 printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n",
352 rc, dev->bus->number, dev->devfn, reg);
353 out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
354 } else
355 out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
356 } while (reg < 0x100);
357 } else
358 #endif /* CONFIG_BLK_DEV_IDEPCI */
359 out += sprintf(out, "(none)\n");
360 len = out - page;
361 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
362 }
363
364
365 static int ide_getdigit(char c)
366 {
367 int digit;
368 if (isdigit(c))
369 digit = c - '';
370 else
371 digit = -1;
372 return digit;
373 }
374
375 static int proc_ide_read_drivers
376 (char *page, char **start, off_t off, int count, int *eof, void *data)
377 {
378 char *out = page;
379 int len;
380 ide_module_t *p = ide_modules;
381 ide_driver_t *driver;
382
383 while (p) {
384 driver = (ide_driver_t *) p->info;
385 if (driver)
386 out += sprintf(out, "%s version %s\n", driver->name, driver->version);
387 p = p->next;
388 }
389 len = out - page;
390 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
391 }
392
393 static int proc_ide_read_imodel
394 (char *page, char **start, off_t off, int count, int *eof, void *data)
395 {
396 ide_hwif_t *hwif = (ide_hwif_t *) data;
397 int len;
398 const char *name;
399
400 switch (hwif->chipset) {
401 case ide_unknown: name = "(none)"; break;
402 case ide_generic: name = "generic"; break;
403 case ide_pci: name = "pci"; break;
404 case ide_cmd640: name = "cmd640"; break;
405 case ide_dtc2278: name = "dtc2278"; break;
406 case ide_ali14xx: name = "ali14xx"; break;
407 case ide_qd6580: name = "qd6580"; break;
408 case ide_umc8672: name = "umc8672"; break;
409 case ide_ht6560b: name = "ht6560b"; break;
410 case ide_pdc4030: name = "pdc4030"; break;
411 case ide_rz1000: name = "rz1000"; break;
412 case ide_trm290: name = "trm290"; break;
413 case ide_cmd646: name = "cmd646"; break;
414 case ide_cy82c693: name = "cy82c693"; break;
415 case ide_4drives: name = "4drives"; break;
416 case ide_pmac: name = "mac-io"; break;
417 default: name = "(unknown)"; break;
418 }
419 len = sprintf(page, "%s\n", name);
420 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
421 }
422
423 static int proc_ide_read_mate
424 (char *page, char **start, off_t off, int count, int *eof, void *data)
425 {
426 ide_hwif_t *hwif = (ide_hwif_t *) data;
427 int len;
428
429 if (hwif && hwif->mate && hwif->mate->present)
430 len = sprintf(page, "%s\n", hwif->mate->name);
431 else
432 len = sprintf(page, "(none)\n");
433 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
434 }
435
436 static int proc_ide_read_channel
437 (char *page, char **start, off_t off, int count, int *eof, void *data)
438 {
439 ide_hwif_t *hwif = (ide_hwif_t *) data;
440 int len;
441
442 page[0] = hwif->channel ? '1' : '';
443 page[1] = '\n';
444 len = 2;
445 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
446 }
447
448 static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
449 {
450 return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf);
451 }
452
453 static int proc_ide_read_identify
454 (char *page, char **start, off_t off, int count, int *eof, void *data)
455 {
456 ide_drive_t *drive = (ide_drive_t *)data;
457 int len = 0, i = 0;
458
459 if (drive && !proc_ide_get_identify(drive, page)) {
460 unsigned short *val = ((unsigned short *)page) + 2;
461 char *out = ((char *)val) + (SECTOR_WORDS * 4);
462 page = out;
463 do {
464 out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
465 val += 1;
466 } while (i < (SECTOR_WORDS * 2));
467 len = out - page;
468 }
469 else
470 len = sprintf(page, "\n");
471 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
472 }
473
474 static int proc_ide_read_settings
475 (char *page, char **start, off_t off, int count, int *eof, void *data)
476 {
477 ide_drive_t *drive = (ide_drive_t *) data;
478 ide_settings_t *setting = (ide_settings_t *) drive->settings;
479 char *out = page;
480 int len, rc, mul_factor, div_factor;
481
482 out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
483 out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
484 while(setting) {
485 mul_factor = setting->mul_factor;
486 div_factor = setting->div_factor;
487 out += sprintf(out, "%-24s", setting->name);
488 if ((rc = ide_read_setting(drive, setting)) >= 0)
489 out += sprintf(out, "%-16d", rc * mul_factor / div_factor);
490 else
491 out += sprintf(out, "%-16s", "write-only");
492 out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
493 if (setting->rw & SETTING_READ)
494 out += sprintf(out, "r");
495 if (setting->rw & SETTING_WRITE)
496 out += sprintf(out, "w");
497 out += sprintf(out, "\n");
498 setting = setting->next;
499 }
500 len = out - page;
501 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
502 }
503
504 #define MAX_LEN 30
505
506 static int proc_ide_write_settings
507 (struct file *file, const char *buffer, unsigned long count, void *data)
508 {
509 ide_drive_t *drive = (ide_drive_t *) data;
510 char name[MAX_LEN + 1];
511 int for_real = 0, len;
512 unsigned long n;
513 const char *start = NULL;
514 ide_settings_t *setting;
515
516 if (!capable(CAP_SYS_ADMIN))
517 return -EACCES;
518 /*
519 * Skip over leading whitespace
520 */
521 while (count && isspace(*buffer)) {
522 --count;
523 ++buffer;
524 }
525 /*
526 * Do one full pass to verify all parameters,
527 * then do another to actually write the new settings.
528 */
529 do {
530 const char *p;
531 p = buffer;
532 n = count;
533 while (n > 0) {
534 int d, digits;
535 unsigned int val = 0;
536 start = p;
537
538 while (n > 0 && *p != ':') {
539 --n;
540 p++;
541 }
542 if (*p != ':')
543 goto parse_error;
544 len = IDE_MIN(p - start, MAX_LEN);
545 strncpy(name, start, IDE_MIN(len, MAX_LEN));
546 name[len] = 0;
547
548 if (n > 0) {
549 --n;
550 p++;
551 } else
552 goto parse_error;
553
554 digits = 0;
555 while (n > 0 && (d = ide_getdigit(*p)) >= 0) {
556 val = (val * 10) + d;
557 --n;
558 ++p;
559 ++digits;
560 }
561 if (n > 0 && !isspace(*p))
562 goto parse_error;
563 while (n > 0 && isspace(*p)) {
564 --n;
565 ++p;
566 }
567 setting = ide_find_setting_by_name(drive, name);
568 if (!setting)
569 goto parse_error;
570
571 if (for_real)
572 ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
573 }
574 } while (!for_real++);
575 return count;
576 parse_error:
577 printk("proc_ide_write_settings(): parse error\n");
578 return -EINVAL;
579 }
580
581 int proc_ide_read_capacity
582 (char *page, char **start, off_t off, int count, int *eof, void *data)
583 {
584 ide_drive_t *drive = (ide_drive_t *) data;
585 ide_driver_t *driver = (ide_driver_t *) drive->driver;
586 int len;
587
588 if (!driver)
589 len = sprintf(page, "(none)\n");
590 else
591 len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
592 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
593 }
594
595 int proc_ide_read_geometry
596 (char *page, char **start, off_t off, int count, int *eof, void *data)
597 {
598 ide_drive_t *drive = (ide_drive_t *) data;
599 char *out = page;
600 int len;
601
602 out += sprintf(out,"physical %d/%d/%d\n", drive->cyl, drive->head, drive->sect);
603 out += sprintf(out,"logical %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
604 len = out - page;
605 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
606 }
607
608 static int proc_ide_read_dmodel
609 (char *page, char **start, off_t off, int count, int *eof, void *data)
610 {
611 ide_drive_t *drive = (ide_drive_t *) data;
612 struct hd_driveid *id = drive->id;
613 int len;
614
615 len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
616 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
617 }
618
619 static int proc_ide_read_driver
620 (char *page, char **start, off_t off, int count, int *eof, void *data)
621 {
622 ide_drive_t *drive = (ide_drive_t *) data;
623 ide_driver_t *driver = (ide_driver_t *) drive->driver;
624 int len;
625
626 if (!driver)
627 len = sprintf(page, "(none)\n");
628 else
629 len = sprintf(page, "%s version %s\n", driver->name, driver->version);
630 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
631 }
632
633 static int proc_ide_write_driver
634 (struct file *file, const char *buffer, unsigned long count, void *data)
635 {
636 ide_drive_t *drive = (ide_drive_t *) data;
637
638 if (!capable(CAP_SYS_ADMIN))
639 return -EACCES;
640 if (ide_replace_subdriver(drive, buffer))
641 return -EINVAL;
642 return count;
643 }
644
645 static int proc_ide_read_media
646 (char *page, char **start, off_t off, int count, int *eof, void *data)
647 {
648 ide_drive_t *drive = (ide_drive_t *) data;
649 const char *media;
650 int len;
651
652 switch (drive->media) {
653 case ide_disk: media = "disk\n";
654 break;
655 case ide_cdrom: media = "cdrom\n";
656 break;
657 case ide_tape: media = "tape\n";
658 break;
659 case ide_floppy:media = "floppy\n";
660 break;
661 default: media = "UNKNOWN\n";
662 break;
663 }
664 strcpy(page,media);
665 len = strlen(media);
666 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
667 }
668
669 static ide_proc_entry_t generic_drive_entries[] = {
670 { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, proc_ide_write_driver },
671 { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL },
672 { "media", S_IFREG|S_IRUGO, proc_ide_read_media, NULL },
673 { "model", S_IFREG|S_IRUGO, proc_ide_read_dmodel, NULL },
674 { "settings", S_IFREG|S_IRUSR|S_IWUSR,proc_ide_read_settings, proc_ide_write_settings },
675 { NULL, 0, NULL, NULL }
676 };
677
678 void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
679 {
680 struct proc_dir_entry *ent;
681
682 if (!dir || !p)
683 return;
684 while (p->name != NULL) {
685 ent = create_proc_entry(p->name, p->mode, dir);
686 if (!ent) return;
687 ent->nlink = 1;
688 ent->data = data;
689 ent->read_proc = p->read_proc;
690 ent->write_proc = p->write_proc;
691 p++;
692 }
693 }
694
695 void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
696 {
697 if (!dir || !p)
698 return;
699 while (p->name != NULL) {
700 remove_proc_entry(p->name, dir);
701 p++;
702 }
703 }
704
705 static void create_proc_ide_drives(ide_hwif_t *hwif)
706 {
707 int d;
708 struct proc_dir_entry *ent;
709 struct proc_dir_entry *parent = hwif->proc;
710 char name[64];
711
712 for (d = 0; d < MAX_DRIVES; d++) {
713 ide_drive_t *drive = &hwif->drives[d];
714 ide_driver_t *driver = drive->driver;
715
716 if (!drive->present)
717 continue;
718 if (drive->proc)
719 continue;
720
721 drive->proc = proc_mkdir(drive->name, parent);
722 if (drive->proc) {
723 ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
724 if (driver) {
725 ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
726 ide_add_proc_entries(drive->proc, driver->proc, drive);
727 }
728 }
729 sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
730 ent = proc_symlink(drive->name, proc_ide_root, name);
731 if (!ent) return;
732 }
733 }
734
735 void destroy_proc_ide_drives(ide_hwif_t *hwif)
736 {
737 int d;
738
739 for (d = 0; d < MAX_DRIVES; d++) {
740 ide_drive_t *drive = &hwif->drives[d];
741 ide_driver_t *driver = drive->driver;
742
743 if (!drive->proc)
744 continue;
745 if (driver)
746 ide_remove_proc_entries(drive->proc, driver->proc);
747 ide_remove_proc_entries(drive->proc, generic_drive_entries);
748 remove_proc_entry(drive->name, proc_ide_root);
749 remove_proc_entry(drive->name, hwif->proc);
750 drive->proc = NULL;
751 }
752 }
753
754 static ide_proc_entry_t hwif_entries[] = {
755 { "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL },
756 { "config", S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config, proc_ide_write_config },
757 { "mate", S_IFREG|S_IRUGO, proc_ide_read_mate, NULL },
758 { "model", S_IFREG|S_IRUGO, proc_ide_read_imodel, NULL },
759 { NULL, 0, NULL, NULL }
760 };
761
762 void create_proc_ide_interfaces(void)
763 {
764 int h;
765
766 for (h = 0; h < MAX_HWIFS; h++) {
767 ide_hwif_t *hwif = &ide_hwifs[h];
768
769 if (!hwif->present)
770 continue;
771 if (!hwif->proc) {
772 hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
773 if (!hwif->proc)
774 return;
775 ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
776 }
777 create_proc_ide_drives(hwif);
778 }
779 }
780
781 static void destroy_proc_ide_interfaces(void)
782 {
783 int h;
784
785 for (h = 0; h < MAX_HWIFS; h++) {
786 ide_hwif_t *hwif = &ide_hwifs[h];
787 int exist = (hwif->proc != NULL);
788 #if 0
789 if (!hwif->present)
790 continue;
791 #endif
792 if (exist) {
793 destroy_proc_ide_drives(hwif);
794 ide_remove_proc_entries(hwif->proc, hwif_entries);
795 remove_proc_entry(hwif->name, proc_ide_root);
796 hwif->proc = NULL;
797 } else
798 continue;
799 }
800 }
801
802 void proc_ide_create(void)
803 {
804 proc_ide_root = proc_mkdir("ide", 0);
805 if (!proc_ide_root) return;
806
807 create_proc_ide_interfaces();
808
809 create_proc_read_entry("drivers", 0, proc_ide_root,
810 proc_ide_read_drivers, NULL);
811
812 #ifdef CONFIG_BLK_DEV_AEC62XX
813 if ((aec62xx_display_info) && (aec62xx_proc))
814 create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info);
815 #endif /* CONFIG_BLK_DEV_AEC62XX */
816 #ifdef CONFIG_BLK_DEV_ALI15X3
817 if ((ali_display_info) && (ali_proc))
818 create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
819 #endif /* CONFIG_BLK_DEV_ALI15X3 */
820 #ifdef CONFIG_BLK_DEV_AMD7409
821 if ((amd7409_display_info) && (amd7409_proc))
822 create_proc_info_entry("amd7409", 0, proc_ide_root, amd7409_display_info);
823 #endif /* CONFIG_BLK_DEV_AMD7409 */
824 #ifdef CONFIG_BLK_DEV_CMD64X
825 if ((cmd64x_display_info) && (cmd64x_proc))
826 create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info);
827 #endif /* CONFIG_BLK_DEV_CMD64X */
828 #ifdef CONFIG_BLK_DEV_CS5530
829 if ((cs5530_display_info) && (cs5530_proc))
830 create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info);
831 #endif /* CONFIG_BLK_DEV_CS5530 */
832 #ifdef CONFIG_BLK_DEV_HPT34X
833 if ((hpt34x_display_info) && (hpt34x_proc))
834 create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info);
835 #endif /* CONFIG_BLK_DEV_HPT34X */
836 #ifdef CONFIG_BLK_DEV_HPT366
837 if ((hpt366_display_info) && (hpt366_proc))
838 create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info);
839 #endif /* CONFIG_BLK_DEV_HPT366 */
840 #ifdef CONFIG_BLK_DEV_OSB4
841 if ((osb4_display_info) && (osb4_proc))
842 create_proc_info_entry("osb4", 0, proc_ide_root, osb4_display_info);
843 #endif /* CONFIG_BLK_DEV_OSB4 */
844 #ifdef CONFIG_BLK_DEV_PDC202XX
845 if ((pdc202xx_display_info) && (pdc202xx_proc))
846 create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info);
847 #endif /* CONFIG_BLK_DEV_PDC202XX */
848 #ifdef CONFIG_BLK_DEV_PIIX
849 if ((piix_display_info) && (piix_proc))
850 create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info);
851 #endif /* CONFIG_BLK_DEV_PIIX */
852 #ifdef CONFIG_BLK_DEV_SIS5513
853 if ((sis_display_info) && (sis_proc))
854 create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info);
855 #endif /* CONFIG_BLK_DEV_SIS5513 */
856 #ifdef CONFIG_BLK_DEV_SLC90E66
857 if ((slc90e66_display_info) && (slc90e66_proc))
858 create_proc_info_entry("slc90e66", 0, proc_ide_root, slc90e66_display_info);
859 #endif /* CONFIG_BLK_DEV_SLC90E66 */
860 #ifdef CONFIG_BLK_DEV_VIA82CXXX
861 if ((via_display_info) && (via_proc))
862 create_proc_info_entry("via", 0, proc_ide_root, via_display_info);
863 #endif /* CONFIG_BLK_DEV_VIA82CXXX */
864 }
865
866 void proc_ide_destroy(void)
867 {
868 /*
869 * Mmmm.. does this free up all resources,
870 * or do we need to do a more proper cleanup here ??
871 */
872 #ifdef CONFIG_BLK_DEV_AEC62XX
873 if ((aec62xx_display_info) && (aec62xx_proc))
874 remove_proc_entry("ide/aec62xx",0);
875 #endif /* CONFIG_BLK_DEV_AEC62XX */
876 #ifdef CONFIG_BLK_DEV_ALI15X3
877 if ((ali_display_info) && (ali_proc))
878 remove_proc_entry("ide/ali",0);
879 #endif /* CONFIG_BLK_DEV_ALI15X3 */
880 #ifdef CONFIG_BLK_DEV_AMD7409
881 if ((amd7409_display_info) && (amd7409_proc))
882 remove_proc_entry("ide/amd7409",0);
883 #endif /* CONFIG_BLK_DEV_AMD7409 */
884 #ifdef CONFIG_BLK_DEV_CMD64X
885 if ((cmd64x_display_info) && (cmd64x_proc))
886 remove_proc_entry("ide/cmd64x",0);
887 #endif /* CONFIG_BLK_DEV_CMD64X */
888 #ifdef CONFIG_BLK_DEV_CS5530
889 if ((cs5530_display_info) && (cs5530_proc))
890 remove_proc_entry("ide/cs5530",0);
891 #endif /* CONFIG_BLK_DEV_CS5530 */
892 #ifdef CONFIG_BLK_DEV_HPT34X
893 if ((hpt34x_display_info) && (hpt34x_proc))
894 remove_proc_entry("ide/hpt34x",0);
895 #endif /* CONFIG_BLK_DEV_HPT34X */
896 #ifdef CONFIG_BLK_DEV_HPT366
897 if ((hpt366_display_info) && (hpt366_proc))
898 remove_proc_entry("ide/hpt366",0);
899 #endif /* CONFIG_BLK_DEV_HPT366 */
900 #ifdef CONFIG_BLK_DEV_OSB4
901 if ((osb4_display_info) && (osb4_proc))
902 remove_proc_entry("ide/osb4",0);
903 #endif /* CONFIG_BLK_DEV_OSB4 */
904 #ifdef CONFIG_BLK_DEV_PDC202XX
905 if ((pdc202xx_display_info) && (pdc202xx_proc))
906 remove_proc_entry("ide/pdc202xx",0);
907 #endif /* CONFIG_BLK_DEV_PDC202XX */
908 #ifdef CONFIG_BLK_DEV_PIIX
909 if ((piix_display_info) && (piix_proc))
910 remove_proc_entry("ide/piix",0);
911 #endif /* CONFIG_BLK_DEV_PIIX */
912 #ifdef CONFIG_BLK_DEV_SIS5513
913 if ((sis_display_info) && (sis_proc))
914 remove_proc_entry("ide/sis", 0);
915 #endif /* CONFIG_BLK_DEV_SIS5513 */
916 #ifdef CONFIG_BLK_DEV_SLC90E66
917 if ((slc90e66_display_info) && (slc90e66_proc))
918 remove_proc_entry("ide/slc90e66",0);
919 #endif /* CONFIG_BLK_DEV_SLC90E66 */
920 #ifdef CONFIG_BLK_DEV_VIA82CXXX
921 if ((via_display_info) && (via_proc))
922 remove_proc_entry("ide/via",0);
923 #endif /* CONFIG_BLK_DEV_VIA82CXXX */
924
925 remove_proc_entry("ide/drivers", 0);
926 destroy_proc_ide_interfaces();
927 remove_proc_entry("ide", 0);
928 }
929
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.