网站没有关键词的弊端,郫都区网站建设,seo排名赚能赚钱吗,我想建设一个算命网站今天进入《Linux设备驱动程序#xff08;第3版#xff09;》第六章高级字符驱动程序操作的学习。 一、ioctl 大部分设备除了读写能力#xff0c;还可进行超出简单的数据传输之外的操作#xff0c;所以设备驱动也必须具备进行各种硬件控制操作的能力. 这些操作常常通过 io…今天进入《Linux设备驱动程序第3版》第六章高级字符驱动程序操作的学习。 一、ioctl 大部分设备除了读写能力还可进行超出简单的数据传输之外的操作所以设备驱动也必须具备进行各种硬件控制操作的能力. 这些操作常常通过 ioctl 方法来支持它有和用户空间版本不同的原型: int (*ioctl) (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg); 需要注意的是不管可选的参数arg是否由用户给定为一个整数或一个指针它都以一个unsigned long的形式传递。如果调用程序不传递arg参数, 被驱动收到的 arg 值是未定义的。因为在arg参数上的类型检查被关闭了,所以若一个非法参数传递给 ioctl编译器是无法报警的且任何关联的错误难以查找. 选择ioctl命令 为了防止向错误的设备使用正确的命令命令号应该在系统范围内唯一。为方便程序员创建唯一的 ioctl 命令代号 每个命令号被划分为多个位字段。要按 Linux 内核的约定方法为驱动选择 ioctl 的命令号, 应该首先看看 include/asm/ioctl.h 和 Documentation/ioctl-number.txt。 要使用的位字段符号定义在 linux/ioctl.h : type(幻数)8 位宽(_IOC_TYPEBITS)参考ioctl-number.txt选择一个数并在整个驱动中使用它。 number序数顺序编号8 位宽(_IOC_NRBITS)。 direction数据传送的方向可能的值是 _IOC_NONE(没有数据传输)、_IOC_READ、 _IOC_WRITE和 _IOC_READ|_IOC_WRITE (双向传输数据)。该字段是一个位掩码两位, 因此可使用 AND 操作来抽取_IOC_READ 和 _IOC_WRITE。 size数据的大小宽度与体系结构有关,ARM为14位.可在宏 _IOC_SIZEBITS 中找到特定体系的值. linux/ioctl.h 中包含的 asm/ioctl.h定义了一些构造命令编号的宏: _IO(type,nr)/*没有参数的命令*/
_IOR(type, nr, datatype)/*从驱动中读数据*/
_IOW(type,nr,datatype)/*写数据*/
_IOWR(type,nr,datatype)/*双向传送*/
/*type 和 number 成员作为参数被传递, 并且 size 成员通过应用 sizeof 到 datatype 参数而得到*/ 这个头文件还定义了用来解开这个字段的宏: _IOC_DIR(nr)
_IOC_TYPE(nr)
_IOC_NR(nr)
_IOC_SIZE(nr) 具体的使用方法在实验中展示。 返回值 POSIX 标准规定如果使用了不合适的 ioctl 命令号应当返回-ENOTTY 。这个错误码被 C 库解释为不合适的设备 ioctl。然而它返回-EINVAL仍是相当普遍的。 预定义命令 有一些ioctl命令是由内核识别的当这些命令用于自己的设备时他们会在我们自己的文件操作被调用之前被解码. 因此, 如果你选择一个ioctl命令编号和系统预定义的相同时你永远不会看到该命令的请求而且因为ioctl 号之间的冲突应用程序的行为将无法预测。预定义命令分为 3 类: 1用于任何文件(常规, 设备, FIFO和socket) 的命令 2只用于常规文件的命令 3特定于文件系统类型的命令 下列 ioctl 命令是预定义给任何文件包括设备特定文件 FIOCLEX 设置 close-on-exec 标志(File IOctl Close on EXec)。 FIONCLEX 清除 close-no-exec 标志(File IOctl Not CLose on EXec)。 FIOQSIZE 这个命令返回一个文件或者目录的大小; 当用作一个设备文件, 但是, 它返回一个 ENOTTY 错误。 FIONBIOFile IOctl Non-Blocking I/O(在阻塞和非阻塞操作一节中描述)。 使用ioctl参数 在使用ioctl的可选arg参数时如果传递的是一个整数它可以直接使用。如果是一个指针,就必须小心。当用一个指针引用用户空间, 我们必须确保用户地址是有效的其校验(不传送数据)由函数 access_ok 实现定义在 asm/uaccess.h : int access_ok(int type, const void *addr, unsigned long size); 第一个参数应当是 VERIFY_READ读或VERIFY_WRITE读写addr 参数为用户空间地址size 为字节数可使用sizeof()。access_ok 返回一个布尔值: 1 是成功(存取没问题)和 0 是失败(存取有问题)。如果它返回假驱动应当返回 -EFAULT 给调用者。 注意首先, access_ok不做校验内存存取的完整工作; 它只检查内存引用是否在这个进程有合理权限的内存范围中且确保这个地址不指向内核空间内存。其次大部分驱动代码不需要真正调用 access_ok而直接使用put_user(datum, ptr)和get_user(local, ptr)它们带有校验的功能确保进程能够写入给定的内存地址成功时返回 0, 并且在错误时返回 -EFAULT.。 put_user(datum, ptr)
__put_user(datum, ptr)
get_user(local, ptr)
__get_user(local, ptr) 这些宏它们相对copy_to_user 和copy_from_user快, 并且这些宏已被编写来允许传递任何类型的指针只要它是一个用户空间地址. 传送的数据大小依赖 prt 参数的类型, 并且在编译时使用 sizeof 和 typeof 等编译器内建宏确定。他们只传送1、2、4或8 个字节。如果使用以上函数来传送一个大小不适合的值结果常常是一个来自编译器的奇怪消息如coversion to non-scalar type requested. 在这些情况中必须使用 copy_to_user 或者 copy_from_user。 __put_user和__get_user 进行更少的检查(不调用 access_ok), 但是仍然能够失败如果被指向的内存对用户是不可写的所以他们应只用在内存区已经用 access_ok 检查过的时候。作为通用的规则当实现一个 read 方法时调用 __put_user 来节省几个周期, 或者当你拷贝几个项时因此在第一次数据传送之前调用 access_ok 一次。 权能与受限操作 Linux 内核提供了一个更加灵活的系统, 称为权能capability。内核专为许可管理上使用权能并导出了两个系统调用 capget 和 capset这样可以从用户空间管理权能其定义在 linux/capability.h 中。对设备驱动编写者有意义的权能如下: CAP_DAC_OVERRIDE /*越过在文件和目录上的访问限制(数据访问控制或 DAC)的能力。*/
CAP_NET_ADMIN /*进行网络管理任务的能力, 包括那些能够影响网络接口的任务*/
CAP_SYS_MODULE /*加载或去除内核模块的能力*/
CAP_SYS_RAWIO /*进行 raw裸I/O 操作的能力. 例子包括存取设备端口或者直接和 USB 设备通讯*/
CAP_SYS_ADMIN /*截获的能力, 提供对许多系统管理操作的途径*/
CAP_SYS_TTY_CONFIG /*执行 tty 配置任务的能力*/ 在进行一个特权操作之前, 一个设备驱动应当检查调用进程有合适的能力,检查是通过 capable 函数来进行的(定义在 linux/sched.h )范例如下: if (! capable (CAP_SYS_ADMIN))
return -EPERM; 二、定位设备llseek实现 llseek是修改文件中的当前读写位置的系统调用。内核中的缺省的实现进行移位通过修改 filp-f_pos, 这是文件中的当前读写位置。对于 lseek 系统调用要正确工作读和写方法必须通过更新它们收到的偏移量来配合。 如果设备是不允许移位的你不能只制止声明 llseek 操作因为缺省的方法允许移位。应当在你的 open 方法中通过调用 nonseekable_open 通知内核你的设备不支持 llseek : int nonseekable_open(struct inode *inode; struct file *filp); 完整起见, 你也应该在你的 file_operations 结构中设置 llseek 方法到一个特殊的帮助函数 no_llseek定义在 linux/fs.h 。 具体的应用在试验程序中学习. 三、ioctl和llseek实验。 模块程序链接ioctl_and_llseek 模块测试程序链接ioctl_and_llseek-test ARM9实验板的实验现象是 [Tekkaman2440SBC2440V4]#cd /lib/modules/
[Tekkaman2440SBC2440V4]#insmod scull.ko scull_nr_devs1
[Tekkaman2440SBC2440V4]#cd /tmp/
[Tekkaman2440SBC2440V4]#./scull_test2
open scull !
SCULL_IOCSQUANTUM-SCULL_IOCQQUANTUM : scull_quantum10
SCULL_IOCTQUANTUM-SCULL_IOCGQUANTUM : scull_quantum6
SCULL_IOCXQUANTUM : scull_quantum6 -- 10
SCULL_IOCHQUANTUM : scull_quantum10 -- 6
SCULL_IOCSQSET-SCULL_IOCQQSET : scull_qset2
SCULL_IOCTQSET-SCULL_IOCGQSET : scull_qset4
SCULL_IOCXQSET : scull_qset4 -- 2
SCULL_IOCHQSET : scull_qset2 -- 4
before reset : scull_quantum6 scull_qset4
close scull !
reopen scull !
reopen : scull_quantum6 scull_qset4
write code6 i20
write code6 i14
write code6 i8
write code2
lseek scull SEEK_SET--0 !
read code6 i20
read code6 i14
read code6 i8
read code2
[0]0 [1]1 [2]2 [3]3 [4]4
[5]5 [6]6 [7]7 [8]8 [9]9
[10]10 [11]11 [12]12 [13]13 [14]14
[15]15 [16]16 [17]17 [18]18 [19]19
SCULL_IOCRESET
after reset : scull_quantum4000 scull_qset1000
close scull !
reopen scull !
write code20
lseek scull SEEK_CUR-10--10 !
read code10
[0]10 [1]11 [2]12 [3]13 [4]14
[5]15 [6]16 [7]17 [8]18 [9]19
lseek scull SEEK_END-20--0 !
read code20
[0]0 [1]1 [2]2 [3]3 [4]4
[5]5 [6]6 [7]7 [8]8 [9]9
[10]10 [11]11 [12]12 [13]13 [14]14
[15]15 [16]16 [17]17 [18]18 [19]19
close scull !
[Tekkaman2440SBC2440V4]#cat /proc/scullseq
Device 0: qset 1000, q 4000, sz 20item at c3dd3d74, qset at c3f540000: c3e71000
[Tekkaman2440SBC2440V4]# 转载于:https://www.cnblogs.com/shenhaocn/archive/2011/03/27/1996874.html