驱动只实现ioctrl接口并使用ioctl修改和读取内核中的一个整型参数为例,使用两个不同方式读取(值传递和地址传递)。
应用程序测试代码main.c
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define IOCTL_RESET 100 /*重置命令*/
-
#define IOCTL_GET1 101 /*读取命令值返回*/
-
#define IOCTL_GET2 102 /*读取命令地址返回*/
-
#define IOCTL_SET1 103 /*设置命令值传入*/
-
#define IOCTL_SET2 104 /*设置命令地址传入*/
-
-
int main (int *argc,char**argv)
-
{
-
int fs;int val;
-
fs=open("/dev/moduledev60",O_RDWR);
-
if(fs<0)
-
{
-
printf("open fail\n");
-
return -1;
-
}
-
-
ioctl(fs,IOCTL_SET1,1000);
-
printf("ioctl get1 result:%d\n",ioctl(fs,IOCTL_GET1));
-
ioctl(fs,IOCTL_GET2,&val);
-
printf("ioctl get2 result:%d\n",val);
-
-
-
ioctl(fs,IOCTL_SET1,-100);
-
printf("ioctl get1 result:%d\n",ioctl(fs,IOCTL_GET1));
-
ioctl(fs,IOCTL_GET2,&val);
-
printf("ioctl get2 result:%d\n",val);
-
-
-
val=5555;
-
ioctl(fs,IOCTL_SET2,&val);
-
printf("ioctl get1 result:%d\n",ioctl(fs,IOCTL_GET1));
-
-
close(fs);
-
return 0;
-
}
驱动主要部分 fileops.c
-
#define IOCTL_RESET 100 /*重置命令*/
-
#define IOCTL_GET1 101 /*读取命令值返回*/
-
#define IOCTL_GET2 102 /*读取命令地址返回*/
-
#define IOCTL_SET1 103 /*设置命令值传入*/
-
#define IOCTL_SET2 104 /*设置命令地址传入*/
-
int drive_param=0;
-
int fileops_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
-
{
-
printk(KERN_ALERT "fileops_ioctl \n");
-
switch(cmd)
-
{
-
case IOCTL_RESET:
-
drive_param=0;
-
break;
-
case IOCTL_GET1:
-
return drive_param;
-
break;
-
case IOCTL_GET2:
-
-
if(copy_to_user((int __user*)arg,&drive_param,4)) return -ENOTTY;
-
break;
-
case IOCTL_SET1:
-
drive_param=arg;
-
break;
-
case IOCTL_SET2:
-
-
if(copy_from_user(&drive_param,(int __user*)arg,4))return -ENOTTY;
-
break;
-
}
-
return 0;
-
}
传送单个值时使用 __put_user __get_user要比copy相对快, 注意 __put_user,__get_user 应当只用在已经使用 access_ok 校验过的地址.copy_from_user和copy_to_user跟踪代码会发现已经加了access_ok的校验。
执行结果
-
ioctl get1 result:1000
-
ioctl get2 result:1000
-
ioctl get1 result:-1
-
ioctl get2 result:-100
-
ioctl get1 result:5555
会发现使用值返回负数-100时,驱动接口内返回-100应用程序的ioctl返回的是-1,使用地址传递参数则正确读取。
下面是部分ioctl-number.tx的内容
-
If you are adding new ioctl's to the kernel, you should use the _IO macros defined in <linux/ioctl.h>:
-
-
_IO an ioctl with no parameters
-
_IOW an ioctl with write parameters (copy_from_user)
-
_IOR an ioctl with read parameters (copy_to_user)
-
_IOWR an ioctl with both write and read parameters.
-
-
'Write' and 'read' are from the user's point of view, just like the system calls 'write' and 'read'. For example, a SET_FOO ioctl would be _IOW, although the kernel would actually read data from user space;
-
a GET_FOO ioctl would be _IOR, although the kernel would actually write data to user space.
-
-
The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter or number from the table below. Because of the large number of drivers,many drivers share a partial letter with other drivers.
-
-
If you are writing a driver for a new device and need a letter, pick an unused block with enough room for expansion: 32 to 256 ioctl commands.
-
You can register the block by patching this file and submitting the patch to Linus Torvalds. Or you can e-mail me at <mec@shout.net> and I'll register one for you.
-
-
The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number to distinguish ioctls from each other. The third argument to _IOW,_IOR, or _IOWR is the type of the data going into the kernel or coming out of the kernel (e.g. 'int' or 'struct foo'). NOTE! Do NOT use sizeof(arg) as the third argument as this results in your ioctl thinking it passes an argument of type size_t.
-
Some devices use their major number as the identifier; this is OK, as long as it is unique. Some devices are irregular and don't follow any convention at all.
-
-
Following this convention is good because:
-
(1) Keeping the ioctl's globally unique helps error checking: if a program calls an ioctl on the wrong device, it will get an error rather than some unexpected behaviour.
-
(2) The 'strace' build procedure automatically finds ioctl numbers defined with _IO, _IOW, _IOR
-
(3) 'strace' can decode numbers back into useful na
-
, or _IOWR. mes when the numbers are unique.
-
(4) People looking for ioctls can grep for them more easily when this convention is used to define the ioctl numbers.
-
(5) When following the convention, the driver code can use generic code to copy the parameters between user and kernel spac
阅读(863) | 评论(0) | 转发(0) |