~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/ide/ide-proc.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.