驱动开发(二)——最简单的驱动程序分析

驱动开发(二)——最简单的驱动程序分析文章目录系统调用与驱动程序的流程最简单的驱动程序源码Makefile驱动测试应用程序测试系统调用与驱动程序的流程如下图通过分析源码,我们可以得出,从我们的测试程序到调用我们的驱动程序,整个过程包含如下:应用程序通过调用open函数,该函数由glibc库提供,作用是执行swi汇编指令,目的是为了产生中断异常,使得CPU进入到SVC模式,也就是我们常说的内核态。当CPU的权限提升到内核态以后,会调用内核中VFS(虚拟文件系统)提供的do_sys_open()函数,VFS也就是我们常说的system


系统调用与驱动程序的流程

如下图
在这里插入图片描述
通过分析源码,我们可以得出,从我们的测试程序到调用我们的驱动程序,整个过程包含如下:

应用程序通过调用open函数,该函数由glibc库提供,作用是执行swi汇编指令,目的是为了产生中断异常,使得CPU进入到SVC模式,也就是我们常说的内核态。

当CPU的权限提升到内核态以后,会调用内核中VFS(虚拟文件系统)提供的do_sys_open()函数,VFS也就是我们常说的system_call,为我们的应用程序提供了统一的接口,也使得Linux一切皆文件变成了事实。通过VFS提供的open函数对应用程序的传入文件、权限进行匹配处理。根据不同的情况调用不同的驱动处理程序。

那么对于我们的字符设备,VFS采用的方式就是通过查看该设备文件类型是否为c。并通过该文件的索引节点对象(inode),确定该设备文件是否注册其对应的file_operations结构体,如果注册了,表示该设备文件有其对应的驱动程序,则在内核中创建一个 struct file的结构体来表示文件描述符。如果没有注册其对应的驱动程序,则返回一个没有被使用的int型数字,但是对该数字无法操作,因为该文件描述符并没有抽象出设备文件的驱动程序。

因此,当在内核中成功的申请了struct file结构体(文件描述符),我们便可以调用对应的驱动函数中的read、write等函数。而我们写驱动的核心工作就是实现驱动的read,write函数

那么如何来写一个最简单的驱动程序呢?

最简单的驱动程序

这个驱动程序很简单,即我们实现对一个设备的读和写就行
注意:这里我们进行在Ubuntu上测试。有兴趣的朋友,可以自行在板子上测试,都一样。

源码

/*驱动程序不同于一般的应用程序,驱动程序的阅读方式是从下往上阅读 * 即从入口函数开始阅读到最后的出口函数 * */
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
/*设置主设备号,为什么定义为全局变量呢?就是为了能够在出口函数注销该主设备号*/
static int major=0;
static char buf[4]={ 
   0};
/*简单的实现read、write函数*/
static ssize_t simple_read(struct file *fp, char __user *buffer, size_t len, loff_t *pos){ 
   
    int ret;
    printk("%s %s line %d\n",__FILE__,__FUNCTION__ ,__LINE__);
    if(len<0){ 
   
        return -1;
    }
    if(len>3){ 
   
        len=3;
    }
    ret=copy_to_user(buffer,buf,len);
    return ret;
}
static ssize_t simple_write(struct file *fp, const char __user *buffer, size_t len, loff_t *pos){ 
   
    int ret;
    printk("%s %s line %d\n",__FILE__,__FUNCTION__ ,__LINE__);
    if(len<0){ 
   
        return -1;
    }
    if(len>3){ 
   
        len=3;
    }
    ret=copy_from_user(buf,buffer,len);
    return ret;
}

/*定义文件操作结构体*/
static struct file_operations fops={ 
   
    .owner = THIS_MODULE,
    .read  = simple_read,
    .write = simple_write,
};

/*编写入口函数*/
/*__init的作用就是为了实现,当我们注册完驱动以后,simple_driver_init这段代码就没用了 * 因此我们释放掉这段空间多好,多香*/
static int __init simple_driver_init(void)
{ 
   
    printk("simple_driver_init success\n");
    major=register_chrdev(0,"simple_driver",&fops);
    return 0;
}

static void __exit simple_driver_exit(void)
{ 
   
    printk("simple_driver_exit success\n");
    unregister_chrdev(major,"simple_driver");
    return ;
}

module_init(simple_driver_init);
module_exit(simple_driver_exit);
MODULE_AUTHOR("jacky");
MODULE_LICENSE("GPL");

Makefile

ARCH := x86
CROSS_COMPILE :=
KERNEL_VERSION :=$(shell uname -r)
KERNEL_DIR :=/lib/modules/$(KERNEL_VERSION)/build
SOURCE :=app_test.c

all:
	make -C $(KERNEL_DIR) M=`pwd` modules
	$(CROSS_COMPILE)gcc -o build $(SOURCE)
clean:
	make -C $(KERNEL_DIR) M=`pwd` modules clean
	rm -rf modules.order build

obj-m +=simple_driver.o


驱动测试

编译
在这里插入图片描述挂载:sudo insmod xxx.ko
在这里插入图片描述查看内核打印信息 : dmesg

在这里插入图片描述
查看设备号: cat /proc/devices
在这里插入图片描述
创建simple_driver的设备节点:sudo mknod /dev/simple c 240 0
在这里插入图片描述卸载驱动:sudo rmmod simple_driver

在这里插入图片描述

应用程序

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

char buffer[4]={ 
   0};

int main(int argc ,char **argv){ 
   

    //打开文件
    int fd=open("/dev/simple",O_RDWR);
    printf("fd:%d\n",fd);
    if(fd==-1){ 
   
        perror("[open file error]");
        return -1;
    }

    //写数据
    int ret=write(fd,"ABC",3);
    if(ret<0){ 
   
        fprintf(stderr,"write data error\n");
        goto failed;
    }
    printf("write:%d\n",ret);

    //读数据
    ret=read(fd,buffer,sizeof(buffer)-1);
    if(ret<0){ 
   
        fprintf(stderr,"read data error\n");
        goto failed;
    }
    printf("read:%s\n",buffer);
    return 0;
failed:
    return -1;

}

测试

在这里插入图片描述
在这里插入图片描述

今天的文章驱动开发(二)——最简单的驱动程序分析分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/24184.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注