linux/drivers/pnp/pnpbios/proc.c
<<
>>
Prefs
   1/*
   2 * /proc/bus/pnp interface for Plug and Play devices
   3 *
   4 * Written by David Hinds, dahinds@users.sourceforge.net
   5 * Modified by Thomas Hood
   6 *
   7 * The .../devices and .../<node> and .../boot/<node> files are
   8 * utilized by the lspnp and setpnp utilities, supplied with the
   9 * pcmcia-cs package.
  10 *     http://pcmcia-cs.sourceforge.net
  11 *
  12 * The .../escd file is utilized by the lsescd utility written by
  13 * Gunther Mayer.
  14 *
  15 * The .../legacy_device_resources file is not used yet.
  16 *
  17 * The other files are human-readable.
  18 */
  19
  20#include <linux/module.h>
  21#include <linux/kernel.h>
  22#include <linux/slab.h>
  23#include <linux/types.h>
  24#include <linux/proc_fs.h>
  25#include <linux/pnp.h>
  26#include <linux/seq_file.h>
  27#include <linux/init.h>
  28
  29#include <asm/uaccess.h>
  30
  31#include "pnpbios.h"
  32
  33static struct proc_dir_entry *proc_pnp = NULL;
  34static struct proc_dir_entry *proc_pnp_boot = NULL;
  35
  36static int pnpconfig_proc_show(struct seq_file *m, void *v)
  37{
  38        struct pnp_isa_config_struc pnps;
  39
  40        if (pnp_bios_isapnp_config(&pnps))
  41                return -EIO;
  42        seq_printf(m, "structure_revision %d\n"
  43                      "number_of_CSNs %d\n"
  44                      "ISA_read_data_port 0x%x\n",
  45                   pnps.revision, pnps.no_csns, pnps.isa_rd_data_port);
  46        return 0;
  47}
  48
  49static int pnpconfig_proc_open(struct inode *inode, struct file *file)
  50{
  51        return single_open(file, pnpconfig_proc_show, NULL);
  52}
  53
  54static const struct file_operations pnpconfig_proc_fops = {
  55        .owner          = THIS_MODULE,
  56        .open           = pnpconfig_proc_open,
  57        .read           = seq_read,
  58        .llseek         = seq_lseek,
  59        .release        = single_release,
  60};
  61
  62static int escd_info_proc_show(struct seq_file *m, void *v)
  63{
  64        struct escd_info_struc escd;
  65
  66        if (pnp_bios_escd_info(&escd))
  67                return -EIO;
  68        seq_printf(m, "min_ESCD_write_size %d\n"
  69                        "ESCD_size %d\n"
  70                        "NVRAM_base 0x%x\n",
  71                        escd.min_escd_write_size,
  72                        escd.escd_size, escd.nv_storage_base);
  73        return 0;
  74}
  75
  76static int escd_info_proc_open(struct inode *inode, struct file *file)
  77{
  78        return single_open(file, escd_info_proc_show, NULL);
  79}
  80
  81static const struct file_operations escd_info_proc_fops = {
  82        .owner          = THIS_MODULE,
  83        .open           = escd_info_proc_open,
  84        .read           = seq_read,
  85        .llseek         = seq_lseek,
  86        .release        = single_release,
  87};
  88
  89#define MAX_SANE_ESCD_SIZE (32*1024)
  90static int escd_proc_show(struct seq_file *m, void *v)
  91{
  92        struct escd_info_struc escd;
  93        char *tmpbuf;
  94        int escd_size;
  95
  96        if (pnp_bios_escd_info(&escd))
  97                return -EIO;
  98
  99        /* sanity check */
 100        if (escd.escd_size > MAX_SANE_ESCD_SIZE) {
 101                printk(KERN_ERR
 102                       "PnPBIOS: %s: ESCD size reported by BIOS escd_info call is too great\n", __func__);
 103                return -EFBIG;
 104        }
 105
 106        tmpbuf = kzalloc(escd.escd_size, GFP_KERNEL);
 107        if (!tmpbuf)
 108                return -ENOMEM;
 109
 110        if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
 111                kfree(tmpbuf);
 112                return -EIO;
 113        }
 114
 115        escd_size =
 116            (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1]) * 256;
 117
 118        /* sanity check */
 119        if (escd_size > MAX_SANE_ESCD_SIZE) {
 120                printk(KERN_ERR "PnPBIOS: %s: ESCD size reported by"
 121                                " BIOS read_escd call is too great\n", __func__);
 122                kfree(tmpbuf);
 123                return -EFBIG;
 124        }
 125
 126        seq_write(m, tmpbuf, escd_size);
 127        kfree(tmpbuf);
 128        return 0;
 129}
 130
 131static int escd_proc_open(struct inode *inode, struct file *file)
 132{
 133        return single_open(file, escd_proc_show, NULL);
 134}
 135
 136static const struct file_operations escd_proc_fops = {
 137        .owner          = THIS_MODULE,
 138        .open           = escd_proc_open,
 139        .read           = seq_read,
 140        .llseek         = seq_lseek,
 141        .release        = single_release,
 142};
 143
 144static int pnp_legacyres_proc_show(struct seq_file *m, void *v)
 145{
 146        void *buf;
 147
 148        buf = kmalloc(65536, GFP_KERNEL);
 149        if (!buf)
 150                return -ENOMEM;
 151        if (pnp_bios_get_stat_res(buf)) {
 152                kfree(buf);
 153                return -EIO;
 154        }
 155
 156        seq_write(m, buf, 65536);
 157        kfree(buf);
 158        return 0;
 159}
 160
 161static int pnp_legacyres_proc_open(struct inode *inode, struct file *file)
 162{
 163        return single_open(file, pnp_legacyres_proc_show, NULL);
 164}
 165
 166static const struct file_operations pnp_legacyres_proc_fops = {
 167        .owner          = THIS_MODULE,
 168        .open           = pnp_legacyres_proc_open,
 169        .read           = seq_read,
 170        .llseek         = seq_lseek,
 171        .release        = single_release,
 172};
 173
 174static int pnp_devices_proc_show(struct seq_file *m, void *v)
 175{
 176        struct pnp_bios_node *node;
 177        u8 nodenum;
 178
 179        node = kzalloc(node_info.max_node_size, GFP_KERNEL);
 180        if (!node)
 181                return -ENOMEM;
 182
 183        for (nodenum = 0; nodenum < 0xff;) {
 184                u8 thisnodenum = nodenum;
 185
 186                if (pnp_bios_get_dev_node(&nodenum, PNPMODE_DYNAMIC, node))
 187                        break;
 188                seq_printf(m, "%02x\t%08x\t%3phC\t%04x\n",
 189                             node->handle, node->eisa_id,
 190                             node->type_code, node->flags);
 191                if (nodenum <= thisnodenum) {
 192                        printk(KERN_ERR
 193                               "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n",
 194                               "PnPBIOS: proc_read_devices:",
 195                               (unsigned int)nodenum,
 196                               (unsigned int)thisnodenum);
 197                        break;
 198                }
 199        }
 200        kfree(node);
 201        return 0;
 202}
 203
 204static int pnp_devices_proc_open(struct inode *inode, struct file *file)
 205{
 206        return single_open(file, pnp_devices_proc_show, NULL);
 207}
 208
 209static const struct file_operations pnp_devices_proc_fops = {
 210        .owner          = THIS_MODULE,
 211        .open           = pnp_devices_proc_open,
 212        .read           = seq_read,
 213        .llseek         = seq_lseek,
 214        .release        = single_release,
 215};
 216
 217static int pnpbios_proc_show(struct seq_file *m, void *v)
 218{
 219        void *data = m->private;
 220        struct pnp_bios_node *node;
 221        int boot = (long)data >> 8;
 222        u8 nodenum = (long)data;
 223        int len;
 224
 225        node = kzalloc(node_info.max_node_size, GFP_KERNEL);
 226        if (!node)
 227                return -ENOMEM;
 228        if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
 229                kfree(node);
 230                return -EIO;
 231        }
 232        len = node->size - sizeof(struct pnp_bios_node);
 233        seq_write(m, node->data, len);
 234        kfree(node);
 235        return 0;
 236}
 237
 238static int pnpbios_proc_open(struct inode *inode, struct file *file)
 239{
 240        return single_open(file, pnpbios_proc_show, PDE_DATA(inode));
 241}
 242
 243static ssize_t pnpbios_proc_write(struct file *file, const char __user *buf,
 244                                  size_t count, loff_t *pos)
 245{
 246        void *data = PDE_DATA(file_inode(file));
 247        struct pnp_bios_node *node;
 248        int boot = (long)data >> 8;
 249        u8 nodenum = (long)data;
 250        int ret = count;
 251
 252        node = kzalloc(node_info.max_node_size, GFP_KERNEL);
 253        if (!node)
 254                return -ENOMEM;
 255        if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
 256                ret = -EIO;
 257                goto out;
 258        }
 259        if (count != node->size - sizeof(struct pnp_bios_node)) {
 260                ret = -EINVAL;
 261                goto out;
 262        }
 263        if (copy_from_user(node->data, buf, count)) {
 264                ret = -EFAULT;
 265                goto out;
 266        }
 267        if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) {
 268                ret = -EINVAL;
 269                goto out;
 270        }
 271        ret = count;
 272out:
 273        kfree(node);
 274        return ret;
 275}
 276
 277static const struct file_operations pnpbios_proc_fops = {
 278        .owner          = THIS_MODULE,
 279        .open           = pnpbios_proc_open,
 280        .read           = seq_read,
 281        .llseek         = seq_lseek,
 282        .release        = single_release,
 283        .write          = pnpbios_proc_write,
 284};
 285
 286int pnpbios_interface_attach_device(struct pnp_bios_node *node)
 287{
 288        char name[3];
 289
 290        sprintf(name, "%02x", node->handle);
 291
 292        if (!proc_pnp)
 293                return -EIO;
 294        if (!pnpbios_dont_use_current_config) {
 295                proc_create_data(name, 0644, proc_pnp, &pnpbios_proc_fops,
 296                                 (void *)(long)(node->handle));
 297        }
 298
 299        if (!proc_pnp_boot)
 300                return -EIO;
 301        if (proc_create_data(name, 0644, proc_pnp_boot, &pnpbios_proc_fops,
 302                             (void *)(long)(node->handle + 0x100)))
 303                return 0;
 304        return -EIO;
 305}
 306
 307/*
 308 * When this is called, pnpbios functions are assumed to
 309 * work and the pnpbios_dont_use_current_config flag
 310 * should already have been set to the appropriate value
 311 */
 312int __init pnpbios_proc_init(void)
 313{
 314        proc_pnp = proc_mkdir("bus/pnp", NULL);
 315        if (!proc_pnp)
 316                return -EIO;
 317        proc_pnp_boot = proc_mkdir("boot", proc_pnp);
 318        if (!proc_pnp_boot)
 319                return -EIO;
 320        proc_create("devices", 0, proc_pnp, &pnp_devices_proc_fops);
 321        proc_create("configuration_info", 0, proc_pnp, &pnpconfig_proc_fops);
 322        proc_create("escd_info", 0, proc_pnp, &escd_info_proc_fops);
 323        proc_create("escd", S_IRUSR, proc_pnp, &escd_proc_fops);
 324        proc_create("legacy_device_resources", 0, proc_pnp, &pnp_legacyres_proc_fops);
 325
 326        return 0;
 327}
 328
 329void __exit pnpbios_proc_exit(void)
 330{
 331        int i;
 332        char name[3];
 333
 334        if (!proc_pnp)
 335                return;
 336
 337        for (i = 0; i < 0xff; i++) {
 338                sprintf(name, "%02x", i);
 339                if (!pnpbios_dont_use_current_config)
 340                        remove_proc_entry(name, proc_pnp);
 341                remove_proc_entry(name, proc_pnp_boot);
 342        }
 343        remove_proc_entry("legacy_device_resources", proc_pnp);
 344        remove_proc_entry("escd", proc_pnp);
 345        remove_proc_entry("escd_info", proc_pnp);
 346        remove_proc_entry("configuration_info", proc_pnp);
 347        remove_proc_entry("devices", proc_pnp);
 348        remove_proc_entry("boot", proc_pnp);
 349        remove_proc_entry("bus/pnp", NULL);
 350}
 351