嵌入式字符设备驱动程序

嵌入式字符设备驱动程序

字符设备驱动程序是将硬件设备封装的方法,对操作系统和应用程序隐藏硬件细节,仅向上提供API,即应用程序接口,read/oped/write/close等API函数接口。

嵌入式分为应用层,操作系统Linux层,驱动层,硬件层。以应用程序打开一个文件为例:

应用层:fd = open("/dev/myled", O_RDWR);
linux操作系统层会有一个sys_open()与之对应
驱动层struct file_operations结构体中定义.open = drv_myled_open()与sys_open()对应
驱动层执行对硬件的打开,读写等。
驱动程序编写的流程:
1.确定主设备号,一般设置major = 0;让内核进行分配。
2.定义自己的file_operations结构体
3.实现对应的drv_open/drv_read/drv_write等函数,填入file_operations结构体。
4.把file_operations结构体告诉内核:register_chrdev()
5.注册驱动程序,在入口函数中注册:安装驱动程序时,会调用这个函数
6.出口函数:卸载驱动函数时调用这个函数,unregister_chrdev();
7.创建设备信息,比如设备节点:class_create(),device_create(),便于对设备进行操作

1. Hello驱动(不涉及硬件操作)

本节会写一个不涉及硬件操作的驱动程序,也是一般驱动的模板,后面会涉及对具体引脚的操作,及驱动程序的优化:分离,设备树等

//一些头文件,可以参考内核中其他的字符设备
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

//1.确定设备号
static int major = 0;//static表示major变量仅本程序可见
static char kernel_buf[1024] = {0};//创建一个内核字符变量,用来存取从用户发送来的字符数据
static struct class *hello_class;//创建一个class结构体,用于创建设备节点的

//对要实现的函数进行声明
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset);
static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset);
static int hello_drv_open (struct inode *node, struct file *file);
static int hello_drv_close (struct inode *node, struct file *file);

//2.定义自己的file_operations结构体
static struct file_operations hello_drv = {
	.owner = THIS_MODULE,
	.open = hello_drv_open,
	.read = hello_drv_read,
	.write = hello_drv_write,
	.release = hello_drv_close,
};

//3.实现定义的hello_drv_open...函数,参考其他驱动程序
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset){
	//读函数,从内核中读取数据
	int ret;
	printk("%s %s line %d\n",__FILE__, __FUNCTION__, __LINE__);
	ret = copy_to_user(buf, kernel_buf, size);//内核与用户进行交互的函数
	return 0;
}

static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset){
	//写函数,从用户写入到内核
	int ret;
	printk("%s %s line %d\n", _FILE__, __FUNCTION__, __LINE__);
	ret = copy_from_user(kernel_buf, buf, size);//从用户拷贝到内核,上面从内核拷贝到用户
	return 0;
}

static int hello_drv_open(struct inode *node, struct file *file){
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static int hello_drv_close(struct inode* node, struct file* file){
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

//4.把file_operations结构体告诉内核:注册驱动程序
//5.在入口函数中注册驱动程序
static int __init hello_init(void){
	int ret;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	
	major = register_chrdev(0, "hello", &hello_drv); //注册file_operations,设备名
	hello_class = class_create(THIS_MODULE, "hello_class");
	device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello_drv");/*/dev/hello设备节点*/
	return 0;
}
//6.出口函数,卸载驱动程序
static void __exit hello_exit(void){
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	device_destory(hello_class, MKDEV(major, 0);
    class_destroy(hello_class);
    unregister_chrdev(major, "hello");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

上面就是标准的字符设备驱动程序的代码。

在Ubuntu中用交叉编译工具编译成hello_drv.ko文件,就可以在开发板上运行.

insmod hello_drv.ko:加载安装驱动程序

ls /dev/:查看设备节点,看是否有我们安装的hello设备节点

cat /proc/devices:查看所有的设备文件,包括主设备号和设备名

lsmod:查看已经加载的设备驱动

rmmod hello_drv:卸载驱动

2.hello驱动的测试程序

3.涉及硬件操作的设备驱动程序

先把坑挖好,后面有时间过来填坑。。。。

了解嵌入式开发的更多内容,关注微信公众号:河边小乌龟爬

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

河边小乌龟爬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值