首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >container_of、dev_set_drvdata和dev_get_drvdata的使用

container_of、dev_set_drvdata和dev_get_drvdata的使用
EN

Stack Overflow用户
提问于 2014-07-23 14:06:21
回答 1查看 2.3K关注 0票数 0

我是设备驱动程序的新手,我正在学习这个container_of和dev_get_drvdata,偶然发现了这个驱动程序。我删除了这个驱动程序的一部分,以使它更紧凑。

代码语言:javascript
复制
    static void tsl4531_polling_worker(struct work_struct *work)
    {

        u8 buf[2];

        struct tsl4531_data *data   = container_of(to_delayed_work(work),
                            struct tsl4531_data, work);

        mutex_lock(&data->update_lock);
        buf[0] = DEVICE_LIGHT;
        buf[1] = GET_REQUEST;
        sam4l_send_request(data->pdata.sam4l,2,buf);
        mutex_unlock(&data->update_lock);

    }

    static ssize_t store_enable_value(struct device *dev,struct device_attribute *devattr,const char *buf,size_t count){

        struct tsl4531_data *data = dev_get_drvdata(dev);

        if((buf[0] == '1') && (!tsl4531_enabled)) {
            schedule_delayed_work(&data->work, msecs_to_jiffies(50));
            tsl4531_enabled = 1;

        } else if (buf[0] == '0'){
            tsl4531_enabled = 0;
            cancel_delayed_work_sync(&data->work);
            tsl4531_lux = 0;

        }

        return count;
    }

    static DEVICE_ATTR(enable,S_IRUGO | S_IWUGO,
               show_enable_value, store_enable_value );        

    static struct attribute *tsl4531_attributes[] = {
        &dev_attr_lux_show.attr,
        &dev_attr_enable.attr,
        NULL
    };

    static const struct attribute_group tsl4531_attr_group = {
        .attrs = tsl4531_attributes,
    };

    void tsl4531_callback_fun(struct work_struct *work)
    {

        struct tsl4531_data *chip = container_of(work,struct tsl4531_data,
                    pdata.work.work);

        tsl4531_lux = chip->pdata.response[2];//Need to check on which response index we get lux value

        input_report_abs(tsl4531_dev, ABS_X,tsl4531_lux);
        input_sync(tsl4531_dev);
        schedule_delayed_work(&chip->work, msecs_to_jiffies(1500));

    }

    static int __devinit tsl4531_probe(struct platform_device *pdev){
        struct tsl4531_data *chip;  
        int err=0;

        chip = kzalloc(sizeof(struct tsl4531_data), GFP_KERNEL);
        if (!chip){
            dev_dbg(&pdev->dev, "memory not allocated for tsl4531 light sensor module.\n");
            return -ENOMEM;
        }

        dev_set_drvdata(&pdev->dev,chip);//here we give address in chip to struct device

        tsl4531_dev=input_allocate_device();
        if(!tsl4531_dev) {
            dev_dbg(&pdev->dev, "memory not allocated for tsl4531_dev.\n");
            return -ENOMEM;
        }

        err=input_register_device(tsl4531_dev);
        if(err){
            dev_dbg(&pdev->dev, "input register poll the device failed ... \n");
            goto err_reg_poll;
        }

        mutex_init(&chip->update_lock);

        err = sysfs_create_group(&pdev->dev.kobj,&tsl4531_attr_group);
        if (err){
            dev_dbg(&pdev->dev, "creating sysfs group for tsl4531 sensor module failed.\n");
            goto exit_err;
        }

        INIT_DELAYED_WORK(&chip->work, tsl4531_polling_worker);
        INIT_DELAYED_WORK(&chip->pdata.work,tsl4531_callback_fun);

        chip->pdata.dev_id = DEVICE_LIGHT;

        return 0;

        return err;
    }

    static int __devexit tsl4531_remove(struct platform_device *pdev){

        struct tsl4531_data *data = dev_get_drvdata(&pdev->dev);

        cancel_delayed_work_sync(&data->work);
        cancel_delayed_work(&data->pdata.work);
        sysfs_remove_group(&pdev->dev.kobj, &tsl4531_attr_group);
        unregister_sam4l_client(&data->pdata);
        kfree(data);
        return 0;
    }

    static const struct platform_device_id tsl4531_id[] = {
        { "tsl45317", 0 },
        { }
    };

    static struct platform_driver tsl4531_driver = {
        .driver = {
            .owner = THIS_MODULE,
            .name  = "tsl45317",
        },
        .probe      = tsl4531_probe,
        .remove     = tsl4531_remove,
        .suspend    = tsl4531_suspend,
        .resume     = tsl4531_resume,
        .id_table   = tsl4531_id,
    };


    static int __init tsl4531_init(void){

        return platform_driver_register(&tsl4531_driver);
    }


    static void __exit tsl4531_exit(void){

        platform_driver_unregister(&tsl4531_driver);
    }

关于container_of和dev_get_drvdata的工作,我没有什么疑问

1)在polling_worker函数中,我们可以看到一个探测宏,它将地址提取到原始结构并分配给结构tsl4531_data *data;2)在探测函数中,我们可以看到对dev_set_drvdata以及store_enable_value和tsl4531 dev_get_drvdata的一次调用。

在这里,container_of、dev_set和dev_get不是都在做同样的事情吗?

EN

回答 1

Stack Overflow用户

发布于 2014-07-31 16:44:46

container_ofdev_set, dev_get是不同的。但是,是的,意图可能是相同的。两者实际上都用于检索指针(通常指向设备的私有数据结构)。

container_of()实际上做了一个反向映射。它做与&struct_base->member操作相反的操作。在前面的操作中,您有指向结构基址的指针,并且需要它的一个成员的地址。而container_of接受成员的地址并返回基地址。在tsl4531_polling_worker()函数中,它有成员的地址,并使用container_of获取结构的基地址(struct tsl4531_data)

dev_set_drvdata()通常用来保存指针的地址,这样以后就可以使用dev_get_drvdata()检索它。与反向映射不同,函数从void *类型的指针存储和加载地址(请参阅http://lxr.free-electrons.com/source/drivers/base/dd.c#L595)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24903012

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档