操作驱动的上层代码(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