linux驱动学习加强版-5(ioctl的使用)

文章介绍了如何在Linux驱动程序中添加ioctl函数,以便于用户空间通过ioctl调用驱动进行数据交互。示例代码展示了如何修改测试应用程序以支持读写和ioctl命令,并提供了驱动代码实现读写及ioctl操作,包括copy_to_user和copy_from_user函数的使用,确保用户空间和内核空间的数据传输。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


ioctl是用户空间和内核空间相互交流时候用的比较多的一种手段。
我们也可以在HAL层通过ioctl调到驱动里面。

一、添加ioctl控制节点

先看patch 吧
在这里插入图片描述

这是在驱动中添加的ioctl函数,同样的在ioctl里面去添加操作函数集合

二、修改测试APP

直接上源码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

// 我们目前只传递一个参数
static int file_ioctl(unsigned int cmd) {
    return 1;
}

#define FILECTL_READ       _IOR('c',0,unsigned int)   //对文件进行读取的命令
#define FILECTL_WRITE      _IOW('c',0,unsigned int)  //对文件进行写入的命令

int main(int argc,char **argv)
{   
    if(argc <2)
    {
        printf("Usage:%s -w <string>\n",argv[0]);
        printf("Usage:%s -r \n",argv[0]);

        return -1;
    }
    
    int fd;
    char buf[1024];
    fd = open("/dev/filectl",O_RDWR);
    if(fd < 0)
    {
        printf("can not open /dev/filectl\n");
        return -1;
    }
    printf("open /dev/filectl success \n");
    // 屏蔽掉原来的参数
    // if(strcmp(argv[1],"-w")==0 && argc==3)
    // {
    //     int err = write(fd, argv[2], strlen(argv[2]));
    //     if (err < 0 ) {
    //         printf("write /dev/filectl error \n");
    //         return -1;
    //     }
    //     printf("write /dev/filectl success \n");
    // }else
    // {
    //     int err = read(fd,buf,1024);
    //     if (err < 0 ) {
    //         printf("read /dev/filectl error \n");
    //         return -1;
    //     }
    //     printf("read /dev/filectl success \n");
    //     buf[1023] = '\n';
    //}

    // 添加ioctl的函数
    if (strcmp(argv[1] , "ior") == 0 ) { //通过参数比较来获取命令
        int rc = ioctl(fd, FILECTL_READ); // 通过ioctl 函数去传递参数
        if ( rc < 0 ) {
            printf("ioctl read  /dev/filectl error \n");
            return -1;
        }
        printf("ioctl read  /dev/filectl sucess \n");
    } else if ( strcmp(argv[1], "iow") == 0 ) {
        int rc = ioctl(fd, FILECTL_WRITE, argv[2]);
        if ( rc < 0 ) {
            printf("ioctl read  /dev/filectl error \n");
            return -1;
        }
        printf("ioctl read  /dev/filectl sucess \n");
    } else {
        printf("please input right argv[1], 'ior' or 'iow'");
        printf("It will return error\n");
        return -1;
    }
        printf("APP get data %s\n",buf);

    close(fd);
    
    return  0;
}

然后我们加载模块,运行测试app
在这里插入图片描述
在这里插入图片描述

同样的我们还是会存在问题,就是读写的接口这些是有问题的,和之前的逻辑一样,下一步就是完善这个代码逻辑。
目前我们的框架已经是ok的了

话不多说 直接上代码:

2.1 测试APP的代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#define FILECTL_READ       _IOR('c', 0, unsigned int)   //对文件进行读取
#define FILECTL_WRITE      _IOW('c', 0, unsigned int)  //对文件进行写入

int main(int argc,char **argv)
{   
	int temp = 0;
	char buffer[1024];  // 存放内核拷贝的数据
	if(argc <2)
    {
        printf("Usage:%s -w <string>\n",argv[0]);
        printf("Usage:%s -r \n",argv[0]);

        return -1;
    }
    
    int fd;
    char buf[1024];
    fd = open("/dev/filectl",O_RDWR);
    if(fd < 0)
    {
        printf("can not open /dev/filectl\n");
        return -1;
    }
    printf("open /dev/filectl success \n");

    if(strcmp(argv[1],"-w")==0 && argc==3)
    {
        int err = write(fd, argv[2], strlen(argv[2]));
        if (err < 0 ) {
            printf("write /dev/filectl error \n");
            return -1;
        }
        printf("write /dev/filectl success \n");
        printf("APP set  data %s\n",argv[2]);
    }else if (strcmp(argv[1],"-r")==0) {
        int err = read(fd,buf,1024);
        if (err < 0 ) {
            printf("read /dev/filectl error \n");
            return -1;
        }
        printf("read /dev/filectl success \n");
        printf("APP get  data %s\n", buf);
        buf[1023] = '\n';
    } else if (strcmp(argv[1] , "ior") == 0 ) {
        int rc = ioctl(fd, FILECTL_READ, &buffer); // 将内核传递的数据读取出来
        if ( rc < 0 ) {
            printf("ioctl read  /dev/filectl error \n");
            return -1;
        }
        printf("ioctl read  /dev/filectl sucess \n");
        printf("APP get  data %s\n", buffer);
        buf[1023] = '\n';
    } else if ( strcmp(argv[1], "iow") == 0 ) {
        int rc = ioctl(fd, FILECTL_WRITE, argv[2]); // 写入数据
        if ( rc < 0 ) {
            printf("ioctl write /dev/filectl error \n");
            return -1;
        }
        printf("ioctl read  /dev/filectl sucess \n");
        printf("APP set data %s\n",argv[2]);
    } else {
        printf("please input right argv[1], 'ior' or 'iow'");
        printf("It will return error\n");
        return -1;
    }
    close(fd);

    return  0;
}

2.2 驱动代码:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/stat.h>
#include <linux/tty.h>

static int major = 0; //确定主设备号,0默认系统分配
static struct class *filectl_class;
unsigned char kbuffer[1024]; // 内核空间的buffer
unsigned char ubuffer[1024]; // 申请一段空间用于存放用户数据

/*
  * FILECTL_READ 是和测试传递的参数是一样的才能匹配上 
  * FILECTL_WRITE 同样如此
  */

#define FILECTL_READ       _IOR('c', 0, unsigned int)   //对文件进行读取
#define FILECTL_WRITE      _IOW('c', 0, unsigned int)   //对文件进行写入


static long filectl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int ret;
	printk("[%s %d]1111\n", __FUNCTION__, __LINE__);

	switch(cmd) {
		case FILECTL_READ:
            ret = copy_to_user((void __user *)arg, ubuffer, sizeof(ubuffer)); // 将内核空间的buffer拷贝至用户空间
            if(ret < 0) {
                printk("[%s %d]copy_to_user error\n ",__FUNCTION__, __LINE__);
			}
			printk("[%s %s %d]\n", __FILE__, __func__, __LINE__);
			break;
		case FILECTL_WRITE:
            ret = copy_from_user(ubuffer, (void __user *)arg, sizeof(ubuffer)); 
            if(ret < 0) {
                printk("[%s %d]copy_from_user error \n ",__FUNCTION__, __LINE__);
            }
			printk("[%s %s %d]\n", __FILE__, __func__, __LINE__);
			break;
	}
    return 0;
}

ssize_t filectl_read(struct file *file, char __user *buf, size_t size, loff_t *pops)
{
    int ret;
	printk("[%s %d]\n", __FUNCTION__, __LINE__);
    ret = copy_to_user(buf, kbuffer, size);
    if(ret < 0) {
        printk("[%s %d]copy_to_user error \n ",__FUNCTION__, __LINE__ );
    }
	printk("[%s %s %d]\n", __FILE__, __func__, __LINE__);
    return size;
}

ssize_t filectl_write(struct file *file,const char __user *buf, size_t size, loff_t *pops)
{
    int ret;
	printk("[%s %d]\n", __FUNCTION__, __LINE__);
    ret = copy_from_user(kbuffer, buf, size);
    if(ret < 0) {
        printk("[%s %d]copy_from_user error \n ",__FUNCTION__, __LINE__ );
    }
    return size;
}

int filectl_open(struct inode *inode, struct file *file)
{
	printk("[%s %d]\n", __FUNCTION__, __LINE__);
    return 0;
}

int filectl_close(struct inode *inode, struct file *file)
{
	printk("[%s %d]\n", __FUNCTION__, __LINE__);
    return 0;
}

// 定义自己的驱动的 file_operations
static struct file_operations filectl_ops = {
    .owner	 = THIS_MODULE,
    .read    = filectl_read,
    .write   = filectl_write,
    .open    = filectl_open,
    .release = filectl_close, // 好像没有close这个函数
    .unlocked_ioctl = filectl_ioctl, //添加ioclt操作函数
};

static int __init filectl_init(void)
{
    // 在初始化的时候进行驱动注册, 设备号, 设备名,核心操作函数
    major = register_chrdev(0,"filectl",&filectl_ops); 
    if(major < 0) {
        printk("[%s %d] filectl error\n", __FUNCTION__, __LINE__); // 注册失败
        return -1;
    }

    filectl_class = class_create(THIS_MODULE, "filectl"); // class_create 动态创建dev的类
    // IS_ERR 查看指针是否有错误
    if(IS_ERR(filectl_class)) {
        printk("[%s %d] class_create error\n", __FUNCTION__, __LINE__);
        unregister_chrdev(major,"filectl");
        return -1;
    }
	// 创建字符设备
    device_create(filectl_class, NULL, MKDEV(major, 0),NULL, "filectl");
    printk("[%s %d] filectl driver create success\n", __FUNCTION__, __LINE__);

    return 0;
}

static void __exit filectl_exit(void) {
    device_destroy(filectl_class, MKDEV(major, 0));
    class_destroy(filectl_class);
    // 注销字符设备
	unregister_chrdev(major,"filectl");
    printk("[%s %d]goodbye filectl driver\n",  __FUNCTION__, __LINE__);
}

module_init(filectl_init);
module_exit(filectl_exit);
MODULE_LICENSE		("GPL");
MODULE_AUTHOR		("cong.luo");
MODULE_DESCRIPTION	("First file contrl module");

测试结果:
在这里插入图片描述

内核使用两个buf,使用 ioctl 和 之前的读写接口互不影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永不秃头的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值