ide-proc.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:27k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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