patch-2.3.6 linux/drivers/misc/parport_procfs.c
Next file: linux/drivers/misc/parport_share.c
Previous file: linux/drivers/misc/parport_pc.c
Back to the patch index
Back to the overall index
- Lines: 727
- Date:
Thu Jun 3 16:21:47 1999
- Orig file:
v2.3.5/linux/drivers/misc/parport_procfs.c
- Orig date:
Wed Jun 2 14:44:39 1999
diff -u --recursive --new-file v2.3.5/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
@@ -1,4 +1,4 @@
-/* Parallel port /proc interface code.
+/* Sysctl interface for parport devices.
*
* Authors: David Campbell <campbell@torque.net>
* Tim Waugh <tim@cyberelk.demon.co.uk>
@@ -14,400 +14,425 @@
#include <linux/string.h>
#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
-#include <linux/proc_fs.h>
#include <linux/parport.h>
#include <linux/ctype.h>
+#include <linux/sysctl.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-
-#ifdef CONFIG_PROC_FS
-
-struct proc_dir_entry *base = NULL;
-
-static int irq_write_proc(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- int retval = -EINVAL;
- int newirq = PARPORT_IRQ_NONE;
- struct parport *pp = (struct parport *)data;
- int oldirq = pp->irq;
-
-/*
- * We can have these valid cases:
- * "none" (count == 4 || count == 5)
- * decimal number (count == 2 || count == 3)
- * octal number (count == 3 || count == 4)
- * hex number (count == 4 || count == 5)
- * all other cases are -EINVAL
- *
- * Note: newirq is alredy set up to NONE.
- *
- * -RF
- */
- if (count > 5 || count < 1)
- goto out;
-
- if (isdigit(buffer[0]))
- newirq = simple_strtoul(buffer, NULL, 0);
- else if (strncmp(buffer, "none", 4) != 0) {
- if (buffer[0] < 32)
- /* Things like '\n' are harmless */
- retval = count;
-
- goto out;
- }
+#include <asm/uaccess.h>
- retval = count;
+#ifdef CONFIG_SYSCTL
- if (oldirq == newirq)
- goto out;
- if (pp->flags & PARPORT_FLAG_COMA)
- goto out_ok;
-
- retval = -EBUSY;
+static int do_active_device(ctl_table *table, int write, struct file *filp,
+ void *result, size_t *lenp)
+{
+ struct parport *port = (struct parport *)table->extra1;
+ char buffer[256];
+ struct pardevice *dev;
+ int len = 0;
- /*
- * Here we don' t need the irq version of spinlocks because
- * the parport_lowlevel irq handler must not change the cad,
- * and so has no one reason to write_lock() the cad_lock spinlock.
- * -arca
- */
- read_lock(&pp->cad_lock);
+ if (write) /* can't happen anyway */
+ return -EACCES;
- if (pp->cad)
- {
- read_unlock(&pp->cad_lock);
- return retval;
+ if (filp->f_pos) {
+ *lenp = 0;
+ return 0;
}
-
- if (newirq != PARPORT_IRQ_NONE) {
- retval = request_irq(newirq, pp->ops->interrupt,
- 0, pp->name, pp);
- if (retval)
- {
- read_unlock(&pp->cad_lock);
- return retval;
+
+ for (dev = port->devices; dev ; dev = dev->next) {
+ if(dev == port->cad) {
+ len += sprintf(buffer, "%s\n", dev->name);
}
}
- if (oldirq != PARPORT_IRQ_NONE)
- free_irq(oldirq, pp);
-
- retval = count;
+ if(!len) {
+ len += sprintf(buffer, "%s\n", "none");
+ }
- read_unlock(&pp->cad_lock);
+ if (len > *lenp)
+ len = *lenp;
+ else
+ *lenp = len;
-out_ok:
- pp->irq = newirq;
+ filp->f_pos += len;
-out:
- return retval;
+ return copy_to_user(result, buffer, len) ? -EFAULT : 0;
}
-static int irq_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+#if 0 && defined (CONFIG_PARPORT_1284)
+static int do_autoprobe(ctl_table *table, int write, struct file *filp,
+ void *result, size_t *lenp)
{
- struct parport *pp = (struct parport *)data;
- int len;
-
- if (pp->irq == PARPORT_IRQ_NONE) {
- len = sprintf(page, "none\n");
- } else {
-#ifdef __sparc__
- len = sprintf(page, "%s\n", __irq_itoa(pp->irq));
-#else
- len = sprintf(page, "%d\n", pp->irq);
-#endif
+ struct parport_device_info *info = table->extra2;
+ const char *str;
+ char buffer[256];
+ int len = 0;
+
+ if (write) /* permissions stop this */
+ return -EACCES;
+
+ if (filp->f_pos) {
+ *lenp = 0;
+ return 0;
}
- *start = 0;
- *eof = 1;
- return len;
-}
+ if ((str = info->class_name) != NULL)
+ len += sprintf (buffer + len, "CLASS:%s;\n", str);
-static int devices_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct parport *pp = (struct parport *)data;
- struct pardevice *pd1;
- int len=0;
+ if ((str = info->model) != NULL)
+ len += sprintf (buffer + len, "MODEL:%s;\n", str);
- for (pd1 = pp->devices; pd1 ; pd1 = pd1->next) {
- if (pd1 == pp->cad)
- page[len++] = '+';
- else
- page[len++] = ' ';
+ if ((str = info->mfr) != NULL)
+ len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str);
- len += sprintf(page+len, "%s", pd1->name);
+ if ((str = info->description) != NULL)
+ len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str);
- page[len++] = '\n';
- }
-
- *start = 0;
- *eof = 1;
- return len;
+ if ((str = info->cmdset) != NULL)
+ len += sprintf (buffer + len, "COMMAND SET:%s;\n", str);
+
+ if (len > *lenp)
+ len = *lenp;
+ else
+ *lenp = len;
+
+ filp->f_pos += len;
+
+ return copy_to_user (result, buffer, len) ? -EFAULT : 0;
}
+#endif /* IEEE1284.3 support. */
-static int hardware_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int do_hardware(ctl_table *table, int write, struct file *filp,
+ void *result, size_t *lenp)
{
- struct parport *pp = (struct parport *)data;
- int len=0;
+ struct parport *port = (struct parport *)table->extra1;
+ char buffer[256];
+ int len = 0;
+
+ if (filp->f_pos) {
+ *lenp = 0;
+ return 0;
+ }
+
+ if (write) /* can't happen anyway */
+ return -EACCES;
- len += sprintf(page+len, "base:\t0x%lx\n",pp->base);
+ len += sprintf(buffer+len, "base:\t0x%lx", port->base);
+ if (port->base_hi)
+ len += sprintf(buffer+len, " (0x%lx)", port->base_hi);
+ buffer[len++] = '\n';
- if (pp->irq == PARPORT_IRQ_NONE) {
- len += sprintf(page+len, "irq:\tnone\n");
+ if (port->irq == PARPORT_IRQ_NONE) {
+ len += sprintf(buffer+len, "irq:\tnone\n");
} else {
#ifdef __sparc__
- len += sprintf(page+len, "irq:\t%s\n",__irq_itoa(pp->irq));
+ len += sprintf(buffer+len, "irq:\t%s\n",
+ __irq_itoa(port->irq));
#else
- len += sprintf(page+len, "irq:\t%d\n",pp->irq);
+ len += sprintf(buffer+len, "irq:\t%d\n", port->irq);
#endif
}
- if (pp->dma == PARPORT_DMA_NONE)
- len += sprintf(page+len, "dma:\tnone\n");
+ if (port->dma == PARPORT_DMA_NONE)
+ len += sprintf(buffer+len, "dma:\tnone\n");
else
- len += sprintf(page+len, "dma:\t%d\n",pp->dma);
+ len += sprintf(buffer+len, "dma:\t%d\n", port->dma);
- len += sprintf(page+len, "modes:\t");
+ len += sprintf(buffer+len, "modes:\t");
{
-#define printmode(x) {if(pp->modes&PARPORT_MODE_PC##x){len+=sprintf(page+len,"%s%s",f?",":"",#x);f++;}}
+#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
int f = 0;
- printmode(SPP);
- printmode(PS2);
- printmode(EPP);
- printmode(ECP);
- printmode(ECPEPP);
- printmode(ECPPS2);
+ printmode(PCSPP);
+ printmode(PCPS2);
+ printmode(PCEPP);
+ printmode(PCECP);
#undef printmode
}
- page[len++] = '\n';
+ buffer[len++] = '\n';
+
+ if (len > *lenp)
+ len = *lenp;
+ else
+ *lenp = len;
+
+ filp->f_pos += len;
- *start = 0;
- *eof = 1;
- return len;
+ return copy_to_user(result, buffer, len) ? -EFAULT : 0;
}
-static int autoprobe_read_proc (char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct parport *pp = (struct parport *) data;
- int len = 0;
- const char *str;
+#define PARPORT_PORT_DIR(child) { 0, NULL, NULL, 0, 0555, child }
+#define PARPORT_PARPORT_DIR(child) { DEV_PARPORT, "parport", \
+ NULL, 0, 0555, child }
+#define PARPORT_DEV_DIR(child) { CTL_DEV, "dev", NULL, 0, 0555, child }
+#define PARPORT_DEVICES_ROOT_DIR { DEV_PARPORT_DEVICES, "devices", \
+ NULL, 0, 0555, NULL }
+
+
+struct parport_sysctl_table {
+ struct ctl_table_header *sysctl_header;
+ ctl_table vars[9];
+ ctl_table device_dir[2];
+ ctl_table port_dir[2];
+ ctl_table parport_dir[2];
+ ctl_table dev_dir[2];
+};
+
+static const struct parport_sysctl_table parport_sysctl_template = {
+ NULL,
+ {
+ { DEV_PARPORT_SPINTIME, "spintime",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec },
+ { DEV_PARPORT_HARDWARE, "hardware",
+ NULL, 0, 0444, NULL,
+ &do_hardware },
+ PARPORT_DEVICES_ROOT_DIR,
+#if 0 && defined(CONFIG_PARPORT_1284)
+ { DEV_PARPORT_AUTOPROBE, "autoprobe",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+ { DEV_PARPORT_AUTOPROBE + 1, "autoprobe0",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+ { DEV_PARPORT_AUTOPROBE + 2, "autoprobe1",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+ { DEV_PARPORT_AUTOPROBE + 3, "autoprobe2",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+ { DEV_PARPORT_AUTOPROBE + 4, "autoprobe3",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+#endif /* IEEE 1284 support */
+ {0}
+ },
+ { {DEV_PARPORT_DEVICES_ACTIVE, "active", NULL, 0, 444, NULL,
+ &do_active_device }, {0}},
+ { PARPORT_PORT_DIR(NULL), {0}},
+ { PARPORT_PARPORT_DIR(NULL), {0}},
+ { PARPORT_DEV_DIR(NULL), {0}}
+};
+
+struct parport_device_sysctl_table
+{
+ struct ctl_table_header *sysctl_header;
+ ctl_table vars[2];
+ ctl_table device_dir[2];
+ ctl_table devices_root_dir[2];
+ ctl_table port_dir[2];
+ ctl_table parport_dir[2];
+ ctl_table dev_dir[2];
+};
+
+static const struct parport_device_sysctl_table
+parport_device_sysctl_template = {
+ NULL,
+ {
+ { DEV_PARPORT_DEVICE_TIMESLICE, "timeslice",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec },
+ },
+ { {0, NULL, NULL, 0, 0555, NULL}, {0}},
+ { PARPORT_DEVICES_ROOT_DIR, {0}},
+ { PARPORT_PORT_DIR(NULL), {0}},
+ { PARPORT_PARPORT_DIR(NULL), {0}},
+ { PARPORT_DEV_DIR(NULL), {0}}
+};
+
+struct parport_default_sysctl_table
+{
+ struct ctl_table_header *sysctl_header;
+ ctl_table vars[3];
+ ctl_table default_dir[2];
+ ctl_table parport_dir[2];
+ ctl_table dev_dir[2];
+};
+
+extern unsigned long parport_default_timeslice;
+extern int parport_default_spintime;
+
+static struct parport_default_sysctl_table
+parport_default_sysctl_table = {
+ NULL,
+ {
+ { DEV_PARPORT_DEFAULT_TIMESLICE, "timeslice",
+ &parport_default_timeslice,
+ sizeof(parport_default_timeslice), 0644, NULL,
+ &proc_dointvec },
+ { DEV_PARPORT_DEFAULT_SPINTIME, "spintime",
+ &parport_default_spintime,
+ sizeof(parport_default_timeslice), 0644, NULL,
+ &proc_dointvec },
+ {0}
+ },
+ { { DEV_PARPORT_DEFAULT, "default", NULL, 0, 0555,
+ parport_default_sysctl_table.vars },{0}},
+ {
+ PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
+ {0}},
+ { PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), {0}}
+};
- page[0] = '\0';
- if ((str = pp->probe_info.class_name) != NULL)
- len += sprintf (page+len, "CLASS:%s;\n", str);
+int parport_proc_register(struct parport *port)
+{
+ struct parport_sysctl_table *t;
+ int i;
- if ((str = pp->probe_info.model) != NULL)
- len += sprintf (page+len, "MODEL:%s;\n", str);
+ t = kmalloc(sizeof(*t), GFP_KERNEL);
+ if (t == NULL)
+ return -ENOMEM;
+ memcpy(t, &parport_sysctl_template, sizeof(*t));
- if ((str = pp->probe_info.mfr) != NULL)
- len += sprintf (page+len, "MANUFACTURER:%s;\n", str);
+ t->device_dir[0].extra1 = port;
- if ((str = pp->probe_info.description) != NULL)
- len += sprintf (page+len, "DESCRIPTION:%s;\n", str);
+ for (i = 0; i < 8; i++)
+ t->vars[i].extra1 = port;
- if ((str = pp->probe_info.cmdset) != NULL)
- len += sprintf (page+len, "COMMAND SET:%s;\n", str);
+#if 0 /* Wait for IEEE 1284 support */
+ t->vars[0].data = &port->spintime;
+#endif
+ t->vars[2].child = t->device_dir;
+
+ for (i = 0; i < 5; i++)
+#if 0
+ t->vars[3 + i].extra2 = &port->probe_info[i];
+#else
+ t->vars[3 + i].extra2 = &port->probe_info;
+#endif
- *start = 0;
- *eof = 1;
- return len;
-}
+ t->port_dir[0].procname = port->name;
+ t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
-static inline void destroy_proc_entry(struct proc_dir_entry *root,
- struct proc_dir_entry **d)
-{
- proc_unregister(root, (*d)->low_ino);
- kfree(*d);
- *d = NULL;
+ t->port_dir[0].child = t->vars;
+ t->parport_dir[0].child = t->port_dir;
+ t->dev_dir[0].child = t->parport_dir;
+
+ t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
+ if (t->sysctl_header == NULL) {
+ kfree(t);
+ t = NULL;
+ }
+ port->sysctl_table = t;
+ return 0;
}
-static void destroy_proc_tree(struct parport *pp) {
- if (pp->pdir.entry) {
- if (pp->pdir.irq)
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq);
- if (pp->pdir.devices)
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices);
- if (pp->pdir.hardware)
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.hardware);
- if (pp->pdir.probe)
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.probe);
- destroy_proc_entry(base, &pp->pdir.entry);
+int parport_proc_unregister(struct parport *port)
+{
+ if (port->sysctl_table) {
+ struct parport_sysctl_table *t = port->sysctl_table;
+ port->sysctl_table = NULL;
+ unregister_sysctl_table(t->sysctl_header);
+ kfree(t);
}
+ return 0;
}
-static struct proc_dir_entry *new_proc_entry(const char *name, mode_t mode,
- struct proc_dir_entry *parent,
- unsigned short ino,
- struct parport *p)
+int parport_device_proc_register(struct pardevice *device)
{
- struct proc_dir_entry *ent;
-
- ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
- if (!ent)
- return NULL;
-
- memset(ent, 0, sizeof(struct proc_dir_entry));
+ struct parport_device_sysctl_table *t;
+ struct parport * port = device->port;
- if (mode == S_IFDIR)
- mode |= S_IRUGO | S_IXUGO;
- else if (mode == 0)
- mode = S_IFREG | S_IRUGO;
-
- ent->low_ino = ino;
- ent->name = name;
- ent->namelen = strlen(name);
- ent->mode = mode;
+ t = kmalloc(sizeof(*t), GFP_KERNEL);
+ if (t == NULL)
+ return -ENOMEM;
+ memcpy(t, &parport_device_sysctl_template, sizeof(*t));
+
+ t->dev_dir[0].child = t->parport_dir;
+ t->parport_dir[0].child = t->port_dir;
+ t->port_dir[0].procname = port->name;
+ t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
+ t->port_dir[0].child = t->devices_root_dir;
+ t->devices_root_dir[0].child = t->device_dir;
+
+#if 0 && defined(CONFIG_PARPORT_1284)
+
+ t->device_dir[0].ctl_name =
+ parport_device_num(port->number, port->muxport,
+ device->daisy)
+ + 1; /* nb 0 isn't legal here */
- if (S_ISDIR(mode))
- {
- if (p && p->ops)
- ent->fill_inode = p->ops->fill_inode;
- ent->nlink = 2;
- } else
- ent->nlink = 1;
+#else /* No IEEE 1284 support */
- proc_register(parent, ent);
+ /* parport_device_num isn't available. */
+ t->device_dir[0].ctl_name = 1;
- return ent;
-}
+#endif /* IEEE 1284 support or not */
-/*
- * This is called as the fill_inode function when an inode
- * is going into (fill = 1) or out of service (fill = 0).
- * We use it here to manage the module use counts.
- *
- * Note: only the top-level directory needs to do this; if
- * a lower level is referenced, the parent will be as well.
- */
-static void parport_modcount(struct inode *inode, int fill)
-{
-#ifdef MODULE
- if (fill)
- inc_parport_count();
- else
- dec_parport_count();
-#endif
+ t->device_dir[0].procname = device->name;
+ t->device_dir[0].extra1 = device;
+ t->device_dir[0].child = t->vars;
+ t->vars[0].data = &device->timeslice;
+
+ t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
+ if (t->sysctl_header == NULL) {
+ kfree(t);
+ t = NULL;
+ }
+ device->sysctl_table = t;
+ return 0;
}
-int parport_proc_init(void)
+int parport_device_proc_unregister(struct pardevice *device)
{
- base = new_proc_entry("parport", S_IFDIR, &proc_root,PROC_PARPORT,
- NULL);
- if (base == NULL) {
- printk(KERN_ERR "Unable to initialise /proc/parport.\n");
- return 0;
+ if (device->sysctl_table) {
+ struct parport_device_sysctl_table *t = device->sysctl_table;
+ device->sysctl_table = NULL;
+ unregister_sysctl_table(t->sysctl_header);
+ kfree(t);
}
- base->fill_inode = &parport_modcount;
-
- return 1;
+ return 0;
}
-void parport_proc_cleanup(void)
+int parport_default_proc_register(void)
{
- if (base) {
- proc_unregister(&proc_root,base->low_ino);
- kfree(base);
- base = NULL;
- }
+ parport_default_sysctl_table.sysctl_header =
+ register_sysctl_table(parport_default_sysctl_table.dev_dir, 0);
+ return 0;
}
-int parport_proc_register(struct parport *pp)
+int parport_default_proc_unregister(void)
{
- memset(&pp->pdir, 0, sizeof(struct parport_dir));
-
- if (base == NULL) {
- printk(KERN_ERR "parport_proc not initialised yet.\n");
- return 1;
+ if (parport_default_sysctl_table.sysctl_header) {
+ unregister_sysctl_table(parport_default_sysctl_table.
+ sysctl_header);
+ parport_default_sysctl_table.sysctl_header = NULL;
}
-
- strncpy(pp->pdir.name, pp->name + strlen("parport"),
- sizeof(pp->pdir.name));
-
- pp->pdir.entry = new_proc_entry(pp->pdir.name, S_IFDIR, base, 0, pp);
- if (pp->pdir.entry == NULL)
- goto out_fail;
-
- pp->pdir.irq = new_proc_entry("irq", S_IFREG | S_IRUGO | S_IWUSR,
- pp->pdir.entry, 0, pp);
- if (pp->pdir.irq == NULL)
- goto out_fail;
-
- pp->pdir.irq->read_proc = irq_read_proc;
- pp->pdir.irq->write_proc = irq_write_proc;
- pp->pdir.irq->data = pp;
-
- pp->pdir.devices = new_proc_entry("devices", 0, pp->pdir.entry, 0, pp);
- if (pp->pdir.devices == NULL)
- goto out_fail;
-
- pp->pdir.devices->read_proc = devices_read_proc;
- pp->pdir.devices->data = pp;
-
- pp->pdir.hardware = new_proc_entry("hardware", 0, pp->pdir.entry, 0,
- pp);
- if (pp->pdir.hardware == NULL)
- goto out_fail;
-
- pp->pdir.hardware->read_proc = hardware_read_proc;
- pp->pdir.hardware->data = pp;
-
- pp->pdir.probe = new_proc_entry("autoprobe", 0, pp->pdir.entry, 0, pp);
- if (pp->pdir.probe == NULL)
- goto out_fail;
-
- pp->pdir.probe->read_proc = autoprobe_read_proc;
- pp->pdir.probe->data = pp;
-
return 0;
+}
-out_fail:
+#else /* no sysctl */
- printk(KERN_ERR "%s: failure registering /proc/ entry.\n", pp->name);
- destroy_proc_tree(pp);
- return 1;
+int parport_proc_register(struct parport *pp)
+{
+ return 0;
}
int parport_proc_unregister(struct parport *pp)
{
- destroy_proc_tree(pp);
return 0;
}
-#else
-
-int parport_proc_register(struct parport *p)
+int parport_device_proc_register(struct pardevice *device)
{
return 0;
}
-int parport_proc_unregister(struct parport *p)
+int parport_device_proc_unregister(struct pardevice *device)
{
return 0;
}
-int parport_proc_init(void)
+int parport_default_proc_register (void)
{
return 0;
}
-void parport_proc_cleanup(void)
+int parport_default_proc_unregister (void)
{
+ return 0;
}
-
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)