`
sony-soft
  • 浏览: 1019253 次
文章分类
社区版块
存档分类
最新评论

在驱动模块初始化函数中实现设备节点的自动创建

 
阅读更多

在驱动模块初始化函数中实现设备节点的自动创建

我们在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev

内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

注意,在2.6较早的内核版本中,device_create(…)函数名称不同,是class_device_create(…),所以在新的内核中编译以前的模块程序有时会报错,就是因为函数名称不同,而且里面的参数设置也有一些变化。

struct classdevice_create(…) 以及device_create(…)都定义在/include/linux/device.h中,使用的时候一定要包含这个头文件,否则编译器会报错。

2.6.26.6内核版本中,struct class定义在头文件include/linux/device.h中:

/*
* device classes
*/
struct class {
const char *name;
struct module *owner;

nbsp;struct kset subsys;
struct list_head devices;
struct list_head interfaces;
struct kset class_dirs;
struct semaphore sem; /* locks children, devices, interfaces */
struct class_attribute *class_attrs;
struct device_attribute *dev_attrs;

int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);

void (*class_release)(struct class *class);
void (*dev_release)(struct device *dev);

int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);

};

class_create(…)/drivers/base/class.c中实现:
/**
* class_create - create a struct class structure
* @owner: pointer to the module that is to "own" this struct class
* @name: pointer to a string for the name of this class.
*
* This is used to create a struct class pointer that can then be used
* in calls to device_create().
*
* Note, the pointer created here is to be destroyed when finished by
* making a call to class_destroy().
*/
struct class *class_create(struct module *owner, const char *name)
{
struct class *cls;
int retval;
cls = kzalloc(sizeof(*cls), GFP_KERNEL);
if (!cls) {
retval = -ENOMEM;
goto error;
}

cls->name = name;
cls->owner = owner;
cls->class_release = class_create_release;

retval = class_register(cls);
if (retval)
goto error;

return cls;

error:
kfree(cls);
return ERR_PTR(retval);
}
第一个参数指定类的所有者是哪个模块,第二个参数指定类名。
class.c中,还定义了class_destroy(…)函数,用于在模块卸载时删除类。

device_create(…)函数在/drivers/base/core.c中实现:
/**
* device_create - creates a device and registers it with sysfs
* @class: pointer to the struct class that this device should be registered to
* @parent: pointer to the parent struct device of this new device, if any
* @devt: the dev_t for the char device to be added
* @fmt: string for the device's name
*
* This can be used by char device classes. A struct device
* will be created in sysfs, registered to the specified class.
*
* A "dev" file will be created, showing the dev_t for the device, if
* the dev_t is not 0,0.
* If a pointer to a parent struct device is passed in, the newly created
* struct device will be a child of that device in sysfs.
* The pointer to the struct device will be returned from the call.
* Any further sysfs files that might be required can be created using this
* pointer.
*
* Note: the struct class passed to this must have previously
* been created with a call to class_create().
*/
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, const char *fmt, ...)
{
va_list vargs;
struct device *dev;

va_start(vargs, fmt);
dev = device_create_vargs(class, parent, devt, NULL, fmt, vargs);
va_end(vargs);
return dev;
}

第一个参数指定所要创建的设备所从属的类,第二个参数是这个设备的父设备,如果没有就指定为NULL,第三个参数是设备号,第四个参数是设备名称,第五个参数是从设备号。

下面以一个简单字符设备驱动来展示如何使用这几个函数
i nclude <linux/module.h>
i nclude <linux/kernel.h>
i nclude <linux/init.h>
i nclude <linux/fs.h>
i nclude <linux/cdev.h>
i nclude <linux/device.h>

MODULE_LICENSE ("GPL");

int hello_major = 555;
int hello_minor = 0;
int number_of_devices = 1;

struct cdev cdev;
dev_t dev = 0;

struct file_operations hello_fops = {
.owner = THIS_MODULE
};

static void char_reg_setup_cdev (void)
{
int error, devno = MKDEV (hello_major, hello_minor);
cdev_init (&cdev, &hello_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &hello_fops;
error = cdev_add (&cdev, devno , 1);
if (error)
printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);

}

struct class *my_class;

static int __init hello_2_init (void)
{
int result;
dev = MKDEV (hello_major, hello_minor);
result = register_chrdev_region (dev, number_of_devices, "hello");
if (result<0) {
printk (KERN_WARNING "hello: can't get major number %d/n", hello_major);
return result;
}

char_reg_setup_cdev ();

/* create your own class under /sysfs */
my_class = class_create(THIS_MODULE, "my_class");
if(IS_ERR(my_class))
{
printk("Err: failed in creating class./n");
return -1;
}

/* register your own device in sysfs, and this will cause udev to create corresponding device node */
device_create( my_class, NULL, MKDEV(hello_major, 0), "hello" "%d", 0 );

printk (KERN_INFO "Registered character driver/n");
return 0;
}

static void __exit hello_2_exit (void)
{
dev_t devno = MKDEV (hello_major, hello_minor);

cdev_del (&cdev);

device_destroy(my_class, MKDEV(adc_major, 0)); //delete device node under /dev
class_destroy(my_class); //delete class created by us

unregister_chrdev_region (devno, number_of_devices);

printk (KERN_INFO "char driver cleaned up/n");
}

module_init (hello_2_init);
module_exit (hello_2_exit);

这样,模块加载后,就能在/dev目录下找到hello0这个设备节点了

分享到:
评论

相关推荐

    在驱动模块初始化函数中实现设备节点的自动创建.pdf

    。。。

    在驱动模块初始化函数中实现设备节点的自动创建.docx

    。。。

    嵌入式系统/ARM技术中的在驱动模块初始化函数中实现设备节点的自动创建

     我们在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该...

    sysfs文件接口修改内核模块变量值-fasync源码

    这个例了同时也展示了sysfs文件系统在驱动程序中的用法,以及通过Linux设各模型来创建设备节点及其他一些特性(这个看起来很简单的内核模块其实体现了设备驱动程序中一些比较重要且典型的特征)。 首先是设备驱动程序...

    Python Cookbook

    6.18 用_ _init_ _参数自动初始化实例变量 266 6.19 调用超类的_ _init_ _方法 267 6.20 精确和安全地使用协作的超类调用 270 第7章 持久化和数据库 273 引言 273 7.1 使用marshal模块序列化数据 275 7.2 ...

    Linux内核源代码情景分析 (上下册 高清非扫描 )

    3.2 中断向量表IDT的初始化 3.3 中断请求队列的初始化 3.4 中断的响应和服务 3.5 软中断与Bottom Half 3.6 页面异常的进入和返回 3.7 时钟中断 3.8 系统调用 3.9 系统调用号与跳转表 第4章 进程与进程调度 4.1 进程...

    linux 内核源代码分析

    3. 2 中断向量表IDT的初始化 3. 3 中断请求队列的初始化 3. 4 中断的响应和服务 3. 5 软中断与Bottom Half 3.6 页面异常的进入和返回 3. 7 时钟中断 3. 8 系统调用 3. 9 系统调用号与跳转表 第4章 进程与...

    深入分析Linux内核源码

    13.5 main.c中的初始化 13.6 建立init进程 13.6.1 init进程的建立 13.6.2 启动所需的Shell脚本文件 附录: 1 Linux 2.4内核API 2.1 驱动程序的基本函数 2.2 双向循环链表的操作 2.3 基本C库函数 2.4 ...

    linux内核源代码情景分析

    3.2 中断向量表IDT的初始化 3.3 中断请求队列的初始化 3.4 中断的响应和服务 3.5 软中断与Bottom Half 3.6 页面异常的进入和返回 3.7 时钟中断 3.8 系统调用 3.9 系统调用号与跳转表 第4章 进程与进程调度 ...

    Linux内核:从底层向上分析驱动程序层+链路层

     我们首先有第一篇博文中知道在网络栈初始化的时候在net/socket.c中的函数sock_init()函数中当proto_init()完成后会执行dev_init()来进行网络设备模块的初始化。  首先说明一下,在drivers/net/space.c中定义了...

    tty_driver 结构的细节

    ty_driver 结构用来注册一个 tty 驱动到 tty 核心.... 在 alloc_tty_driver 函数中被初始化. const char *driver_name; 驱动的名子, 用在 /proc/tty 和 sysfs. const char *name; 驱动的节点名.

    Linux内核情景分析(非扫描版)

    3. 2 中断向量表IDT的初始化 3. 3 中断请求队列的初始化 3. 4 中断的响应和服务 3. 5 软中断与Bottom Half 3.6 页面异常的进入和返回 3. 7 时钟中断 3. 8 系统调用 3. 9 系统调用号与跳转表 第4章 进程与进程调度 ...

    Linux内核情景分析

    3. 2 中断向量表IDT的初始化 3. 3 中断请求队列的初始化 3. 4 中断的响应和服务 3. 5 软中断与Bottom Half 3.6 页面异常的进入和返回 3. 7 时钟中断 3. 8 系统调用 3. 9 系统调用号与跳转表 第4章 进程与进程调度 ...

    清华大学Linux操作系统原理与应用

    1.1.3 从操作系统在整个计算机系统中所处位置 2 1.1.4 从操作系统设计者的角度 3 1.2 操作系统的发展 4 1.2.1 操作系统的演变 4 1.2.2 硬件的发展轨迹 5 1.2.3 软件的轨迹 6 1.2.4 单内核与微内核操作系统 7 1.3 ...

    UNIX 高级教程系统技术内幕

    15.4.1 内存对象初始化 15.4.2 内核与pager 间的接口 15.4.3 内核与pager 交互 15.5 外部pager 和内部pager 15.5.1 一个网络共享内存服务器 15.6 页面替换 15.7 分析 15.8 4.4BSD 的内存管理 15.9 快表(TLB)一致性 ...

    Visual Basic 2010入门经典.part1.rar

    11.8.2 初始化和使用选项变量 199 11.9 总结 201 11.10 问与答 202 11.11 作业 202 11.11.1 测验 202 11.11.2 答案 203 11.11.3 练习 203 第十二章 执行算术运算、字符串操作和日期/时间调整 204 12.1 使用...

    Visual Basic 2010入门经典.part2.rar

    11.8.2 初始化和使用选项变量 199 11.9 总结 201 11.10 问与答 202 11.11 作业 202 11.11.1 测验 202 11.11.2 答案 203 11.11.3 练习 203 第十二章 执行算术运算、字符串操作和日期/时间调整 204 12.1 使用...

    Linux2.6内核标准教程(共计8-- 第1个)

    6.5.1 初始化内核定时器节点 273 6.5.2 激活内核定时器节点 273 6.5.3 内核定时器的处理过程 277 6.6 微秒级延迟 280 6.6.1 微妙级延迟的访问接口 281 6.6.2 微妙级延迟的实现方法 281 第7章 系统调用...

Global site tag (gtag.js) - Google Analytics