linux系统-树莓派内核驱动

本文详细介绍了树莓派设备驱动的开发过程,包括用户空间通过API与内核交互,设备号的概念,内核空间的驱动框架,以及如何编写和加载驱动模块。通过实例展示了驱动程序的创建、注册和卸载,以及测试驱动的步骤,帮助读者理解Linux系统中硬件驱动的工作原理。
摘要由CSDN通过智能技术生成

驱动模块概述

内核实现驱动的路径

用户空间

linux 一切皆文件
设备文件: 鼠标、键盘、LED、屏幕、Flash、内存、网卡

对于文件的API的控制有:open、read、write

这些API能打开不同硬件设备,并控制,是因为不同设备有不同的设备驱动

编辑设备驱动就只有两个功能:
1、添加驱动

  • 设备名
  • 设备号
  • 设备驱动函数
    • 操作寄存器来驱动IO口

2、调用驱动

驱动实现路径:

用户层:open(”/dev/pin4”,O_RDWR)——>
open去调用sys_call

从用户空间到内核空间会发生一次软中断,中断号:0x80

为了快速响应用汇编去实现了sys_call

内核层:sys_call——>

sys_call去调用VFS里的sys_open

VFS:sys_open——>

sys_open根据设备名,去找到对应的主设备号,次设备号,再去找到pin4引脚的设备驱动里的open

驱动pin4:open——>

open就的对寄存器的操作,驱动IO口

APP应用层

APP: CP指令,FTP项目,实现各种功能的应用层的软件

APP需要基础: C语言,C库

C库功能: 文件,进程,进程间通信,线程,网络,界面(GTK)

打开设备:

fd=open(”/dev/pin4”,O_RDWR);

1、需要有设备文件名,pin4
2、硬件设备号1

  • 主设备号
  • 次设备号
Linux的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备文件。应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备

C library & C库

提供了APP支配内核工作的接口,由此处封装实现各种功能

open、read、write、fork、pthread、socket

  • C 库是所有系统基本都会有,但wiringPI库,不同的平台就不一定会提供,那么开发者就必须要学会自己开发,树莓派的就是可以用wiringPI库

内核空间

应用层open调用:
sys_call

调用VFS虚拟文件系统:

sys_open、sys_read、sys_write

进程、内存、线程、网络、设备驱动

设备驱动有驱动链表管理所有设备的驱动

有两个功能:
1、添加

  • 编写完驱动程序,加载到内核
    2、查找
  • 调用驱动程序,用户空间用open,通过设备号进行检索

驱动程序是在内核中呈现链表的形式存在

驱动插入链表的顺序,也是通过设备号进行检索

磁盘驱动——>pin4驱动——>pin5驱动——>pin6驱动

对应的驱动控制对应的设备

硬件

磁盘.txt、pin4、pin5、pin6

驱动框架应用

基础的驱动框架:

#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_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{

    return 0;
}

static struct file_operations pin4_fops = {
    .owner = THIS_MODULE,
    .open  = pin4_open,
    .write = pin4_write,
};

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);  //入口, 内核加载该驱动的时候,这时,这个宏会被调用
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");

static:限定作用域,限定变量只能当前文件使用,防止其它文件内也有同样的变量名之后造成冲突

可以用命令来生成设备

sudo mknod yang c 8 1
超级用户 生成一个yang的字符设备,主设备号为8,次设备号为1

pin4测试驱动框架:

#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 ssize_t 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,
    .read  = pin4_read,
    .write = pin4_write,
};

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");
    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);  //入口
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");


上层驱动程序:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
        int fd;
        fd = open("/dev/pin4",O_RDWR);
        if(fd < 0){
                printf("open failed\n");
                perror("reson");
        }else{
                printf("open success\n");
        }
        fd = write(fd,'1',1);
        return 0;
}

printk(“pin4_write\n”); 相当于printf函数效果,只不过是需要用dmesg查看内核打印信息

启用模块编译

因为是字符设备,所以需要把编写的pin4driver.c 代码C文件拷贝到内核文件里的char文件夹下

cp pin4driver.c /home/yangyingchun/SYSTEM/linux-rpi-4.14.y/drivers/char/.

模块编译:

1、因为是把驱动文件拷贝到了 /home/yangyingchun/SYSTEM/linux-rpi-4.14.y/drivers/char/
这个文件夹下,所以要修改当前文件夹 /home/yangyingchun/SYSTEM/linux-rpi-4.14.y/drivers/char/
下的Makefile文件

告诉编译器,要编译该驱动文件

vi Makefile

新添加一行,添加驱动编译模块
obj-m += pin4driver.o

2、编译内核驱动

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules

生成pin4driver.ko文件

3、拷贝驱动模块pin4driver.ko文件到树莓派

scp drivers/char/pin4driver.ko pi@192.168.1.105:/home/pi

拷贝测试程序:
scp pin4test pi@192.168.1.105:/home/pi

转到树莓派操作

4、加载内核驱动
sudo insmod pin4driver.ko

5、查看当前内核模块,看驱动设备模块是否加载成功
lsmod

6、给驱动模块pin4driver.ko文件权限
sudo chmod 666 /dev/pin4

7、执行测试程序

./pin4test

8、查看内核打印信息

dmesg

9、卸载驱动
sudo rmmod pin4driver


  1. 设备号讲解 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值