700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Linux 字符设备驱动结构(二)—— 自动创建设备节点

Linux 字符设备驱动结构(二)—— 自动创建设备节点

时间:2023-02-12 06:16:55

相关推荐

Linux 字符设备驱动结构(二)—— 自动创建设备节点

上一篇我们介绍到创建设备文件的方法,利用cat /proc/devices查看申请到的设备名,设备号。

第一种是使用mknod手工创建:mknod filename type major minor

第二种是自动创建设备节点:利用udev(mdev)来实现设备文件的自动创建,首先应保证支持udev(mdev),由busybox配置。

具体udev相关知识这里不详细阐述,可以移步Linux 文件系统与设备文件系统 —— udev 设备文件系统,这里主要讲使用方法。

在驱动用加入对udev 的支持主要做的就是:在驱动初始化的代码里调用class_create(...)为该设备创建一个class,再为每个设备调用device_create(...)创建对应的设备

内核中定义的struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用 device_create(…)函数来在/dev目录下创建相应的设备节点。

这样,加载模块的时候,用户空间中的udev会自动响应 device_create()函数,去/sysfs下寻找对应的类从而创建设备节点。

下面是两个函数的解析:

1、class_create(...) 函数

功能:创建一个类;

下面是具体定义:

[cpp]view plaincopy#defineclass_create(owner,name)\ ({\ staticstructlock_class_key__key;\ __class_create(owner,name,&__key);\ })

owner:THIS_MODULE

name : 名字

__class_create(owner, name, &__key)源代码如下:[cpp]view plaincopystructclass*__class_create(structmodule*owner,constchar*name, structlock_class_key*key) { structclass*cls; intretval; cls=kzalloc(sizeof(*cls),GFP_KERNEL); if(!cls){ retval=-ENOMEM; gotoerror; } cls->name=name; cls->owner=owner; cls->class_release=class_create_release; retval=__class_register(cls,key); if(retval) gotoerror; returncls; error: kfree(cls); returnERR_PTR(retval); } EXPORT_SYMBOL_GPL(__class_create);

销毁函数:void class_destroy(struct class *cls)

[cpp]view plaincopyvoidclass_destroy(structclass*cls) { if((cls==NULL)||(IS_ERR(cls))) return; class_unregister(cls); }

2、device_create(...) 函数

struct device *device_create(struct class *class, struct device *parent,

dev_t devt, void *drvdata, const char *fmt, ...)

功能:创建一个字符设备文件

参数:

struct class *class :类

struct device *parent:NULL

dev_t devt :设备号

void *drvdata :null、

const char *fmt :名字

返回:

struct device *

下面是源码解析:

[cpp]view plaincopystructdevice*device_create(structclass*class,structdevice*parent, dev_tdevt,void*drvdata,constchar*fmt,...) { va_listvargs; structdevice*dev; va_start(vargs,fmt); dev=device_create_vargs(class,parent,devt,drvdata,fmt,vargs); va_end(vargs); returndev; }

device_create_vargs(class, parent, devt, drvdata, fmt, vargs)解析如下:

[cpp]view plaincopystructdevice*device_create_vargs(structclass*class,structdevice*parent, dev_tdevt,void*drvdata,constchar*fmt, va_listargs) { returndevice_create_groups_vargs(class,parent,devt,drvdata,NULL, fmt,args); } 现在就不继续往下跟了,大家可以继续往下跟;

下面是一个实例:

hello.c

[cpp]view plaincopy#include<linux/module.h> #include<linux/fs.h> #include<linux/cdev.h> #include<linux/device.h> staticintmajor=250; staticintminor=0; staticdev_tdevno; staticstructclass*cls; staticstructdevice*test_device; staticinthello_open(structinode*inode,structfile*filep) { printk("hello_open\n"); return0; } staticstructfile_operationshello_ops= { .open=hello_open, }; staticinthello_init(void) { intret; printk("hello_init\n"); devno=MKDEV(major,minor); ret=register_chrdev(major,"hello",&hello_ops); cls=class_create(THIS_MODULE,"myclass"); if(IS_ERR(cls)) { unregister_chrdev(major,"hello"); return-EBUSY; } test_device=device_create(cls,NULL,devno,NULL,"hello");//mknod/dev/hello if(IS_ERR(test_device)) { class_destroy(cls); unregister_chrdev(major,"hello"); return-EBUSY; } return0; } staticvoidhello_exit(void) { device_destroy(cls,devno); class_destroy(cls); unregister_chrdev(major,"hello"); printk("hello_exit\n"); } MODULE_LICENSE("GPL"); module_init(hello_init); module_exit(hello_exit);

test.c

[cpp]view plaincopy#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdio.h> main() { intfd; fd=open("/dev/hello",O_RDWR); if(fd<0) { perror("openfail\n"); return; } close(fd); }

makefile

[cpp]view plaincopyifneq($(KERNELRELEASE),) obj-m:=hello.o $(info"2nd") else KDIR:=/lib/modules/$(shelluname-r)/build PWD:=$(shellpwd) all: $(info"1st") make-C$(KDIR)M=$(PWD)modules clean: rm-f*.ko*.o*.symvers*.mod.c*.mod.o*.order endif

下面可以看几个class几个名字的对应关系:

上一篇我们介绍到创建设备文件的方法,利用cat /proc/devices查看申请到的设备名,设备号。

第一种是使用mknod手工创建:mknod filename type major minor

第二种是自动创建设备节点:利用udev(mdev)来实现设备文件的自动创建,首先应保证支持udev(mdev),由busybox配置。

具体udev相关知识这里不详细阐述,可以移步Linux 文件系统与设备文件系统 —— udev 设备文件系统,这里主要讲使用方法。

在驱动用加入对udev 的支持主要做的就是:在驱动初始化的代码里调用class_create(...)为该设备创建一个class,再为每个设备调用device_create(...)创建对应的设备

内核中定义的struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用 device_create(…)函数来在/dev目录下创建相应的设备节点。

这样,加载模块的时候,用户空间中的udev会自动响应 device_create()函数,去/sysfs下寻找对应的类从而创建设备节点。

下面是两个函数的解析:

1、class_create(...) 函数

功能:创建一个类;

下面是具体定义:

[cpp]view plaincopy#defineclass_create(owner,name)\ ({\ staticstructlock_class_key__key;\ __class_create(owner,name,&__key);\ })

owner:THIS_MODULE

name : 名字

__class_create(owner, name, &__key)源代码如下:[cpp]view plaincopystructclass*__class_create(structmodule*owner,constchar*name, structlock_class_key*key) { structclass*cls; intretval; cls=kzalloc(sizeof(*cls),GFP_KERNEL); if(!cls){ retval=-ENOMEM; gotoerror; } cls->name=name; cls->owner=owner; cls->class_release=class_create_release; retval=__class_register(cls,key); if(retval) gotoerror; returncls; error: kfree(cls); returnERR_PTR(retval); } EXPORT_SYMBOL_GPL(__class_create);

销毁函数:void class_destroy(struct class *cls)

[cpp]view plaincopyvoidclass_destroy(structclass*cls) { if((cls==NULL)||(IS_ERR(cls))) return; class_unregister(cls); }

2、device_create(...) 函数

struct device *device_create(struct class *class, struct device *parent,

dev_t devt, void *drvdata, const char *fmt, ...)

功能:创建一个字符设备文件

参数:

struct class *class :类

struct device *parent:NULL

dev_t devt :设备号

void *drvdata :null、

const char *fmt :名字

返回:

struct device *

下面是源码解析:

[cpp]view plaincopystructdevice*device_create(structclass*class,structdevice*parent, dev_tdevt,void*drvdata,constchar*fmt,...) { va_listvargs; structdevice*dev; va_start(vargs,fmt); dev=device_create_vargs(class,parent,devt,drvdata,fmt,vargs); va_end(vargs); returndev; }

device_create_vargs(class, parent, devt, drvdata, fmt, vargs)解析如下:

[cpp]view plaincopystructdevice*device_create_vargs(structclass*class,structdevice*parent, dev_tdevt,void*drvdata,constchar*fmt, va_listargs) { returndevice_create_groups_vargs(class,parent,devt,drvdata,NULL, fmt,args); } 现在就不继续往下跟了,大家可以继续往下跟;

下面是一个实例:

hello.c

[cpp]view plaincopy#include<linux/module.h> #include<linux/fs.h> #include<linux/cdev.h> #include<linux/device.h> staticintmajor=250; staticintminor=0; staticdev_tdevno; staticstructclass*cls; staticstructdevice*test_device; staticinthello_open(structinode*inode,structfile*filep) { printk("hello_open\n"); return0; } staticstructfile_operationshello_ops= { .open=hello_open, }; staticinthello_init(void) { intret; printk("hello_init\n"); devno=MKDEV(major,minor); ret=register_chrdev(major,"hello",&hello_ops); cls=class_create(THIS_MODULE,"myclass"); if(IS_ERR(cls)) { unregister_chrdev(major,"hello"); return-EBUSY; } test_device=device_create(cls,NULL,devno,NULL,"hello");//mknod/dev/hello if(IS_ERR(test_device)) { class_destroy(cls); unregister_chrdev(major,"hello"); return-EBUSY; } return0; } staticvoidhello_exit(void) { device_destroy(cls,devno); class_destroy(cls); unregister_chrdev(major,"hello"); printk("hello_exit\n"); } MODULE_LICENSE("GPL"); module_init(hello_init); module_exit(hello_exit);

test.c

[cpp]view plaincopy#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdio.h> main() { intfd; fd=open("/dev/hello",O_RDWR); if(fd<0) { perror("openfail\n"); return; } close(fd); }

makefile

[cpp]view plaincopyifneq($(KERNELRELEASE),) obj-m:=hello.o $(info"2nd") else KDIR:=/lib/modules/$(shelluname-r)/build PWD:=$(shellpwd) all: $(info"1st") make-C$(KDIR)M=$(PWD)modules clean: rm-f*.ko*.o*.symvers*.mod.c*.mod.o*.order endif

下面可以看几个class几个名字的对应关系:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。