linux 字符设备驱动 ioctl,Tiny6410学习ing—(四)、嵌入式Linux内核驱动进阶—(7)、高级字符设备驱动(ioctl 控制)—①...

每天总是想学一点,然后积累多了,自己也就有那么点的满足感,不得不承认自己还是不行,但是,一直相信,只要肯努力,肯坚持,那就算是一种成功!!

学习 Linux

那更得这样!!

不过做玩这点东西,五一我也打算休息的。

(四)、嵌入式Linux内核驱动进阶

(7)、字符设备驱动(ioctl

控制)—①

大部分驱动除了需要具备读写设备的能力外,还学要具备对硬件控制的能力。

例如,要求设备报告错误信息,改变波特率,这些操作常常通过 ioctl

方法来实现!

1、ioctl

使用方法

1)用户使用 ioctl

的方法

在用户下,使用 ioctl() 系统调用来控制设备,原型如下:

int ioctl(int fd,unsigned long

cmd,...)

原型中的点表示这是一个可选的参数,存在与否依赖于控制命令(第二个参数)是否涉及到与设备的数据交互。

2)驱动 ioctl

方法

在内核中,ioctl 驱动方法和用户空间版本不同的原型:

int (*ioctl) (struct innod *innod,struct

file *filp,unsigned int cmd,unsigned long arg)

cmd 参数是从用户空间传下来的,可选的参数 arg 以一个 unsigned long

的形式传递,不管它是一个整数或者一个指针。

如果 cmd 命令不涉及数据传输,则第三个参数 arg 的值没有任何意义!

注意:

在 2.6.36 以及以后的内核版本中,file_operation 结构中的 ioctl

成员已经被取消,使用心得内核编写驱动时,可以用下面两个操作替换:

// 不适用 BLK(大内核锁),将使用这种函数指针代替

ioctl

long (*unlocked_ioctl) (struct file

*,unsigned int,unsigned long);

// 兼容 64 位系统,使用此函数指针代替

long (*compat_ioctl) (struct file

*,unsigned int,unsigned long);

2、定义命令

在编写 ioctl 代码之前,首先需要定义命令。

为了防止对错误的设备使用正确的命令,命令号应该在系统范围内唯一!ioctl

命令编码被划分为几个位段,include/asm/ioctl.h 中定义了这些字段:

类型(幻数),序号,传送方向,参数的大小。

其中 Documentation/ioctl-number.txt 文件中罗列了在内核中已经使用了的幻数。

1)位段

定义 ioctl 命令的正确方法是使用 4 个位段,这个列表中介绍的符号定义在

中:

字段(bit) 说明

type(8) 幻数(类型),表明哪个设备的命令,在参考了

ioctl-number.txt 之后选出

8位宽

number(8) 序号,表明设备的第几个,8位宽

direction(2) 传送数据的方向,可能的值是

_IOC_NONE(没有数据传输),_IOC_READ

、_IOC_WRITE。数据传送的是从应用程序的观点来看待的,_IOC_READ 意思是从设备读

size(8~14) 用户数据的大小。(8~14 位宽,视处理器而定)

2)帮助定义命令的宏以及解开各个字段的宏!

①、帮助定义命令的宏:

_IO(type,nr) // 没有参数的命令

_IOR(type,nr,datatype) // 从设备读数据

_IOW(type,nr,datatype) // 向设备写数据

_IOWR(type,nr,datatype) // 双向传送

②、解开各个字段的宏:

_IOC_DIR(nr)

_IOC_TYPE(nr)

_IOC_NR(nr)

_IOC_SIZE(nr)

3)定义命令(范例)

#define MEM_IOC_MAGIC

'm' // 定义幻数

#define MEM_IOCSET

_IOW(MEM_IOC_MAGIC,0,int)

#define MEM_IOCGQSET

_IOR(MEM_IOC_MAGIC,1,int)

3、ioctl

函数实现

定义好了命令,下一步就是实现 ioctl 函数了,ioctl 函数饿实现包括三个技术环节:

▲:返回值

▲:参数使用

▲:命令操作

1)返回值

ioctl 函数的实现通常是根据命令执行的一个 switch 语句。但是,当命令号不能匹配任何一个设备所支持的命令时,通常返回

-EINVAL(非法参数)!

2)参数

如果是一个整数,可以直接使用。

如果是指针,我们必须确保这个用户地址是有效的,因此使用前需进行正确的检查!

①不需要进行参数检查的函数:

▲:copy_from_user

▲:copy_to_user

▲:get_user

▲:put_user

②、需要检查的函数:

▲:__get_user

▲:__put_user

③、检查函数:

int access_ok(int type,const void

*addr,unsigned long size)

第一个参数是 VERIFY_READ 或者 VERIFY_WRITE,用来表明是读用户内存还是写用户内存。

addr 参数是要操作的用户内存地址,size 是操作的长度。

如果 ioctl 需要从用户空间读一个整数,那么 size 参数等于 sizeof(int)。

access_ok 返回一个布尔值:1 是成功(存储没有问题)和0

是失败(存储有问题),如果该函数返回失败,则 ioctl 应当返回 -EFAULT。

④、参数检查例程:

if(_IOC_DIR(cmd) & _IOC_READ)

err =

!access_ok(VERIFY_WRITE,(void __user *)arg,_IOC_SIZE(cmd));

else if(_IOC_DIR(cmd) & _IOC_WRITE)

err =

!access_ok(VERFIY_READ,(void __user *)arg,_IOC_SIZE(cmd));

4、命令操作范例:

switch(cmd)

{

case

MEM_IOCSQUANTUM: // Set: arg points to the value

retval = _get_user(scull_quantum,(int *)arg);

break;

case

MEM_IOCGQUANTUM: // Get: arg is pointer to result

retval = _put_user(scull_quantum,(int *)arg);

break;

default:

return -EINVAL;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值