patch-2.1.77 linux/drivers/block/ide-proc.c
Next file: linux/drivers/block/ide.h
Previous file: linux/drivers/block/ide-pci.c
Back to the patch index
Back to the overall index
- Lines: 279
- Date:
Wed Dec 31 16:45:47 1997
- Orig file:
v2.1.76/linux/drivers/block/ide-proc.c
- Orig date:
Sun Dec 21 22:36:12 1997
diff -u --recursive --new-file v2.1.76/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/proc_ide.c Version 1.01 December 12, 1997
+ * linux/drivers/block/ide-proc.c Version 1.02 December 31, 1997
*
* Copyright (C) 1997-1998 Mark Lord
*/
@@ -13,15 +13,30 @@
* This should provide better utilities, and less kernel bloat.
*
* The entire pci config space for a PCI interface chipset can be
- * retrieved by just reading it. e.g. "cat /proc/ide3/pci"
+ * retrieved by just reading it. e.g. "cat /proc/ide3/config"
*
- * To modify registers, do something like:
- * echo "40:88" >/proc/ide/ide3/pci
+ * To modify registers *safely*, do something like:
+ * echo "P40:88" >/proc/ide/ide3/config
* That expression writes 0x88 to pci config register 0x40
* on the chip which controls ide3. Multiple tuples can be issued,
* and the writes will be completed as an atomic set:
- * echo "40:88 41:35 42:00 43:00" >/proc/ide/ide3/pci
- * All numbers must be pairs of ascii hex digits.
+ * echo "P40:88 P41:35 P42:00 P43:00" >/proc/ide/ide3/config
+ *
+ * All numbers must be specified using pairs of ascii hex digits.
+ * It is important to note that these writes will be performed
+ * after waiting for the IDE controller (both interfaces)
+ * to be completely idle, to ensure no corruption of I/O in progress.
+ *
+ * Non-PCI registers can also be written, using "R" in place of "P"
+ * in the above examples. The size of the port transfer is determined
+ * by the number of pairs of hex digits given for the data. If a two
+ * digit value is given, the write will be a byte operation; if four
+ * digits are used, the write will be performed as a 16-bit operation;
+ * and if eight digits are specified, a 32-bit "dword" write will be
+ * performed. Odd numbers of digits are not permitted.
+ *
+ * If there is an error *anywhere* in the string of registers/data
+ * then *none* of the writes will be performed.
*
* Also useful, "cat /proc/ide0/hda/identify" will issue an IDENTIFY
* (or PACKET_IDENTIFY) command to /dev/hda, and then dump out the
@@ -44,6 +59,7 @@
#include <linux/pci.h>
#include <linux/bios32.h>
#include <linux/ctype.h>
+#include <asm/io.h>
#include "ide.h"
#ifndef MIN
@@ -64,13 +80,14 @@
return digit;
}
-
-static int xx_xx_parse_error (const char *start, unsigned long maxlen)
+static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg)
{
- char errbuf[7];
- int i, len = MIN(6, maxlen);
+ char errbuf[16];
+ int i;
+ if (len >= sizeof(errbuf))
+ len = sizeof(errbuf) - 1;
for (i = 0; i < len; ++i) {
- char c = start[i];
+ char c = data[i];
if (!c || c == '\n')
c = '\0';
else if (iscntrl(c))
@@ -78,17 +95,17 @@
errbuf[i] = c;
}
errbuf[i] = '\0';
- printk("proc_ide: error: expected 'xx:xx', but got '%s'\n", errbuf);
+ printk("proc_ide: error: %s: '%s'\n", msg, errbuf);
return -EINVAL;
}
-static int proc_ide_write_pci
+static int proc_ide_write_config
(struct file *file, const char *buffer, unsigned long count, void *data)
{
ide_hwif_t *hwif = (ide_hwif_t *)data;
int for_real = 0;
- unsigned long n, flags;
- const char *start;
+ unsigned long startn = 0, n, flags;
+ const char *start = NULL, *msg = NULL;
if (!suser())
return -EACCES;
@@ -105,56 +122,109 @@
*/
save_flags(flags);
do {
- const char *p = buffer;
- n = count;
+ const char *p;
if (for_real) {
unsigned long timeout = jiffies + (3 * HZ);
+ ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup);
+ ide_hwgroup_t *mategroup = NULL;
+ if (hwif->mate && hwif->mate->hwgroup)
+ mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
cli(); /* ensure all PCI writes are done together */
- while (((ide_hwgroup_t *)(hwif->hwgroup))->active || (hwif->mate && ((ide_hwgroup_t *)(hwif->mate->hwgroup))->active)) {
- sti();
+ while (mygroup->active || (mategroup && mategroup->active)) {
+ restore_flags(flags);
if (0 < (signed long)(jiffies - timeout)) {
printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name);
- restore_flags(flags);
return -EBUSY;
}
cli();
}
}
- while (n) {
- int d1, d2, rc;
- byte reg, val;
+ p = buffer;
+ n = count;
+ while (n > 0) {
+ int d, digits;
+ unsigned int reg = 0, val = 0, is_pci;
start = p;
-#if 0
- printk("loop(%d): n=%ld, input=%.5s\n", for_real, n, p);
-#endif
- if (n < 5)
- goto parse_error;
- if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+ startn = n--;
+ switch (*p++) {
+ case 'R': is_pci = 0;
+ break;
+ case 'P': is_pci = 1;
+ break;
+ default: msg = "expected 'R' or 'P'";
+ goto parse_error;
+ }
+ digits = 0;
+ while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
+ reg = (reg << 4) | d;
+ --n;
+ ++p;
+ ++digits;
+ }
+ if (!digits || (digits > 4) || (is_pci && reg > 0xff)) {
+ msg = "bad/missing register number";
goto parse_error;
- reg = (d1 << 4) | d2;
- if (*p++ != ':')
+ }
+ if (--n < 0 || *p++ != ':') {
+ msg = "missing ':'";
goto parse_error;
- if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+ }
+ digits = 0;
+ while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
+ val = (val << 4) | d;
+ --n;
+ ++p;
+ ++digits;
+ }
+ if (digits != 2 && digits != 4 && digits != 8) {
+ msg = "bad data, 2/4/8 digits required";
goto parse_error;
- val = (d1 << 4) | d2;
- if (n > 5 && !isspace(*p))
+ }
+ if (n > 0 && !isspace(*p)) {
+ msg = "expected whitespace after data";
goto parse_error;
- n -= 5;
- while (n && isspace(*p)) {
+ }
+ while (n > 0 && isspace(*p)) {
--n;
++p;
}
+ if (is_pci && (reg & ((digits >> 1) - 1))) {
+ msg = "misaligned access";
+ goto parse_error;
+ }
if (for_real) {
#if 0
- printk("proc_ide_write_pci: reg=0x%02x, val=0x%02x\n", reg, val);
+ printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? 'PCI' : 'non-PCI', reg, val, digits);
#endif
- rc = pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, reg, val);
- if (rc) {
- restore_flags(flags);
- printk("proc_ide_write_pci: error writing bus %d fn %d reg 0x%02x value 0x%02x\n",
- hwif->pci_bus, hwif->pci_fn, reg, val);
- printk("proc_ide_write_pci: %s\n", pcibios_strerror(rc));
- return -EIO;
+ if (is_pci) {
+ int rc = 0;
+ switch (digits) {
+ case 2: msg = "byte";
+ rc = pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, reg, val);
+ break;
+ case 4: msg = "word";
+ rc = pcibios_write_config_word(hwif->pci_bus, hwif->pci_fn, reg, val);
+ break;
+ case 8: msg = "dword";
+ rc = pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, reg, val);
+ break;
+ }
+ if (rc) {
+ restore_flags(flags);
+ printk("proc_ide_write_config: error writing %s at bus %d fn %d reg 0x%x value 0x%x\n",
+ msg, hwif->pci_bus, hwif->pci_fn, reg, val);
+ printk("proc_ide_write_config: %s\n", pcibios_strerror(rc));
+ return -EIO;
+ }
+ } else { /* not pci */
+ switch (digits) {
+ case 2: outb(val, reg);
+ break;
+ case 4: outw(val, reg);
+ break;
+ case 8: outl(val, reg);
+ break;
+ }
}
}
}
@@ -163,25 +233,26 @@
return count;
parse_error:
restore_flags(flags);
- return xx_xx_parse_error(start, n);
+ printk("parse error\n");
+ return xx_xx_parse_error(start, startn, msg);
}
-static int proc_ide_read_pci
+static int proc_ide_read_config
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
ide_hwif_t *hwif = (ide_hwif_t *)data;
char *out = page;
int len, reg = 0;
- out += sprintf(out, "Bus %d Function %d Vendor %04x Device %04x Channel %d\n",
+ out += sprintf(out, "pci bus %d function %d vendor %04x device %04x channel %d\n",
hwif->pci_bus, hwif->pci_fn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
do {
byte val;
int rc = pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, reg, &val);
if (rc) {
- printk("proc_ide_read_pci: error reading bus %d fn %d reg 0x%02x\n",
+ printk("proc_ide_read_config: error reading bus %d fn %d reg 0x%02x\n",
hwif->pci_bus, hwif->pci_fn, reg);
- printk("proc_ide_read_pci: %s\n", pcibios_strerror(rc));
+ printk("proc_ide_read_config: %s\n", pcibios_strerror(rc));
return -EIO;
out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
} else
@@ -455,11 +526,11 @@
if (!hwif_ent) return;
#ifdef CONFIG_PCI
if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) {
- ent = create_proc_entry("pci", 0, hwif_ent);
+ ent = create_proc_entry("config", 0, hwif_ent);
if (!ent) return;
ent->data = hwif;
- ent->read_proc = proc_ide_read_pci;
- ent->write_proc = proc_ide_write_pci;;
+ ent->read_proc = proc_ide_read_config;
+ ent->write_proc = proc_ide_write_config;;
ent = create_proc_entry("model", 0, hwif_ent);
if (!ent) return;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov