linux驱动私有数据,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;

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

定义一个全局的变量

在probe 或者入口函数中初始化 全局变量

在 file_operation open 中,将全局变量赋值给file的private_data

在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

参考文献

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值