lkml.org 
[lkml]   [2004]   [Aug]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: VPD in sysfs
    On Sat, Aug 14, 2004 at 07:29:32PM +0100, Matthew Wilcox wrote:
    > Thoughts? Since there's at least four and probably more ways of getting
    > at VPD, we either need to fill in some VPD structs at initialisation or
    > have some kind of vpd_ops that a driver can fill in so the core can get
    > at the data.

    I've tried the first option -- creating a large block of sysfs entries for
    all the VPD entries that are present. However, I've come upon a problem
    with sysfs that prevents me from doing so.

    Basically, the problem is that sysfs doesn't pass the attribute that's
    being invoked to the attribute ->show method. So I can't determine
    which one is being read. This isn't a problem for any other sysfs attribute
    because they're all static, but for dynamically created attributes, it's
    not possible to work this way.

    What I wanted to have was:

    /sys/devices/pci0000:00/0000:00:00.0/vpd/
    /sys/devices/pci0000:00/0000:00:00.0/vpd/PN (contents "6181682A")
    /sys/devices/pci0000:00/0000:00:00.0/vpd/EC (contents "4950262536")
    /sys/devices/pci0000:00/0000:00:00.0/vpd/SN (contents "00000194")
    /sys/devices/pci0000:00/0000:00:00.0/vpd/FN (contents "135722")
    /sys/devices/pci0000:00/0000:00:00.0/vpd/MN (contents "1037")
    ...

    (note, this example is taken from table 6-8 in PCI 2.1)

    So I have code that iterates over each element in a block of raw VPD,
    extracts each name and value and creates sysfs entries for them ... but
    I can't write the show method. Here's the VPD file (compiles, haven't
    hooked any code up to it yet):


    /*
    * drivers/base/vpd.c
    *
    * Expose Vital Product Data through sysfs
    *
    * Copyright (c) Matthew Wilcox 2004
    */

    #include <linux/device.h>

    /* This should really be in a common file shared with drivers/pnp/isapnp */

    enum isapnp_tag {
    ISA_TAG_COMPAT = 0x03,
    ISA_TAG_VEND_S = 0x0e,
    ISA_TAG_END = 0x0f,
    ISA_TAG_IDSTR = 0x82,
    ISA_TAG_VEND_L = 0x84,
    ISA_TAG_VPD = 0x90,
    };

    static inline int vpd_get_len(char *data, int *idx, enum isapnp_tag *tag)
    {
    int i, x, len;

    i = *idx;
    x = data[i++];

    if (x & 0x80) {
    len = data[i] | (data[i + 1] << 8);
    i += 2;
    } else {
    len = x & 7;
    x >>= 3;
    }

    *idx = i;
    *tag = x;
    return len;
    }

    static int vpd_count_items(char *data)
    {
    int i = 0;
    int count = 0;

    for (;;) {
    int j;
    enum isapnp_tag tag;
    int len = vpd_get_len(data, &i, &tag);
    if (tag == ISA_TAG_END)
    break;
    if (tag != ISA_TAG_VPD)
    continue;
    j = i;
    while (j < i + len) {
    count++;
    j += 2;
    j += data[j] + 1;
    }
    }
    return count;
    }

    static ssize_t vpd_show(struct device *dev, char *buf)
    {
    return 0;
    }

    static struct attribute * vpd_create_attr(unsigned char *data)
    {
    struct device_attribute *attr;
    char *buf;
    unsigned int len = data[2];

    attr = kmalloc(sizeof(*attr) + 4 + len, GFP_KERNEL);
    if (!attr)
    return NULL;
    buf = (char *)(attr + 1);

    buf[0] = data[0];
    buf[1] = data[1];
    buf[2] = '\0';
    memcpy(buf, data + 3, len);

    attr->attr.name = buf;
    attr->attr.mode = 0644;
    attr->show = vpd_show;
    attr->store = NULL;

    return &attr->attr;
    }

    static int vpd_create_attrs(struct attribute **attrs, int count, unsigned char *data)
    {
    int i = 0;
    int k = 0;

    for (;;) {
    int j;
    enum isapnp_tag tag;
    int len = vpd_get_len(data, &i, &tag);
    if (tag == ISA_TAG_END)
    break;
    if (tag != ISA_TAG_VPD)
    continue;
    j = i;
    while (j < i + len) {
    attrs[k] = vpd_create_attr(data + j);
    if (!attrs[k])
    return -ENOMEM;
    k++;
    j += 2;
    j += data[j] + 1;
    }
    }

    BUG_ON(k != count);
    attrs[count] = NULL;
    return 0;
    }

    /**
    * device_add_vpd - Add VPD files to a device
    * @dev: The device that this VPD pertains to
    * @vpd: A memory region containing VPD data
    */
    int device_add_vpd(struct device *dev, unsigned char *data)
    {
    int err, i;
    int count = vpd_count_items(data);
    if (count < 1)
    return count;

    dev->vpd = kmalloc(sizeof(*dev->vpd) + (count + 1) * sizeof(void *),
    GFP_KERNEL);
    if (!dev->vpd)
    return -ENOMEM;
    memset(dev->vpd, 0, sizeof(*dev->vpd) + (count + 1) * sizeof(void *));

    dev->vpd->name = "vpd";
    dev->vpd->attrs = (struct attribute **)(dev->vpd + 1);

    err = vpd_create_attrs(dev->vpd->attrs, count, data);
    if (err)
    goto fail;

    err = sysfs_create_group(&dev->kobj, dev->vpd);
    if (err)
    goto fail;

    return 0;

    fail:
    for (i = 0; i < count; i++) {
    kfree(dev->vpd->attrs[i]);
    }
    kfree(dev->vpd);
    return err;
    }

    void device_remove_vpd(struct device *dev)
    {
    int i = 0;
    sysfs_remove_group(&dev->kobj, dev->vpd);
    while (dev->vpd->attrs[i] != NULL) {
    kfree(dev->vpd->attrs[i]);
    i++;
    }
    kfree(dev->vpd->attrs);
    kfree(dev->vpd);
    dev->vpd = NULL;
    }

    EXPORT_SYMBOL(device_add_vpd);
    EXPORT_SYMBOL(device_remove_vpd);

    --
    "Next the statesmen will invent cheap lies, putting the blame upon
    the nation that is attacked, and every man will be glad of those
    conscience-soothing falsities, and will diligently study them, and refuse
    to examine any refutations of them; and thus he will by and by convince
    himself that the war is just, and will thank God for the better sleep
    he enjoys after this process of grotesque self-deception." -- Mark Twain
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 14:05    [W:0.035 / U:1.888 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site