00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #include <linux/config.h>
00060 #include <asm/uaccess.h>
00061 #include <linux/errno.h>
00062 #include <linux/sched.h>
00063 #include <linux/proc_fs.h>
00064 #include <linux/stat.h>
00065 #include <linux/mm.h>
00066 #include <linux/pci.h>
00067 #include <linux/ctype.h>
00068 #include <asm/io.h>
00069 #include "ide.h"
00070
00071 #ifndef MIN
00072 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
00073 #endif
00074
00075 static int ide_getxdigit(char c)
00076 {
00077 int digit;
00078 if (isdigit(c))
00079 digit = c - '0';
00080 else if (isxdigit(c))
00081 digit = tolower(c) - 'a' + 10;
00082 else
00083 digit = -1;
00084 return digit;
00085 }
00086
00087 static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg)
00088 {
00089 char errbuf[16];
00090 int i;
00091 if (len >= sizeof(errbuf))
00092 len = sizeof(errbuf) - 1;
00093 for (i = 0; i < len; ++i) {
00094 char c = data[i];
00095 if (!c || c == '\n')
00096 c = '\0';
00097 else if (iscntrl(c))
00098 c = '?';
00099 errbuf[i] = c;
00100 }
00101 errbuf[i] = '\0';
00102 printk("proc_ide: error: %s: '%s'\n", msg, errbuf);
00103 return -EINVAL;
00104 }
00105
00106 static int proc_ide_write_config
00107 (struct file *file, const char *buffer, unsigned long count, void *data)
00108 {
00109 ide_hwif_t *hwif = (ide_hwif_t *)data;
00110 int for_real = 0;
00111 unsigned long startn = 0, n, flags;
00112 const char *start = NULL, *msg = NULL;
00113
00114 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
00115 return -EACCES;
00116
00117
00118
00119 while (count && isspace(*buffer)) {
00120 --count;
00121 ++buffer;
00122 }
00123
00124
00125
00126
00127 save_flags(flags);
00128 do {
00129 const char *p;
00130 if (for_real) {
00131 unsigned long timeout = jiffies + (3 * HZ);
00132 ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup);
00133 ide_hwgroup_t *mategroup = NULL;
00134 if (hwif->mate && hwif->mate->hwgroup)
00135 mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
00136 cli();
00137 while (mygroup->busy || (mategroup && mategroup->busy)) {
00138 sti();
00139 if (0 < (signed long)(jiffies - timeout)) {
00140 printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
00141 restore_flags(flags);
00142 return -EBUSY;
00143 }
00144 cli();
00145 }
00146 }
00147 p = buffer;
00148 n = count;
00149 while (n > 0) {
00150 int d, digits;
00151 unsigned int reg = 0, val = 0, is_pci;
00152 start = p;
00153 startn = n--;
00154 switch (*p++) {
00155 case 'R': is_pci = 0;
00156 break;
00157 case 'P': is_pci = 1;
00158 #ifdef CONFIG_BLK_DEV_IDEPCI
00159 if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
00160 break;
00161 #endif
00162 msg = "not a PCI device";
00163 goto parse_error;
00164 default: msg = "expected 'R' or 'P'";
00165 goto parse_error;
00166 }
00167 digits = 0;
00168 while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
00169 reg = (reg << 4) | d;
00170 --n;
00171 ++p;
00172 ++digits;
00173 }
00174 if (!digits || (digits > 4) || (is_pci && reg > 0xff)) {
00175 msg = "bad/missing register number";
00176 goto parse_error;
00177 }
00178 if (n-- == 0 || *p++ != ':') {
00179 msg = "missing ':'";
00180 goto parse_error;
00181 }
00182 digits = 0;
00183 while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
00184 val = (val << 4) | d;
00185 --n;
00186 ++p;
00187 ++digits;
00188 }
00189 if (digits != 2 && digits != 4 && digits != 8) {
00190 msg = "bad data, 2/4/8 digits required";
00191 goto parse_error;
00192 }
00193 if (n > 0 && !isspace(*p)) {
00194 msg = "expected whitespace after data";
00195 goto parse_error;
00196 }
00197 while (n > 0 && isspace(*p)) {
00198 --n;
00199 ++p;
00200 }
00201 #ifdef CONFIG_BLK_DEV_IDEPCI
00202 if (is_pci && (reg & ((digits >> 1) - 1))) {
00203 msg = "misaligned access";
00204 goto parse_error;
00205 }
00206 #endif
00207 if (for_real) {
00208 #if 0
00209 printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? 'PCI' : 'non-PCI', reg, val, digits);
00210 #endif
00211 if (is_pci) {
00212 #ifdef CONFIG_BLK_DEV_IDEPCI
00213 int rc = 0;
00214 struct pci_dev *dev = hwif->pci_dev;
00215 switch (digits) {
00216 case 2: msg = "byte";
00217 rc = pci_write_config_byte(dev, reg, val);
00218 break;
00219 case 4: msg = "word";
00220 rc = pci_write_config_word(dev, reg, val);
00221 break;
00222 case 8: msg = "dword";
00223 rc = pci_write_config_dword(dev, reg, val);
00224 break;
00225 }
00226 if (rc) {
00227 restore_flags(flags);
00228 printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
00229 msg, dev->bus->number, dev->devfn, reg, val);
00230 printk("proc_ide_write_config: error %d\n", rc);
00231 return -EIO;
00232 }
00233 #endif
00234 } else {
00235 switch (digits) {
00236 case 2: outb(val, reg);
00237 break;
00238 case 4: outw(val, reg);
00239 break;
00240 case 8: outl(val, reg);
00241 break;
00242 }
00243 }
00244 }
00245 }
00246 } while (!for_real++);
00247 restore_flags(flags);
00248 return count;
00249 parse_error:
00250 restore_flags(flags);
00251 printk("parse error\n");
00252 return xx_xx_parse_error(start, startn, msg);
00253 }
00254
00255 static int proc_ide_read_config
00256 (char *page, char **start, off_t off, int count, int *eof, void *data)
00257 {
00258 char *out = page;
00259 int len;
00260
00261 #ifdef CONFIG_BLK_DEV_IDEPCI
00262 ide_hwif_t *hwif = (ide_hwif_t *)data;
00263 struct pci_dev *dev = hwif->pci_dev;
00264 if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) {
00265 int reg = 0;
00266
00267 out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n",
00268 dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
00269 do {
00270 byte val;
00271 int rc = pci_read_config_byte(dev, reg, &val);
00272 if (rc) {
00273 printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n",
00274 rc, dev->bus->number, dev->devfn, reg);
00275 out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
00276 } else
00277 out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
00278 } while (reg < 0x100);
00279 } else
00280 #endif
00281 out += sprintf(out, "(none)\n");
00282 len = out - page;
00283 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00284 }
00285
00286
00287 static int ide_getdigit(char c)
00288 {
00289 int digit;
00290 if (isdigit(c))
00291 digit = c - '0';
00292 else
00293 digit = -1;
00294 return digit;
00295 }
00296
00297 static int proc_ide_read_drivers
00298 (char *page, char **start, off_t off, int count, int *eof, void *data)
00299 {
00300 char *out = page;
00301 int len;
00302 ide_module_t *p = ide_modules;
00303 ide_driver_t *driver;
00304
00305 while (p) {
00306 driver = (ide_driver_t *) p->info;
00307 if (p->type == IDE_DRIVER_MODULE && driver)
00308 out += sprintf(out, "%s version %s\n", driver->name, driver->version);
00309 p = p->next;
00310 }
00311 len = out - page;
00312 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00313 }
00314
00315 static int proc_ide_read_imodel
00316 (char *page, char **start, off_t off, int count, int *eof, void *data)
00317 {
00318 ide_hwif_t *hwif = (ide_hwif_t *) data;
00319 int len;
00320 const char *name;
00321
00322 switch (hwif->chipset) {
00323 case ide_unknown: name = "(none)"; break;
00324 case ide_generic: name = "generic"; break;
00325 case ide_pci: name = "pci"; break;
00326 case ide_cmd640: name = "cmd640"; break;
00327 case ide_dtc2278: name = "dtc2278"; break;
00328 case ide_ali14xx: name = "ali14xx"; break;
00329 case ide_qd6580: name = "qd6580"; break;
00330 case ide_umc8672: name = "umc8672"; break;
00331 case ide_ht6560b: name = "ht6560b"; break;
00332 case ide_pdc4030: name = "pdc4030"; break;
00333 case ide_rz1000: name = "rz1000"; break;
00334 case ide_trm290: name = "trm290"; break;
00335 case ide_4drives: name = "4drives"; break;
00336 case ide_pmac: name = "mac-io"; break;
00337 default: name = "(unknown)"; break;
00338 }
00339 len = sprintf(page, "%s\n", name);
00340 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00341 }
00342
00343 static int proc_ide_read_mate
00344 (char *page, char **start, off_t off, int count, int *eof, void *data)
00345 {
00346 ide_hwif_t *hwif = (ide_hwif_t *) data;
00347 int len;
00348
00349 if (hwif && hwif->mate && hwif->mate->present)
00350 len = sprintf(page, "%s\n", hwif->mate->name);
00351 else
00352 len = sprintf(page, "(none)\n");
00353 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00354 }
00355
00356 static int proc_ide_read_channel
00357 (char *page, char **start, off_t off, int count, int *eof, void *data)
00358 {
00359 ide_hwif_t *hwif = (ide_hwif_t *) data;
00360 int len;
00361
00362 page[0] = hwif->channel ? '1' : '0';
00363 page[1] = '\n';
00364 len = 2;
00365 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00366 }
00367
00368 static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
00369 {
00370 return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf);
00371 }
00372
00373 static int proc_ide_read_identify
00374 (char *page, char **start, off_t off, int count, int *eof, void *data)
00375 {
00376 ide_drive_t *drive = (ide_drive_t *)data;
00377 int len = 0, i = 0;
00378
00379 if (!proc_ide_get_identify(drive, page)) {
00380 unsigned short *val = ((unsigned short *)page) + 2;
00381 char *out = ((char *)val) + (SECTOR_WORDS * 4);
00382 page = out;
00383 do {
00384 out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
00385 val += 1;
00386 } while (i < (SECTOR_WORDS * 2));
00387 len = out - page;
00388 }
00389 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00390 }
00391
00392 static int proc_ide_read_settings
00393 (char *page, char **start, off_t off, int count, int *eof, void *data)
00394 {
00395 ide_drive_t *drive = (ide_drive_t *) data;
00396 ide_settings_t *setting = (ide_settings_t *) drive->settings;
00397 char *out = page;
00398 int len, rc, mul_factor, div_factor;
00399
00400 out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
00401 out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
00402 while(setting) {
00403 mul_factor = setting->mul_factor;
00404 div_factor = setting->div_factor;
00405 out += sprintf(out, "%-24s", setting->name);
00406 if ((rc = ide_read_setting(drive, setting)) >= 0)
00407 out += sprintf(out, "%-16d", rc * mul_factor / div_factor);
00408 else
00409 out += sprintf(out, "%-16s", "write-only");
00410 out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
00411 if (setting->rw & SETTING_READ)
00412 out += sprintf(out, "r");
00413 if (setting->rw & SETTING_WRITE)
00414 out += sprintf(out, "w");
00415 out += sprintf(out, "\n");
00416 setting = setting->next;
00417 }
00418 len = out - page;
00419 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00420 }
00421
00422 #define MAX_LEN 30
00423
00424 static int proc_ide_write_settings
00425 (struct file *file, const char *buffer, unsigned long count, void *data)
00426 {
00427 ide_drive_t *drive = (ide_drive_t *) data;
00428 char name[MAX_LEN + 1];
00429 int for_real = 0, len;
00430 unsigned long n;
00431 const char *start = NULL;
00432 ide_settings_t *setting;
00433
00434 if (!capable(CAP_SYS_ADMIN))
00435 return -EACCES;
00436
00437
00438
00439 while (count && isspace(*buffer)) {
00440 --count;
00441 ++buffer;
00442 }
00443
00444
00445
00446
00447 do {
00448 const char *p;
00449 p = buffer;
00450 n = count;
00451 while (n > 0) {
00452 int d, digits;
00453 unsigned int val = 0;
00454 start = p;
00455
00456 while (n > 0 && *p != ':') {
00457 --n;
00458 p++;
00459 }
00460 if (*p != ':')
00461 goto parse_error;
00462 len = IDE_MIN(p - start, MAX_LEN);
00463 strncpy(name, start, IDE_MIN(len, MAX_LEN));
00464 name[len] = 0;
00465
00466 if (n > 0) {
00467 --n;
00468 p++;
00469 } else
00470 goto parse_error;
00471
00472 digits = 0;
00473 while (n > 0 && (d = ide_getdigit(*p)) >= 0) {
00474 val = (val * 10) + d;
00475 --n;
00476 ++p;
00477 ++digits;
00478 }
00479 if (n > 0 && !isspace(*p))
00480 goto parse_error;
00481 while (n > 0 && isspace(*p)) {
00482 --n;
00483 ++p;
00484 }
00485 setting = ide_find_setting_by_name(drive, name);
00486 if (!setting)
00487 goto parse_error;
00488
00489 if (for_real)
00490 ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
00491 }
00492 } while (!for_real++);
00493 return count;
00494 parse_error:
00495 printk("proc_ide_write_settings(): parse error\n");
00496 return -EINVAL;
00497 }
00498
00499 int proc_ide_read_capacity
00500 (char *page, char **start, off_t off, int count, int *eof, void *data)
00501 {
00502 ide_drive_t *drive = (ide_drive_t *) data;
00503 ide_driver_t *driver = (ide_driver_t *) drive->driver;
00504 int len;
00505
00506 if (!driver)
00507 len = sprintf(page, "(none)\n");
00508 else
00509 len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
00510 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00511 }
00512
00513 int proc_ide_read_geometry
00514 (char *page, char **start, off_t off, int count, int *eof, void *data)
00515 {
00516 ide_drive_t *drive = (ide_drive_t *) data;
00517 char *out = page;
00518 int len;
00519
00520 out += sprintf(out,"physical %d/%d/%d\n",
00521 drive->cyl, drive->head, drive->sect);
00522 out += sprintf(out,"logical %d/%d/%d\n",
00523 drive->bios_cyl, drive->bios_head, drive->bios_sect);
00524 len = out - page;
00525 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00526 }
00527
00528 static int proc_ide_read_dmodel
00529 (char *page, char **start, off_t off, int count, int *eof, void *data)
00530 {
00531 ide_drive_t *drive = (ide_drive_t *) data;
00532 struct hd_driveid *id = drive->id;
00533 int len;
00534
00535 len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
00536 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00537 }
00538
00539 static int proc_ide_read_driver
00540 (char *page, char **start, off_t off, int count, int *eof, void *data)
00541 {
00542 ide_drive_t *drive = (ide_drive_t *) data;
00543 ide_driver_t *driver = (ide_driver_t *) drive->driver;
00544 int len;
00545
00546 if (!driver)
00547 len = sprintf(page, "(none)\n");
00548 else
00549 len = sprintf(page, "%s version %s\n", driver->name, driver->version);
00550 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00551 }
00552
00553 static int proc_ide_write_driver
00554 (struct file *file, const char *buffer, unsigned long count, void *data)
00555 {
00556 ide_drive_t *drive = (ide_drive_t *) data;
00557
00558 if (!capable(CAP_SYS_ADMIN))
00559 return -EACCES;
00560 if (ide_replace_subdriver(drive, buffer))
00561 return -EINVAL;
00562 return count;
00563 }
00564
00565 static int proc_ide_read_media
00566 (char *page, char **start, off_t off, int count, int *eof, void *data)
00567 {
00568 ide_drive_t *drive = (ide_drive_t *) data;
00569 const char *media;
00570 int len;
00571
00572 switch (drive->media) {
00573 case ide_disk: media = "disk\n";
00574 break;
00575 case ide_cdrom: media = "cdrom\n";
00576 break;
00577 case ide_tape: media = "tape\n";
00578 break;
00579 case ide_floppy:media = "floppy\n";
00580 break;
00581 default: media = "UNKNOWN\n";
00582 break;
00583 }
00584 strcpy(page,media);
00585 len = strlen(media);
00586 PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
00587 }
00588
00589 static ide_proc_entry_t generic_drive_entries[] = {
00590 { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, proc_ide_write_driver },
00591 { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL },
00592 { "media", S_IFREG|S_IRUGO, proc_ide_read_media, NULL },
00593 { "model", S_IFREG|S_IRUGO, proc_ide_read_dmodel, NULL },
00594 { "settings", S_IFREG|S_IRUSR|S_IWUSR,proc_ide_read_settings, proc_ide_write_settings },
00595 { NULL, 0, NULL, NULL }
00596 };
00597
00598 void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
00599 {
00600 struct proc_dir_entry *ent;
00601
00602 if (!dir || !p)
00603 return;
00604 while (p->name != NULL) {
00605 ent = create_proc_entry(p->name, p->mode, dir);
00606 if (!ent) return;
00607 ent->nlink = 1;
00608 ent->data = data;
00609 ent->read_proc = p->read_proc;
00610 ent->write_proc = p->write_proc;
00611 p++;
00612 }
00613 }
00614
00615 void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
00616 {
00617 if (!dir || !p)
00618 return;
00619 while (p->name != NULL) {
00620 remove_proc_entry(p->name, dir);
00621 p++;
00622 }
00623 }
00624
00625 static int proc_ide_readlink(struct proc_dir_entry *de, char *page)
00626 {
00627 int n = (de->name[2] - 'a') / 2;
00628 return sprintf(page, "ide%d/%s", n, de->name);
00629 }
00630
00631 static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent, struct proc_dir_entry *root)
00632 {
00633 int d;
00634 struct proc_dir_entry *ent;
00635
00636 for (d = 0; d < MAX_DRIVES; d++) {
00637 ide_drive_t *drive = &hwif->drives[d];
00638
00639 if (!drive->present)
00640 continue;
00641 drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
00642 if (drive->proc)
00643 ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
00644
00645 ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, root);
00646 if (!ent) return;
00647 ent->data = drive;
00648 ent->readlink_proc = proc_ide_readlink;
00649 ent->nlink = 1;
00650 }
00651 }
00652
00653 static ide_proc_entry_t hwif_entries[] = {
00654 { "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL },
00655 { "config", S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config, proc_ide_write_config },
00656 { "mate", S_IFREG|S_IRUGO, proc_ide_read_mate, NULL },
00657 { "model", S_IFREG|S_IRUGO, proc_ide_read_imodel, NULL },
00658 { NULL, 0, NULL, NULL }
00659 };
00660
00661 static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
00662 {
00663 int h;
00664 struct proc_dir_entry *hwif_ent;
00665
00666 for (h = 0; h < MAX_HWIFS; h++) {
00667 ide_hwif_t *hwif = &ide_hwifs[h];
00668
00669 if (!hwif->present)
00670 continue;
00671 hwif_ent = create_proc_entry(hwif->name, S_IFDIR, parent);
00672 if (!hwif_ent) return;
00673 ide_add_proc_entries(hwif_ent, hwif_entries, hwif);
00674 create_proc_ide_drives(hwif, hwif_ent, parent);
00675 }
00676 }
00677
00678 void proc_ide_create(void)
00679 {
00680 struct proc_dir_entry *root, *ent;
00681 root = create_proc_entry("ide", S_IFDIR, 0);
00682 if (!root) return;
00683 create_proc_ide_interfaces(root);
00684
00685 ent = create_proc_entry("drivers", 0, root);
00686 if (!ent) return;
00687 ent->read_proc = proc_ide_read_drivers;
00688 }
00689
00690 void proc_ide_destroy(void)
00691 {
00692
00693
00694
00695
00696 remove_proc_entry("ide/drivers", 0);
00697 remove_proc_entry("ide", 0);
00698 }