linux驱动学习加强版-3 (驱动代码测试,以及代码完善)

一、用户测试代码

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

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;
    }

    if(strcmp(argv[1],"-w")==0 && argc==3)
    {
        write(fd, argv[2], strlen(argv[2]));
    }else
    {
        read(fd,buf,1024);
        buf[1023] = '\n';

        printf("APP get data %s\n",buf);
    }

    close(fd);
    
    return  0;
}

这样一个简单的用户demo就写完了,然后让我们来试试看结果吧;
使用 gcc -o file_ctl file_test.c 将测试的demo编译为一个可执行文件。
在这里插入图片描述
执行完后是乱码,我们看下log呢

在这里插入图片描述
发现Log是调用了的,为啥呢 。
因为我们驱动之提供了接口,但没有提供功能。
在这里插入图片描述

我们驱动没有提供功能,你们怎么使用呢。哈哈!所以接下来我们需要的是完善驱动功能

二、驱动功能完善。

这个demo的功能就是我调用对应的函数,将我要写的文件传递到底层,然后再把数据读取出来,返回给上层。
这个时候我们就需要内核的标准的函数

copy_from_user  // 从用户空间拷贝文件到驱动
copy_to_user // 从驱动拷贝文件到用户层
#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;
static char kbuffer[1024]; //内核空间的buffer

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__ );
    }
    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这个函数
};

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");

再来测试一把呢:
在这里插入图片描述
在这里插入图片描述

这样就OK了哇。

三、open函数的特异性

下面我们修改下代码:
首先是驱动文件,我们去掉read、write、open

#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;
static char kbuffer[1024]; //内核空间的buffer

// 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__ );
//     }
//     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这个函数
};

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");

在app代码中添加一些打印:

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

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';

        printf("APP get data %s\n",buf);
    }

    close(fd);
    
    return  0;
}

在这里插入图片描述没有read和write函数,我们无法读写。
但是我们可以进行open,这说明了open函数是一个比较特殊的函数,或许硬件默认就是可以进行open的,是为了方便一些初始化吧。大家记住就好。

四、代码中的注意事项

copy_to_user 和 copy_from_user传递的参数位置是不一样的哟

ret = copy_to_user(buf, kbuffer, size);
ret = copy_from_user(kbuffer, buf, size);

有些小伙伴可能没有注意到这点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

永不秃头的程序员

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

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

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

打赏作者

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

抵扣说明:

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

余额充值