linuxlinux-kernellinux-device-driversysfs

How to dereference device_private in struct device


I'm working on a driver in Linux. I'm working on getting some /sys file attributes in place. In delivering what these attributes are to convey, the attribute functions must have access to some data that's stored by the driver. Because of how things appear to be made and stored, I thought I could use the device_private *p member of the struct device that comes from device_create(). Basically, it's like this:

    for (i = 0; i < total; i++) {
        pDevice = device_create(ahcip_class, NULL, /*no parent*/
                MKDEV(AHCIP_MAJOR, AHCIP_MINOR + i), NULL, /*no additional info*/
                DRIVER_NAME "%d", AHCIP_MINOR + i);
        if (IS_ERR(pDevice)) {
            ret = PTR_ERR(pDevice);
            printk(KERN_ERR "%s:%d device_create failed AHCIP_MINOR %d\n",
                    __func__, __LINE__, (AHCIP_MINOR + i));
            break;
        }

        mydevs[i].psysfs_dev = pDevice;

        ret = sysfs_create_group(&pDevice->kobj, &attr_group);
        if (!ret) {
            pr_err("%s:%d failed in making the device attributes\n",
                    __func__, __LINE__);
            goto build_udev_quick_out;
        }
    }

This doesn't yet show the assignment into the device_private pointer, but that's where I'm headed. Each new device made under this class will need the same attributes thus the group. Here's my single attribute that I'm starting with for "proof of concept"

    static ahcip_dev *get_ahcip_dev(struct kobject *ko)
    {
        ahcip_dev *adev = NULL;
        struct device *pdev = container_of(ko, struct device, kobj);
        if (!pdev) {
            pr_err("%s:%d unable to find device struct in kobject\n",
                    __func__, __LINE__);
            return NULL;
        }

        /* **** problem dereferencing p **** */
        adev = (ahcip_dev*)pdev->p->driver_data;
        /* return the pointer anyway, but if it's null, print to klog */
        if (!adev)
            pr_err("%s:%d no ahcip_dev, private driver data is NULL\n",
                    __func__, __LINE__);

        /* **** again problem dereferencing p **** */
        return pdev->p->(ahcip_dev*)driver_data; // <--- problem here
    }

    static ssize_t pxis_show(struct kobject *kobj, struct kobj_attribute *attr,
            char *buff)
    {
        u32 pi = 0;
        ahcip_dev *adev = get_ahcip_dev(kobj);

        /* get_ahcip_dev() will print what happened, this needs to return
         * error code
         */
        if (!adev)
            return -EIO;

        pi = adev->port_index;

        return sprintf(buff, "%08x\n", get_port_reg(adev->hba->ports[pi], 0x10));
    }

I figured that, since device_create() returns a struct device* and I'm using that to make the device group, the struct kobject* that is coming into pxis_show is the member of the device structure made by device_create. If this is true, then I should be able to stuff some private data into that object and use it when the /sys files are accessed. However, when the lines of code marked above dereference the p member I get dereferencing pointer of incomplete type from gcc. I've determined that it's the struct device_private member of struct device that is incomplete but why? Is there a different structure I should be using? This seems to be something truly internally by the kernel.


Solution

  • For assign private data for device, you need to use void *drvdata parameter to device_create(). After creation, data can be accessed via dev_get_drvdata(pdev).

    struct device_private is internal for device implementation. From description of this structure (drivers/base/base.h):

    Nothing outside of the driver core should ever touch these fields.