linux字符设备驱动程序--创建设备节点
基于4.14内核,运行在beagleBone green
在上一讲中,我们写了第一个linux设备驱动程序——hello_world,在驱动程序中,我们什么也没有做,仅仅是打印了两条日志消息,今天,我们就要丰富这个设备驱动程序,在/dev目录下创建一个设备节点,用户通过读写文件来与内核进行交互。
预备知识
在linux中,一切皆文件,不管用户是控制某个外设又或者是操作I/O,都是通过文件实现。
设备驱动程序被装载在内核中运行,当用户程序需要使用对应设备时,自然不可能直接访问内核空间,那么用户程序应该怎么做呢?
答案是内核将设备驱动程序操作接口以文件接口的形式导出到用户空间,一般为相应的设备在/dev目录下建立相应的操作接口文件,自linux2.6内核版本以来,内核还会在系统启动时创建sysfs文件系统,内核同样可以将设备操作接口导出到/sys目录下。
举个例子:在开发一款温度传感器时,内核驱动模块可以在驱动程序中实现传感器的初始化,然后在/dev目录下创建对应文件,关联/dev的读写回调函数,当用户访问/dev下相应文件时,就会调用相应的回调函数,执行设备的操作。
下面我们就演示如何在/dev目录下创建一个设备节点。
程序实现
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
MODULE_AUTHOR("Downey");
MODULE_LICENSE("GPL");
static int majorNumber = 0;
/*Class 名称,对应/sys/class/下的目录名称*/
static const char *CLASS_NAME = "basic_class";
/*Device 名称,对应/dev下的目录名称*/
static const char *DEVICE_NAME = "basic_demo";
static int basic_open(struct inode *node, struct file *file);
static ssize_t basic_read(struct file *file,char *buf, size_t len,loff_t *offset);
static ssize_t basic_write(struct file *file,const char *buf,size_t len,loff_t* offset);
static int basic_release(struct inode *node,struct file *file);
static char msg[] = "Downey!";
static char recv_msg[20];
static struct class *basic_class = NULL;
static struct device *basic_device = NULL;
/*File opertion 结构体,我们通过这个结构体建立应用程序到内核之间操作的映射*/
static struct file_operations file_oprts =
{
.open = basic_open,
.read = basic_read,
.write = basic_write,
.release = basic_release,
};
static int __init basic_init(void)
{
printk(KERN_ALERT "Driver init\r\n");
/*注册一个新的字符设备,返回主设备号*/
majorNumber = register_chrdev(0,DEVICE_NAME,&file_oprts);
if(majorNumber < 0 ){
printk(KERN_ALERT "Register failed!!\r\n&