基于框架编写驱动代码

操作驱动的上层代码(pin4test)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>void main()
{int fd,data;fd = open("/dev/pin4",O_RDWR);if(fd<0){printf("open fail\n");perror("reson:");}else{printf("open successful\n");}fd=write(fd,'1',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_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{printk("pin4_write\n");  //内核的打印函数和printf类似return 0;
}static struct file_operations pin4_fops = {.owner = THIS_MODULE,.open  = pin4_open,.write = pin4_write,
};
//static限定这个结构体的作用,仅仅只在这个文件。
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");

自动生成设备(以下代码在框架中):

pin4_class=class_create(THIS_MODULE,"myfirstdemo");//让代码在dev下自动生成设备

手动生成设备:

sudo mknod 设备名 设备类型 主设备号 次设备号 
sudo mknod feng c 8 1
//c是字符型设备类型
//生成成功如下图

在这里插入图片描述

驱动代码(pin4driver)

#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;
}
//read函数
static int pin4_read(struct file *file,char __user *buf,size_t count,loff_t *ppos)
{printk("pin4_read\n");  //内核的打印函数和printf类似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");  //内核的打印函数和printf类似return 0;
}static struct file_operations pin4_fops = {.owner = THIS_MODULE,.open  = pin4_open,.write = pin4_write,.read  = pin4_read,
};
//static限定这个结构体的作用,仅仅只在这个文件。
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");

进入linux源码树目录下的字符设备下(drivers/char/)这个文件夹,创建一个.c文件名为pin4driver2.c(名字自己定义),将驱动代码写入也可以将写好的.c文件拷贝进来

配置Makefile(模块的形式)

加入下面这句代码
obj-m                           += pindriver.o

在源码树目录下进行编译

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules
//指定架构是arm架构
//交叉编译工具是arm-linux-gnueabihf-
//KERNEL=kernel7 内核的版本
//生成modules

将生成的 pin4driver.ko和交叉编译好的上层代码pin4test(自己定义) 发送到开发板(我这里使用的是树莓派3b)

交叉编译指令:

arm-linux-gnueabihf-gcc pintest.c -o pin4test

开发板端

sudo insmod pin4driver2.ko 
//加载内核模块,就会自动的在dev下生成pin4文件若直接运行pin4test会出现以下报错:
open fail
reson:: Permission denied
//报错——没有权限打开这个文件pi@raspberrypi:~ $ lsmod(可以查看驱动是否装进去,列出内核的驱动模块)
Module                  Size  Used by
pin4driver2            16384  0//由此可见驱动已经装好
fuse                  106496  3
rfcomm                 49152  4
bnep                   20480  2
hci_uart               36864  1
btbcm                  16384  1 hci_uart
serdev                 20480  1 hci_uart
bluetooth             372736  29 hci_uart,bnep,btbcm,rfcomm
ecdh_generic           28672  1 bluetooth
8021q                  32768  0
garp                   16384  1 8021q
stp                    16384  1 garp
llc                    16384  2 garp,stp
brcmfmac              278528  0
brcmutil               16384  1 brcmfmac
cfg80211              569344  1 brcmfmac
rfkill                 24576  6 bluetooth,cfg80211
snd_bcm2835            32768  2
snd_pcm                98304  1 snd_bcm2835
snd_timer              32768  1 snd_pcm
snd                    69632  7 snd_timer,snd_bcm2835,snd_pcm
uio_pdrv_genirq        16384  0
uio                    20480  1 uio_pdrv_genirq
fixed                  16384  0
i2c_dev                16384  0
ip_tables              24576  0
x_tables               32768  1 ip_tables
ipv6                  425984  24sudo chmod 666 /dev/pin4
//这句指令的意思是修改权限,666是所有人都可以打开

删除驱动模块

sudo rmmod 驱动模块名(不用写后缀ko)
//删除驱动模块,dev下的设备文件也会被删除

查看内核态打印的内容

dmesg
//查看内核态打印的printk
通过下图可以看到通过上层的open和write触发底层
驱动调用open和write,打印pin4_open和pin4_write

在这里插入图片描述

Published by

风君子

独自遨游何稽首 揭天掀地慰生平