【Linux】【驱动】自动创建设备节点

【Linux】【驱动】自动创建设备节点

  • 驱动代码
  • 操作指令
    • linux端
    • 从机端

这里展示了如何自动的方式去创建一个字符类的节点
下面就是需要调用到的程序

函数

 void cdev_init(struct cdev *, const struct file_operations *);

第一个参数 要初始化的 cdev
第二个参数 文件操作集 cdev->ops = fops; //实际就是把文件操作集写给 ops
功能 cdev_init()函数用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接。

函数

 int cdev_add(struct cdev *, dev_t, unsigned);

第一个参数 cdev 的结构体指针
第二个参数 设备号
第三个参数 次设备号的数量
功能 cdev_alloc()函数用于动态申请一个 cdev 内存

void cdev_del(struct cdev *);

cdev 的结构体指针

生成设备节点
字符设备注册完以后不会自动生成设备节点。我们需要使用 mknod 命令创建一个设备节点
格式:mknod 名称 类型 主设备号 次设备号

mknod /dev/test c 247 0

驱动代码

代码实现的流程

从 hello_init 函数开始看,

  1. 注册设备号,
  2. 初始化 cdev
  3. 向系统注册设备
  4. 创建 class 类
  5. 在 class 类下创建设备

从hello_exit 来看

  1. 注销设备号
  2. 删除设备
  3. 注销设备
  4. 删除类
#include 
#include      //最基本的文件,支持动态添加和卸载模块。
#include         //包含了文件操作相关 struct 的定义,例如大名鼎鼎的 struct file_operations
#include 
#include  //对字符设备结构 cdev 以及一系列的操作函数的定义。//包含了 cdev 结构及相关函数的定义。
#include  //包含了 device、class 等结构的定义



#define DEVICE_NUMBER 1 		//定义次设备号的个数
#define DEVICE_SNAME "schrdev"  //定义静态注册设备的名称
#define DEVICE_ANAME "achrdev"  //定义动态注册设备的名称
#define DEVICE_MINOR_NUMBER 0 	//定义次设备号的起始地址


#define DEVICE_CLASS_NAME "chrdev_class" //宏定义类名
#define DEVICE_NODE_NAME "chrdev_test" //宏定义设备节点的名字

static int major_num, minor_num; //定义主设备号和次设备号

struct class *class; //定义类
struct device *device; /* 设备 */
struct cdev cdev;//定义一个 cdev 结构体


module_param(major_num,int,S_IRUSR); //驱动模块传入普通参数 major_num
module_param(minor_num ,int,S_IRUSR);//驱动模块传入普通参数 minor_num

dev_t dev_num;

/**
* @description: 打开设备
* @param {structinode} *inode:传递给驱动的 inode
* @param {structfile} *file:设备文件,file 结构体有个叫做 private_data 的成员变量,
* 一般在 open 的时候将 private_data 指向设备结构体。
* @return: 0 成功;其他 失败
*/
int chrdev_open(struct inode *inode, struct file *file)
{
	printk("chrdev_open\n");
	return 0;
}

// 设备操作函数结构体
struct file_operations chrdev_ops = {
	.owner = THIS_MODULE,
	.open = chrdev_open};

/**
* @description: 驱动入口函数
* @param {*}无
* @return {*} 0 成功;其他 失败
*/
static int hello_init(void)
{
	int ret;//函数返回值
	if(major_num)
	{
		/*静态注册设备号*/
		printk("major_num = %d\n",major_num);//打印传入进来的主设备号
		printk("minor_num = %d\n",minor_num);//打印传入进来的次设备号

		dev_num = MKDEV(major_num,minor_num);//MKDEV 将主设备号和次设备号合并为一个设备号
		ret = register_chrdev_region(dev_num, DEVICE_NUMBER,DEVICE_SNAME);//注册设备号

		if(ret<0)
		{
			printk("register_chrdev_region error\n");
		}
		//静态注册设备号成功,则打印。
		printk("register_chrdev_region ok\n");
	}
	else
	{
		/*动态注册设备号*/
		ret = alloc_chrdev_region(&dev_num,DEVICE_MINOR_NUMBER,1, DEVICE_ANAME);
		if(ret<0)
		{
			printk("alloc_chrdev_region error\n");
		}
		//动态注册设备号成功,则打印
		printk("alloc_chrdev_region ok\n");


		major_num =MAJOR(dev_num); //将主设备号取出来
		minor_num = MINOR(dev_num);//将次设备号取出来
		printk("major_num = %d\n",major_num);//打印传入进来的主设备号
		printk("minor_num = %d\n",minor_num);//打印传入进来的次设备号
	}

	// 初始化 cdev
	cdev.owner = THIS_MODULE;
	//cdev_init 函数初始化 cdev 结构体成员变量
	cdev_init(&cdev, &chrdev_ops);
	//完成字符设备注册到内核
	cdev_add(&cdev, dev_num, DEVICE_NUMBER);
	//创建类
	class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
	// 在 class 类下创建设备
	device = device_create(class, NULL, dev_num, NULL, DEVICE_NODE_NAME);


	return 0;
}


//drivers for exit 
static void hello_exit(void)
{
	//注销设备号
	unregister_chrdev_region(MKDEV(major_num, minor_num), DEVICE_NUMBER);
	//删除设备
	cdev_del(&cdev);
	//注销设备
	device_destroy(class, dev_num);
	//删除类
	class_destroy(class);
	printk("gooodbye! \n");

}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chris");

下面就是app的代码

#include 
#include 
#include 
#include 
#include 


int main(int argc,char *argv[])
{
	int fd;
	char buf[64] = {0};
	fd = open("/dev/chrdev_test",O_RDWR); //打开设备节点
	if(fd < 0)
	{
		perror("open error \n");
		return fd;
	}
	//read(fd,buf,sizeof(buf)); //从文件中读取数据放入缓冲区中
	close(fd);
	return 0;
}

操作指令

linux端

arm-buildroot-linux-gnueabihf-gcc -o app app.c
cp app /home/book/nfs_rootfs/

从机端

驱动卸载掉,再加载新编译好的的驱动

rmmod chrdev

insmod chrdev.ko

我们输入以下命令查看/sys/class 下面是否生成类,

ls /sys/class/chrdev_class/

查看下是否生成了设备节点

ls /sys/class/

来验证生成的设备节点是否可以使用

 ./app

【Linux】【驱动】自动创建设备节点_第1张图片

你可能感兴趣的:(linux,数据结构,运维)