Linux设备驱动之Ioctl控制Word格式.docx
- 文档编号:20974900
- 上传时间:2023-01-26
- 格式:DOCX
- 页数:12
- 大小:19.58KB
Linux设备驱动之Ioctl控制Word格式.docx
《Linux设备驱动之Ioctl控制Word格式.docx》由会员分享,可在线阅读,更多相关《Linux设备驱动之Ioctl控制Word格式.docx(12页珍藏版)》请在冰豆网上搜索。
但是命令码非常的不直观,所以LinuxKernel中提供了一些宏,这些宏可根据便于理解的字符串生成命令码,或者是从命令码得到一些用户可以理解的字符串以标明这个命令对应的设备类型、设备序列号、数据传送方向和数据传输尺寸。
1、定义命令:
内核提供了一些宏来帮助定义命令:
//nr为序号,datatype为数据类型,如int
_IO(type,nr)//没有参数的命令
_IOR(type,nr,datatype)//从驱动中读数据
_IOW(type,nr,datatype)//写数据到驱动
_IOWR(type,nr,datatype)//双向传送
定义命令例子:
#defineMEM_IOC_MAGIC'
m'
//定义类型
#defineMEM_IOCSET_IOW(MEM_IOC_MAGIC,0,int)
#defineMEM_IOCGQSET_IOR(MEM_IOC_MAGIC,1,int)
2、实现命令:
定义好了命令,下一步就是要实现ioctl函数了,ioctl的实现包括三个技术环节:
1)返回值;
ioctl函数的实现是根据命令执行的一个switch语句,但是,当命令不能匹配任何一个设备所支持的命令时,通常返回-EINVAL(非法参数);
2)参数使用;
用户使用intioctl(intfd,unsingedlongcmd,...)时,...就是要传递的参数;
再通过int(*ioctl)(structinode*inode,structfile*filp,
unsignedintcmd,unsignedlongarg)中的arg传递;
如果arg是一个整数,可以直接使用;
如果是指针,我们必须确保这个用户地址是有效的,因此,使用之前需要进行正确检查。
内部有检查的,不需要检测的:
copy_from_user
copy_to_user
get_user
put_user
需要检测的:
__get_user
__put_user
检测函数access_ok():
type:
是VERIFY_READ或者VERIFY_WRITE用来表明是读用户内存还是写用户内存;
addr:
是要操作的用户内存地址;
size:
是操作的长度。
如果ioctl需要从用户空间读一个整数,那么size参数就等于sizeof(int);
返回值:
Access_ok返回一个布尔值:
1,是成功(存取没问题);
0,是失败,ioctl返回-EFAULT;
staticinlineintaccess_ok(inttype,constvoid*addr,unsignedlongsize)
3)命令操作;
switch(cmd)
{
case:
......
}
三、ioctl实例分析:
(1)memdev.h:
#ifndef_MEMDEV_H_
#define_MEMDEV_H_
#include<
linux/ioctl.h>
#ifndefMEMDEV_MAJOR
#defineMEMDEV_MAJOR0/*预设的mem的主设备号*/
#endif
#ifndefMEMDEV_NR_DEVS
#defineMEMDEV_NR_DEVS2/*设备数*/
#ifndefMEMDEV_SIZE
#defineMEMDEV_SIZE4096
/*mem设备描述结构体*/
structmem_dev
{
char*data;
unsignedlongsize;
};
/*定义幻数*/
#defineMEMDEV_IOC_MAGIC'
k'
/*定义命令*/
#defineMEMDEV_IOCPRINT_IO(MEMDEV_IOC_MAGIC,1)
#defineMEMDEV_IOCGETDATA_IOR(MEMDEV_IOC_MAGIC,2,int)
#defineMEMDEV_IOCSETDATA_IOW(MEMDEV_IOC_MAGIC,3,int)
#defineMEMDEV_IOC_MAXNR3
#endif/*_MEMDEV_H_*/
(2)memdev.c:
(驱动程序)
linux/module.h>
linux/types.h>
linux/fs.h>
linux/errno.h>
linux/mm.h>
linux/sched.h>
linux/init.h>
linux/cdev.h>
asm/io.h>
asm/system.h>
asm/uaccess.h>
#include"
memdev.h"
staticintmem_major=MEMDEV_MAJOR;
module_param(mem_major,int,S_IRUGO);
structmem_dev*mem_devp;
/*设备结构体指针*/
structcdevcdev;
/*文件打开函数*/
intmem_open(structinode*inode,structfile*filp)
structmem_dev*dev;
/*获取次设备号*/
intnum=MINOR(inode->
i_rdev);
if(num>
=MEMDEV_NR_DEVS)
return-ENODEV;
dev=&
mem_devp[num];
/*将设备描述结构指针赋值给文件私有数据指针*/
filp->
private_data=dev;
return0;
/*文件释放函数*/
intmem_release(structinode*inode,structfile*filp)
/*IO操作*/
intmemdev_ioctl(structinode*inode,structfile*filp,
unsignedintcmd,unsignedlongarg)
interr=0;
intret=0;
intioarg=0;
/*检测命令的有效性*/
if(_IOC_TYPE(cmd)!
=MEMDEV_IOC_MAGIC)
return-EINVAL;
if(_IOC_NR(cmd)>
MEMDEV_IOC_MAXNR)
/*根据命令类型,检测参数空间是否可以访问*/
if(_IOC_DIR(cmd)&
_IOC_READ)
err=!
access_ok(VERIFY_WRITE,(void*)arg,_IOC_SIZE(cmd));
elseif(_IOC_DIR(cmd)&
_IOC_WRITE)
access_ok(VERIFY_READ,(void*)arg,_IOC_SIZE(cmd));
if(err)
return-EFAULT;
/*根据命令,执行相应的操作*/
switch(cmd){
/*打印当前设备信息*/
caseMEMDEV_IOCPRINT:
printk("
<
---CMDMEMDEV_IOCPRINTDone--->
\n\n"
);
break;
/*获取参数*/
caseMEMDEV_IOCGETDATA:
ioarg=1101;
ret=__put_user(ioarg,(int*)arg);
/*设置参数*/
caseMEMDEV_IOCSETDATA:
ret=__get_user(ioarg,(int*)arg);
---InKernelMEMDEV_IOCSETDATAioarg=%d--->
ioarg);
default:
}
returnret;
/*文件操作结构体*/
staticconststructfile_operationsmem_fops=
.owner=THIS_MODULE,
.open=mem_open,
.release=mem_release,
.ioctl=memdev_ioctl,
/*设备驱动模块加载函数*/
staticintmemdev_init(void)
intresult;
inti;
dev_tdevno=MKDEV(mem_major,0);
/*静态申请设备号*/
if(mem_major)
result=register_chrdev_region(devno,2,"
memdev"
else/*动态分配设备号*/
{
result=alloc_chrdev_region(&
devno,0,2,"
mem_major=MAJOR(devno);
}
if(result<
0)
returnresult;
/*初始化cdev结构*/
cdev_init(&
cdev,&
mem_fops);
cdev.owner=THIS_MODULE;
cdev.ops=&
mem_fops;
/*注册字符设备*/
cdev_add(&
cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS);
/*为设备描述结构分配内存*/
mem_devp=kmalloc(MEMDEV_NR_DEVS*sizeof(structmem_dev),GFP_KERNEL);
if(!
mem_devp)/*申请失败*/
result=-ENOMEM;
gotofail_malloc;
memset(mem_devp,0,sizeof(structmem_dev));
/*为设备分配内存*/
for(i=0;
i<
MEMDEV_NR_DEVS;
i++)
mem_devp[i].size=MEMDEV_SIZE;
mem_devp[i].data=kmalloc(MEMDEV_SIZE,GFP_KERNEL);
memset(mem_devp[i].data,0,MEMDEV_SIZE);
fail_malloc:
unregister_chrdev_region(devno,1);
/*模块卸载函数*/
staticvoidmemdev_exit(void)
cdev_del(&
cdev);
/*注销设备*/
kfree(mem_devp);
/*释放设备结构体内存*/
unregister_chrdev_region(MKDEV(mem_major,0),2);
/*释放设备号*/
MODULE_AUTHOR("
DavidXie"
MODULE_LICENSE("
GPL"
module_init(memdev_init);
module_exit(memdev_exit);
(3)app-ioctl.c(应用程序)
stdio.h>
#include<
sys/types.h>
sys/stat.h>
fcntl.h>
/*包含命令定义*/
intmain()
intfd=0;
intcmd;
intarg=0;
charBuf[4096];
/*打开设备文件*/
fd=open("
/dev/memdev0"
O_RDWR);
if(fd<
printf("
OpenDevMem0Error!
\n"
return-1;
/*调用命令MEMDEV_IOCPRINT*/
---CallMEMDEV_IOCPRINT--->
cmd=MEMDEV_IOCPRINT;
if(ioctl(fd,cmd,&
arg)<
CallcmdMEMDEV_IOCPRINTfail\n"
/*调用命令MEMDEV_IOCSETDATA*/
---CallMEMDEV_IOCSETDATA--->
cmd=MEMDEV_IOCSETDATA;
arg=2007;
CallcmdMEMDEV_IOCSETDATAfail\n"
/*调用命令MEMDEV_IOCGETDATA*/
---CallMEMDEV_IOCGETDATA--->
cmd=MEMDEV_IOCGETDATA;
CallcmdMEMDEV_IOCGETDATAfail\n"
---InUserSpaceMEMDEV_IOCGETDATAGetDatais%d--->
arg);
close(fd);
/*********************************************/
很棒!
谢谢楼主!
下面这些自动化脚本,锦上添花:
)
#!
/bin/sh
#install_mod.sh
module="
device="
mode="
664"
#Group:
sincedistributionsdoitdifferently,lookforwheelorusestaff
ifgrep'
^staff:
'
/etc/group>
/dev/null;
then
group="
staff"
else
wheel"
fi
#removestalenodes
rm-f/dev/${device}?
#invokeinsmodwithallargumentswegot
#anduseapathname,asnewermodutilsdon'
tlookin.bydefault
/sbin/insmod-f./$module.ko$*||exit1
major=`cat/proc/devices|awk"
\\$2==\"
$module\"
{print\\$1}"
`
mknod/dev/${device}0c$major0
mknod/dev/${device}1c$major1
ln-sf${device}0/dev/${device}
#giveappropriategroup/permissions
chgrp$group/dev/${device}[0-1]
chmod$mode/dev/${device}[0-1]
#unstall_mod.sh
#invokermmodwithallargumentswegot
/sbin/rmmod$module$*||exit1
#removenodes
rm-f/dev/${device}[0-1]/dev/${device}
exit0
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 设备 驱动 Ioctl 控制