lorenzli
lorenzli

Reputation: 630

Debugging of a simple char driver failing on container_of when reading from device attribute

I am writing a simple char driver which accesses a PCI card. It is registered to sysfs with the help of a new class. Now I would like to access multiple parameters (i.e. version, status, control...) of the device in a convenient way. I thought of registering multiple attributes to the device (via device_create_file()). To do so I create my own device structure foo_dev for which I allocate memory and store all device informations in it (i.e. struct device). Once the attribute gets called I wanted to recover my structure by using container_of() as shown in my code (stripped of return verification for readability):

static const ssize_t foo_show(struct device *dev,
    struct device_attribute *attr, char *buf)
{
    struct foo_dev *foo_dev = container_of(dev, struct foo_dev,
        dev);
    mutex_lock(&mutex);

    u32 data = ioread32(foo_dev->bar + 0x2020);

    mutex_unlock(&mutex);
    return sprintf(buf, "%d\n", data);
}

The problem: As soon as I write to the device, the kernel aborts with a Bad IO access at port 0x2020 (return inl(port)) coming from the ioread32() call. Having investigated further and printed other informations stored in foo_dev I see that the structure is completely empty - container_of() apparently does not reconstruct my original structure. For completeness here the device initialization in the probe() function:

...
foo_dev->dev = device_create(fooClass, NULL, foo_dev->devNbr,
    foo_dev, DEVICE_NAME);

cdev_init(&foo_dev->cdev, &foo_fops);
rv = cdev_add(&foo_dev->cdev, foo_dev->devNbr, 1);

rv = pci_enable_device(dev);
...
device_create_file(foo_dev->dev, &dev_attr_bar);
...

What do I probably wrong? How can I investigate further on what I actually receive as struct dev in foo_show()?

Upvotes: 0

Views: 525

Answers (2)

lorenzli
lorenzli

Reputation: 630

Having a closer look at device_create() one can see that the initialized device actually gets a pointer on its parent structure via dev_set_drvdata(). Instead of using container_of() in the attribute routine one can then recover the foodev structure with dev_get_drvdata(). The routine becomes:

static const ssize_t foo_show(struct device *dev,
    struct device_attribute *attr, char *buf)
{
    struct foo_dev *foo_dev = dev_get_drvdata(dev);
    mutex_lock(&mutex);

    u32 data = ioread32(foo_dev->bar + 0x2020);

    mutex_unlock(&mutex);
    return sprintf(buf, "%d\n", data);
}

Upvotes: 0

CL.
CL.

Reputation: 180020

container_of() does not work with an embedded pointer.

It works only for a structure that is directly embedded in another structure:

struct foo_dev {
    ...
    struct device dev;
    ...
};

(You then have to use device_initialize().)

Upvotes: 2

Related Questions