设备驱动程序学习笔记(4)-设备控制ioctl方法

本文详细介绍了Linux系统中ioctl系统调用的工作原理及其在设备驱动程序中的应用。ioctl允许应用程序发送控制命令给设备驱动,支持数据的读取、写入或双向传输。文章深入探讨了ioctl命令的构造、验证过程以及在scull示例中的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

By:             潘云登

Date:          2009-6-2

Email:         intrepyd@gmail.com

Homepage: http://blog.youkuaiyun.com/intrepyd

Copyright: 该文章版权由潘云登所有。可在非商业目的下任意传播和复制。

对于商业目的下对本文的任何行为需经作者同意。


写在前面

1.          本文内容对应《linux设备驱动程序》第六章。

2.          参考俞永昌的《设备驱动开发技术及应用》,以及Documentation/ioctl-number.txtinclude/asm/ioctl.h两个文件。

3.          希望本文对您有所帮助,也欢迎您给我提意见和建议。


设备控制

ioctl

对于那种不传送数据而只响应命令的设备,如机器人J,可以通过向设备写入控制序列进行控制。然而,对于具备读写操作的设备,通过打印序列进行控制将给设备增加策略限制。更好的设备控制方式是ioctl方法。在用户空间,ioctl系统调用具有如下原型:

int ioctl(int fd, unsigned long cmd, char *argp);

控制命令cmd由用户空间不加修改地传递到驱动程序的ioctl方法。argp为可选参数,它可以是一个整型参数或者是一个指针参数,具体形式依赖于要完成的控制命令cmd。使用指针可以向ioctl调用传递任意数据,从而与用户空间交换任意数量的数据。不论argp是何种类型,它都以unsigned long的形式传递给驱动程序。然后,由驱动程序根据具体情况进行类型转换,如转换为整型指针(int __user *arg__user表明指针是一个用户空间地址,不能直接引用。驱动程序的ioctl方法原型如下:

int (*ioctl) (struct inode *inode, struct file *filp,
              unsigned int cmd, unsigned long arg);

其返回值,也是系统调用的返回值,可以向用户空间提供设备信息。负的返回值被认为是一个错误,通常为-ENOTTY (不合适的设备ioctl) -EINVAL (非法参数),被用来设置用户空间的errno变量。


控制命令

高位                                                                         低位

2

14

8

8

direction

size

number

type

Ø         type:幻数,可以在Documentation/ioctl-number.txt中选择一个未使用的号码。如果整个控制命令能够被内核识别,将无法到达驱动程序。

Ø         number:序数,一般从0开始顺序编号。

Ø         size:用户数据大小,用于检查参数类型的大小,如sizeof(int) < (1 << size)

Ø         direction:数据传输方向,可以使用的值包括 _IOC_NONE (无数据传输) _IOC_READ (从设备中读数据) _IOC_WRITE (向设备写数据),以及 _IOC_READ|_IOC_WRITE (双向数据传输)

<linux/ioctl.h>中包含的<asm/ioctl.h>头文件定义了一些构造命令编号的宏:

_IO(type,nr)
_IOR(type,nr,datatype)
_IOW(type,nr,datatype)
_IOWR(type,nr,datatype)

以及用于解开位字段的宏:

_IOC_TYPE(nr)
_IOC_NR(nr)
_IOC_SIZE(nr)
_IOC_DIR(nr)

大多数ioctl的实现中都包含了一个switch语句来根据控制命令选择对应的操作。


ioctl

工作模型

ioctl工作模型


scull

中的几处检查

Ø         控制命令检查

检查设备幻数和命令序数。

if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY;

Ø         用户地址空间检查

当用一个指针指向用户空间时,必须确保指向的用户空间是合法的,这通过access_ok函数完成。通常不需要真正调用access_ok,因为数据交换函数copy_to_user, copy_from_user, put_user, get_user 会处理它。

int access_ok(int type, const void *addr, unsigned long size);
 
/*scull*/
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(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
if (err) return -EFAULT;

Ø         权能检查

对设备的读写访问由设备文件的权限控制,驱动程序通常不进行权限检查。然而,当用户试图修改设备参数时,设备驱动程序应该检查调用进程是否有合适的权能,这通过capable函数完成。

int capable(int capability);
/*scull*/
if (! capable (CAP_SYS_ADMIN))
          return -EPERM;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值