赞
踩
ioctl是linux中一种除read和write之外的数据传递机制
驱动层IOCTL:
int (*ioctl) (struct inode *inode, struct file *fp, unsigned int request, unsigned long args);
以上函数参数的含义如下。
在2.6.36以后ioctl函数已经不存在了,用unlocked_ioctl和compat_ioctl两个函数代替。参数去除了原来ioctl中的struct
inode参数,返回值也发生了改变。
新的代码
#include <linux/ioctl.h>
long (*unlocked_ioctl) (struct file * fp, unsigned int request, unsigned long args);
long (*compat_ioctl) (struct file * fp, unsigned int request, unsigned long args);
应用层IOCTL:
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
注意
驱动代码:
#include <linux/init.h> #include <linux/module.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/io.h> #include <linux/ioctl.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/unistd.h> #define BASEMINOR 0 #define COUNT 3 #define NAME "ioctl_test" #define MEMDEV_IOC_MAGIC 'k' //定义幻数 #define MEMDEV_IOCPRTDATA _IO(MEMDEV_IOC_MAGIC,1) //控制驱动打印数据 #define MEMDEV_IOCSETDATA _IOW(MEMDEV_IOC_MAGIC,3,int) //set数据到驱动中 #define MEMDEV_IOCGETDATA _IOR(MEMDEV_IOC_MAGIC,2,int) //从驱动中读数据 #define MEMDEV_IOCMAXNR 3 dev_t devno; struct cdev *cdevp = NULL; static long test_ioctl(struct file *filp,unsigned int cmd,unsigned long arg){ long ret = 0; int err = 0; int ioarg = 0; //第一步验证命令cmd参数的有效性 if(_IOC_TYPE(cmd) != MEMDEV_IOC_MAGIC){ return -EINVAL;} if(_IOC_NR(cmd) > MEMDEV_IOCMAXNR){ return -EINVAL;} //检测参数空间是否可以正确访问 //ioctl读取数据,需要向用户空间写入数据 if(_IOC_DIR(cmd) & _IOC_READ){ err = !access_ok((void *)arg,_IOC_SIZE(cmd)); } //ioctl设置数据,需要向用户空间读取数据 else if(_IOC_DIR(cmd) & _IOC_WRITE){ err = !access_ok((void *)arg,_IOC_SIZE(cmd)); } if(err){ return -EFAULT; } switch(cmd){ case MEMDEV_IOCPRTDATA: printk("---------打印函数执行成功---------\n"); break; case MEMDEV_IOCSETDATA: ret = __get_user(ioarg,(int *)arg); printk("从用户空间拿到的值:%d\n",ioarg); break; case MEMDEV_IOCGETDATA: ioarg = 1101; ret = __put_user(ioarg,(int *)arg); break; default: return -EINVAL; } return ret; } static const struct file_operations fops = { .owner = THIS_MODULE, .unlocked_ioctl = test_ioctl }; static int __init ioctl_init(void) { int ret; ret = alloc_chrdev_region(&devno,BASEMINOR,COUNT,NAME); if(ret < 0){ printk(KERN_ERR "alloc_chrdev_region failed...\n"); goto err1; } //设备号申请成功打印出来 printk(KERN_INFO "major = %d \n",MAJOR(devno)); cdevp = cdev_alloc(); if(NULL == cdevp){ printk(KERN_ERR "cdev_alloc failed...\n"); ret = -ENOMEM; goto err2; //cdev结构体申请失败需要将上一步申请到的设备号资源释放。 } cdev_init(cdevp,&fops); ret = cdev_add(cdevp,devno,COUNT); if(ret < 0){ printk(KERN_ERR "cdev_add failed...\n"); goto err2; } printk(KERN_INFO "---init over :%s---%s---%d---\n",__FILE__,__func__,__LINE__); return 0; err2: unregister_chrdev_region(devno,COUNT); //释放申请到的设备号资源 err1: return ret; } static void __exit ioctl_exit(void) { cdev_del(cdevp); unregister_chrdev_region(devno,COUNT); //释放申请到的设备号资源 printk(KERN_INFO "---%s---%s---%d---\n",__FILE__,__func__,__LINE__); } module_init(ioctl_init); module_exit(ioctl_exit); MODULE_LICENSE("GPL");
编译驱动的Makefile:
KERNDIR = /lib/modules/`uname -r`/build
PWD = $(shell pwd)
obj-m:=char_ioctl_driver.o
all:
make -C $(KERNDIR) M=$(PWD) modules
clean:
make -C $(KERNDIR) M=$(PWD) clean
应用层代码:
#include <stdio.h> #include <string.h> #include <linux/ioctl.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> int main() { int fd = 0; int cmd; int arg = 0; fd = open("/dev/ioctl_test",O_RDWR); if(fd < 0){ printf("open memdev0 failed!!!\n"); return -1; } cmd = _IO('k',1);//利用kernel api构造cmd if(ioctl(fd,cmd,&arg) < 0){ printf("-------打印命令传输失败--------\n"); return -1; } cmd = _IOW('k',3,int);//利用kernel api构造cmd arg = 2007; if(ioctl(fd,cmd,&arg) < 0){ printf("-----------应用层数据copy到驱动失败--------\n"); return -1; } cmd = _IOR('k',2,int);//利用kernel api构造cmd if(ioctl(fd,cmd,&arg) < 0){ printf("-------驱动数据copy到应用层数据失败---------\n"); return -1; } printf("从内核获取到的数据值:%d\n",arg); close(fd); return 0; }
编译与验证流程:
驱动make直接编译:
ubuntu:~/Desktop/huangrui/project_1/char_ioctl$ make
make -C /lib/modules/`uname -r`/build M=/home/xj/Desktop/huangrui/project_1/char_ioctl modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-149-generic'
CC [M] /home/Desktop/huangrui/project_1/char_ioctl/char_ioctl_driver.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] /home/Desktop/huangrui/project_1/char_ioctl/char_ioctl_driver.mod.o
LD [M] /home/Desktop/huangrui/project_1/char_ioctl/char_ioctl_driver.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-149-generic'
文件罗列:
char_ioctl$ ls
char_ioctl_driver.c char_ioctl_driver.mod char_ioctl_driver.mod.o char_ioctl_user Makefile Module.symvers
char_ioctl_driver.ko char_ioctl_driver.mod.c char_ioctl_driver.o char_ioctl_user.c modules.order
驱动加载:
sudo insmod char_ioctl_driver.ko
驱动模块查看:
project_1/char_ioctl$ lsmod
Module Size Used by
char_ioctl_driver 16384 0
btrfs 1249280 0
xor 24576 1 btrfs
查看驱动程序生成的设备及其主设备号:(可以作为mknod的参数)
$ cat /proc/devices
Character devices:
240 ioctl_test
创建设备节点:(cd到/dev下)
/dev$ sudo mknod ioctl_test c 240 0
查看设备节点情况:
/dev$ ls
ioctl_test
应用层代码编译:
$ gcc char_ioctl_user.c -o char_ioctl_user
执行结果:
$ sudo ./char_ioctl_user
从内核获取到的数据值:1101
驱动打印:
$ dmesg
[1192849.439778] major = 240
[1192849.439781] ---init over :/home/xj/Desktop/huangrui/project_1/char_ioctl/char_ioctl_driver.c---ioctl_init---97---
[1193159.265924] ---------打印函数执行成功---------
[1193159.265925] 从用户空间拿到的值:2007
验证成功!!!
这个就代表正在定义新的cmd
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。