基于框架编写驱动代码并加载驱动进行测试

对于内核驱动代码编写而言,它不像我们写FTP项目那样完全是一步步编写完成,驱动代码编写是基于内核特定框架编写得,里面涉及到底层相关得API也是不要我们去记忆得,我们只需要去注意基于框架编写驱动、加载驱动、测试驱动、查看内核打印信息如何实现即可。

1. 内核驱动基本框架(精简版):
驱动代码:

#include <linux/fs.h>            //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>        //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //ioremap iounmap的头文件


static struct class *pin4_class;
static struct device *pin4_class_dev;

static dev_t devno;                //设备号
static int major =231;                     //主设备号
static int minor =0;                       //次设备号
static char *module_name="pin4";   //模块名




//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{
        printk("pin4_open\n");  //内核的打印函数和printf类似

        return 0;
}

//led_read函数
static int pin4_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
{
        printk("pin4_read\n");

        return 0;
}

//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
        printk("pin4_write\n");

        return 0;
}

static struct file_operations pin4_fops = {

        .owner = THIS_MODULE,
        .open  = pin4_open,
        .write = pin4_write,
        .read  = pin4_read,
};

int __init pin4_drv_init(void)
{

        int ret;
        devno = MKDEV(major,minor);  //创建设备号
        ret   = register_chrdev(major, module_name,&pin4_fops);  //注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中

        pin4_class=class_create(THIS_MODULE,"myfirstdemo");  //让代码在dev自动生成设备
        pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name);  //创建设备文件


        return 0;
}

void __exit pin4_drv_exit(void)
{

        device_destroy(pin4_class,devno);
        class_destroy(pin4_class);
        unregister_chrdev(major, module_name);  //卸载驱动

}

module_init(pin4_drv_init);  //,注意这个不是函数调用,它是一个宏,是加载内核的入口,内核加载驱动的时候,这个宏会被调用,即pin4_drv_init()这个函数会被调用
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");
~                              

测试代码:

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

int main(int argc, char *argv[])
{
        int fd;
        int n_write;
        int n_read;
        char buf[12] = {0};

        fd = open("/dev/pin4", O_RDWR);
        if (fd == -1){
                printf("open /dev/pin4 failuer\n");
                perror("failuer reason");
        }
        else {
                printf("fd = %d\n", fd);
                printf("open /dev/pin4 success\n");
        }

        n_write = write(fd, '8', 1);
        printf("write %d bytes\n", n_write);

        n_read = read(fd, buf, 12);
        printf("read %d bytes\n", n_read);

        return 0;
}

2. 如何生成".ko"文件并加载该驱动:
(1)在/home/zhangkun/SYSTEM/linux-rpi-4.14.y/drivers/char下打开Makefile,添加我们所要编的驱动,即;
在这里插入图片描述其中"m"代表以模块的方式生成该驱动,同时将测试代码交叉编译,即arm-linux-gnueabihf-gcc pin4Test.c -o pin4Test

(2)将该驱动代码pin4Driver2.c拷贝至/home/zhangkun/SYSTEM/linux-rpi-4.14.y/drivers/char ,并进行编译,即ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules
在这里插入图片描述
(3)将pin4Driver2.ko、pin4Test拷贝到树莓派中,即scp drivers/char/pin4Driver2.ko pi@172.20.10.6:/home/piscp pin4Test pi@172.20.10.6:/home/pi:
在这里插入图片描述
(4)将内核驱动加载到树莓派中,即sudo insmod pin4Driver2.ko
在这里插入图片描述
然后,运行pin4Test:
在这里插入图片描述出现这种现象的原因是,我们打开/dev/pin4时没有权限,至=只有root模式下才能open,所以我们需要改变/dev/pin4的权限,即sudo chmod 666 /dev/pin4 ,再次运行pin4Test:
在这里插入图片描述注意到这里read、write都返回的是0而不是1,明明都已经往里面写了字符’8’,为什么还是读写了0个字节呢?原因很简单,就是对于该驱动而言,上层read、write调用的是底层pin4_read、pin4_write,它们的返回值都是0,从而导致我们在终端打印时看到的读写都是0个字节,如果要改成读写都是1个字节,就需要我们将pin4_read、pin4_write的返回值改为1。从这里也可以看出内核驱动的深不可测,要实现read、write底层是需要从很多工作的。
最后通过dmesg查看内核在运行完pin4Test后打印的信息:
在这里插入图片描述说明上层确实是成功调用了底层的pin4_read、pin4write。

最后,再总结下该驱动整个实现过程:对于内核而言,它本身就是一个代码库,一个程序,一个超级裸机。上层open的时候,通过设备名字即/dev/pin4去调用驱动的,文件名背后则包含主设备号和次设备号,同时产生一个软中断,open去触发系统调用即sys_call,sys_call会穿透虚拟文件系统,虚拟文件系统sys_open会根据/dev/pin4所带设备名、设备号,在内核的驱动链表里面找到对应的驱动, 去调用加载的驱动函数即pin4_open函数。对于read、write也是同样的实现过程。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值