linux驱动开发之字符设备--私有数据和container_of

前言

驱动开发中通常为设备定义一个设备相关的设备结构体,其包含该设备的cdev 、私有数据、信号量、irq等这些信息。

驱动开发中通常将文件的私有数据private_data指向设备结构体,在read()、write()、ioctl()等函数通过 private_data 访问数据 设备结构体。

container_of() 是一个比较常用的宏,其作用为通过结构体成员的指针找到对应结构体的指针。

通过分析 akm8975.c 这个文件进行分析

分析

自定义的结构体 akm8975_data ,包含了 i2c_client 、work_struct等信息。

struct akm8975_data {
    struct i2c_client *this_client;
    struct akm8975_platform_data *pdata;
    struct input_dev *input_dev;
    struct work_struct work;
    struct mutex flags_lock;
#ifdef CONFIG_HAS_EARLYSUSPEND
    struct early_suspend early_suspend;
#endif

定义一个全局的变量 akmd_data

/*
* Because misc devices can not carry a pointer from driver register to
* open, we keep this global. This limits the driver to a single instance.
*/
struct akm8975_data *akmd_data;

自定义的设备结构体的初始化:

int akm8975_probe(struct i2c_client *client,
          const struct i2c_device_id *devid){
          ...
    struct akm8975_data *akm; //申请一个局部的结构体指针
    akm = kzalloc(sizeof(struct akm8975_data), GFP_KERNEL); //初始这个指针
    akmd_data = akm; //复制给全局的变量
    }

将自定义的设备结构体赋值给 file的private_data

static int akm_aot_open(struct inode *inode, struct file *file){
    ...

    file->private_data = akmd_data;
}

通过file取得private_data

tatic int akm_aot_ioctl(struct inode *inode, struct file *file,
          unsigned int cmd, unsigned long arg)
{
    void __user *argp = (void __user *) arg;
    short flag;
    struct akm8975_data *akm = file->private_data;

自定义的设备结构体,通常有以下操作

  1. 定义一个全局的变量
  2. 在probe 或者入口函数中初始化 全局变量
  3. 在 file_operation open 中,将全局变量赋值给file的private_data
  4. 在read() 、wriete、ioctl()的操作中,通过file取中private_data 进行操作

    在定义的设备结构体中 一项 工作队列。 这个工作队列 是如何和 container_of联系起来的呢? 先看下代码中的相关内容。

初始化工作队列

int akm8975_probe(struct i2c_client *client,
          const struct i2c_device_id *devid){
    ...
        INIT_WORK(&akm->work, akm_work_func);         
}

工队队列

static void akm_work_func(struct work_struct *work)
{
    struct akm8975_data *akm =
        container_of(work, struct akm8975_data, work);  //利用container_of,获得work指针对于的设备结构体指针 akm

    FUNCDBG("called");
    //通过获得的akm指针,从结构体中,取出成员来执行相应的操作。
    enable_irq(akm->this_client->irq);
}

调度 工作队列

static irqreturn_t akm8975_interrupt(int irq, void *dev_id)
{
    struct akm8975_data *akm = dev_id;
    FUNCDBG("called");

    disable_irq_nosync(akm->this_client->irq);
    schedule_work(&akm->work);
    return IRQ_HANDLED;
}

通过定义一个设备结构体,可以将设备相关的操作、信息封装在一起,后边可以使用 container_of 得到这个结构体。将数据传递给private_data 更加规范和调理。

container_of

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

offsetof 通过将 0 地址,强制转为为TYPE类型的指针,然后取它的成员 NUMBER , 在转为size_t 类型。即得到 NUMBER 在这个TYPE的位置。

/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:   the type of the container struct this is embedded in.
 * @member: the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({          \
    const typeof(((type *)0)->member) * __mptr = (ptr); \
    (type *)((char *)__mptr - offsetof(type, member)); })
#endif

参考文献

磁传感器AKM8975驱动和中间层
offsetof与container_of宏总结
GCC typeof在kernel中的使用——C语言的“编译时多态”
akm8975.c

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值