嵌入式 globalmem设备驱动ioctl()函数的实现

来源:互联网 发布:重大网络教育学院 编辑:程序博客网 时间:2024/05/16 06:55
 一、ioctl的简介

在文件操作结构体file_operations中有很多的对应的设备操作函数,这些函数是通用的设备操作函数,但有些设备的操作是特有的,文件操作结构体不会有对应的函数定义。这样ioctl函数就将这些没办法归类的函数放在ioctl函数中,通过指定的命令来实现对应的操作。所以,ioctl函数里面都实现了多个的对硬件的操作,通过应用层传入的命令来调用相应的操作。下图是应用层与驱动函数的ioctl之间的联系

二、ioctl的cmd分析。

1.函数参数分析int (*ioctl)(struct inode * node, struct file *filp, unsigned int cmd, unsignedlong arg);

1)inode和file:ioctl的操作有可能要修改文件的属性,或者访问硬件。要修改文件属性就要用到这两个结构体了,所以这里传来了它们的指针。

2)cmd我们自己定义的命令,下面我将用实现三个命令。

3)arg:用户程序传来的参数,可以是数值参数也可以是指针参数,下面的测试将都会出现。

2.cmd构成部分,cmd由幻数、序数、数据传输方向、数据大小四部分组成,和ioctl-number.txt这两个文档有对其说明。

1)幻数,是个0~0xff的数,占8bit(_IOC_TYPEBITS)。这个数是用来区分不同的驱动的,内核有一个文档给出一些推荐的或者已经被使用的幻数。

2)序数用这个数来给自己的命令编号,占8bit(_IOC_NRBITS),下面的测试程序从1开始排序。

3)数据传输方向占2bit(_IOC_DIRBITS)。涉及到要传参,需要向内核描述一下传输的方向,传输的方向是以应用层的角度来描述的。

3.返回值

1)如果传入的非法命令,ioctl返回错误号-EINVAL。

2)内核中的驱动函数返回值都有一个默认的方法,只要是正数,内核就会默认为确的返回,并把它传给应用层,如果是负值,内核就会认为它是错误返回值ioctl里面多个不同的命令返回值有可能是不同的,因此需要根据该函数的功能来决定返回值类型。

三、ioctl实现的驱动代码

1.定义头文件test_cmd.h,在头文件中定义了三个用于ioctl函数指令。定义如下:

#ifndef_TEST_CMD_H

#define_TEST_CMD_H

#define TEST_MAGIC'x'

#define TEST_MAX_NR3

#define TEST_CLEAR_IO(TEST_MAGIC,1)//自定义的清除命令

#define TEST_OFFSET_IO(TEST_MAGIC,2)//自定义的修改文件指针位置的命令

#defineTEST_KBUF_IO(TEST_MAGIC,3)//自定义的修改内核内存数据命令

#endif

structioctl_data{//用于测试的数据结构体

unsignedint size;

charbuf[100];

};

2.ioctl函数修改的部分

static intglobalmem_ioctl(struct inode *inodep,struct file *filp,unsigned intcmd,unsigned long arg)

{

intret;

structglobalmem_dev*dev=filp->private_data;

structioctl_data val;

 

if(_IOC_TYPE(cmd)!=TEST_MAGIC)return-EINVAL;

if(_IOC_NR(cmd)>TEST_MAX_NR)return-EINVAL;

switch(cmd){

caseTEST_CLEAR://清零内存

memset(dev->mem,0,GLOBALMEM_SIZE);

filp->f_pos= 0;

printk(KERN_INFO"globalmem id set tozero\n");

break;

caseTEST_OFFSET://修改文件指针位置

filp->f_pos+= (int)arg;

break;

caseTEST_KBUF://修改kbuf

if(copy_from_user(&val, (structioctl_data *)arg, sizeof(struct ioctl_data)))

{

return- EFAULT;

}

memset(dev->mem,0,GLOBALMEM_SIZE);//初始化全局内存

memcpy(dev->mem,val.buf,val.size);//将内核数据结构体数据拷到全局内存中

filp->f_pos =0;

break;

default:

return-EINVAL;

}

return0;

}

3.测试应用程序test.c

#include

#include

#include

#include

#include

#include

#include"test_cmd.h"

#include

int main()

{

intfd;

charbuf[20]="Welcome toChina",receve[20]={'\0'};

structioctl_data test_data={

.size=10,

.buf="123456789"

};

fd= open("/dev/Mac",O_WRONLY);

if(fd< 0)

{

printf("open/dev/Mac error\n");

return0;

}

write(fd,buf,20);

close(fd);

fd =open("/dev/Mac",O_RDONLY);

if(fd< 0)

{

printf("open/dev/Mac error\n");

return0;

}

read(fd,receve,20);

printf("buf:%s\n",receve);

//ioctl(fd,TEST_CLEAR);

//ioctl(fd,TEST_OFFSET,-20);

ioctl(fd,TEST_KBUF,&test_data);

read(fd,receve,20);

printf("buf:%s\n",receve);

close(fd);

return0;

}

4.Makefile文件

ifneq($(KERNELRELEASE),)

obj-m :=globalmem.o

else

KDIR:=/lib/modules/2.6.28/build

all:

make-C $(KDIR) M=`pwd` modules

clean:

-rm-f *.ko *.o *.mod.o *.mod.c *.symversModule.markers modules.order pt_test

endif

到此工作完成,运行测试即可。