ioctl()参数以及驱动编写遇到的问题

最近在做原子IMX6ULL的实验,在第50章Linux内核定时器实验的时候遇到了一点问题记录一下。
这个实验的逻辑就是利用ioctl()给硬件发命令。ioctl()函数在#include<unistd.h>中定义。
int ioctl( int fd, int request, …/* void *arg */ );
第三个参数总是一个指针,但指针的类型依赖于request 参数。
(一)在原子的视频里,APP文件中ioctl(fd,cmd,&arg)是这个形式,
在驱动中使用了copy_from_user(&value,int *(arg),sizeof(int))来get数据到value中,因为传入的arg是一个指针,我们要读取int类型的数据所以对这个指针进行强制类型转换,&value是要存入的地址,sizeof(int)是要读取数据的字节数。这样就成功的把APP文件传入的数据读取到value中了。
(二)在原子的例程里ioctl(fd,cmd,arg)是这个形式的,注意这个arg不是地址而是具体的数值,所以在驱动中直接value = arg;来获得APP传入的参数。

(三)我在实验的时候APP里直接ioctl(fd,cmd,arg)传入的是值,但是我在驱动中用了copy_from_user()在这个函数的参数里面要读取的地址我用了这个形式(int *)(&arg) 首先对arg取址,然后强制类型转换成int*类型的地址,但是这个方式时钟显示copy_from_user fail!!!!读取数据失败。
错误分析:用户空间传送一个数据给内核,直接传数据的话不能使用copy_from_user ,可能是因为这个数据取址之后的地址已经变成了内核空间的地址,用copy_rom_user就直接出错了。如果ioctl传入的是地址的话那么在驱动层得到的就是用户空间的内存地址,那么就可以用copy_from_user。
现在进行实验如下,首先利用ioctl(fd,cmd,arg)直接传送数据给内核空间,首先在用户空间打印出arg的地址发现是0X7E9D1C98,然后在对应的驱动中打印出arg的地址为0x8842ff1c显然这两个地址是不同的,那么我们可以合理的猜想,如果利用ioctl直接传值的话那么传进来的值会赋给一个内核空间的地址,也就是驱动中的arg,这个时候的arg是在内核开辟出来的一个地址空间用来存放值,所以我们看到两个地址是不同的,并且用copy_from_user会出错,因为明显这个地址就不是用户空间的地址,而是内核空间的。
在这里插入图片描利用述
接着的实验在APP代码中ioctl()直接传递的是arg的地址,我们在用户空间中打印出arg的地址和我们在内核中接收到的地址是相同的都是7e852c98,因此我们在驱动中调用copy_from_user可以得到arg对应地址的内容。
在这里插入图片描述
结论:
最终的出来,利用ioctl传递数据给驱动,如果直接传递的是值,那么直接在驱动中引用这个值,而不要再用到copy_from_user,因为在内核中看到的值实际上并不是用户空间的那个变量本身了。如果使用地址传递内容那么驱动得到的是用户空间的地址,那么是可以用copy_from_user。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值