Linux设备驱动程序之二 ---- 完善上一节的驱动程序
来源:互联网 发布:168套优化重组2017答案 编辑:程序博客网 时间:2024/04/29 03:47
我们知道,在上一节驱动中,我们的主设备号是手动指定为111的,还有就是设备节点是手动mknod的。这在某种程度上,不利于我们驱动的移植性。接下来,我们对其进行进一步优化。
I.首先是让其实现自动分配设备号,其驱动程序如下:
#include
#include
#include
#include
int major;
static int led_drv_open(struct inode *inode, struct file *file)
{
printk("this is a led_drv_open\n");
return 0;
}
static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
printk("this is a led_drv_write\n");
return 0;
}
static struct file_operations led_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_drv_open,
.write = led_drv_write,
};
static int led_drv_init(void)
{
major = register_chrdev(0, "led_drv", &led_drv_fops); // 注册, 告诉内核
return 0;
}
static void led_drv_exit(void)
{
unregister_chrdev(major, "led_drv"); // 卸载
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");
注:在register_chrdev()函数中,其第一项参数为0,表示其主设备号为自动分配。
II.上述步骤完成后,我们发现,我们还是得根据其自动分配的主设备号,手动创建其设备节点,这个还是很不利于我们驱动的开发。
于是,我们打算再对其进行进一步优化。其驱动程序的代码如下:
#include
#include
#include
#include
#include
#include
int major;
dev_t dev_num;
static struct class *led_drv_class;
static struct device *led_drv_dev;
static int led_drv_open(struct inode *inode, struct file *file)
{
printk("this is a led_drv_open\n");
return 0;
}
static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
printk("this is a led_drv_write\n");
return 0;
}
static struct file_operations led_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_drv_open,
.write = led_drv_write,
};
static int led_drv_init(void)
{
major = register_chrdev(0, "led_drv", &led_drv_fops); // 注册, 告诉内核
dev_num = MKDEV(major,0);
led_drv_class = class_create(THIS_MODULE, "led_drv");
if (IS_ERR(led_drv_class))
return PTR_ERR(led_drv_class);
led_drv_dev = device_create(led_drv_class, NULL, dev_num, NULL, "led_drv");
if (unlikely(IS_ERR(led_drv_dev)))
return PTR_ERR(led_drv_dev);
return 0;
}
static void led_drv_exit(void)
{
unregister_chrdev(major, "led_drv"); // 卸载
device_destroy(led_drv_class,dev_num);
class_destroy(led_drv_class);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");
注:
I>关于class_create,device_create,class_destroy,device_destroy几个函数的用法如下:
===============================================
1>class_create:
/* This is a #define to keep the compiler from merging different
* instances of the __key variable */
#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name, &__key); \
})
/**
* 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.
* @key: the lock_class_key for this class; used by mutex lock debugging
*
* 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 lock_class_key *key)
{
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, key);
if (retval)
goto error;
return cls;
error:
kfree(cls);
return ERR_PTR(retval);
}
===============================================
===============================================
2>device_create
/**
* 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
* @drvdata: the data to be added to the device for callbacks
* @fmt: string for the device's name
*
* This function 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 function must have previously
* been created with a call to class_create().
*/
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
{
va_list vargs;
struct device *dev;
va_start(vargs, fmt);
dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
va_end(vargs);
return dev;
}
===============================================
===============================================
3>class_destroy
/**
* class_destroy - destroys a struct class structure
* @cls: pointer to the struct class that is to be destroyed
*
* Note, the pointer to be destroyed must have been created with a call
* to class_create().
*/
void class_destroy(struct class *cls)
{
if ((cls == NULL) || (IS_ERR(cls)))
return;
class_unregister(cls);
}
===============================================
===============================================
4>device_destroy
/**
* device_destroy - removes a device that was created with device_create()
* @class: pointer to the struct class that this device was registered with
* @devt: the dev_t of the device that was previously registered
*
* This call unregisters and cleans up a device that was created with a
* call to device_create().
*/
void device_destroy(struct class *class, dev_t devt)
{
struct device *dev;
dev = class_find_device(class, NULL, &devt, __match_devt);
if (dev) {
put_device(dev);
device_unregister(dev);
}
}
===============================================
I.首先是让其实现自动分配设备号,其驱动程序如下:
#include
#include
#include
#include
int major;
static int led_drv_open(struct inode *inode, struct file *file)
{
printk("this is a led_drv_open\n");
return 0;
}
static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
printk("this is a led_drv_write\n");
return 0;
}
static struct file_operations led_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_drv_open,
.write = led_drv_write,
};
static int led_drv_init(void)
{
major = register_chrdev(0, "led_drv", &led_drv_fops); // 注册, 告诉内核
return 0;
}
static void led_drv_exit(void)
{
unregister_chrdev(major, "led_drv"); // 卸载
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");
注:在register_chrdev()函数中,其第一项参数为0,表示其主设备号为自动分配。
II.上述步骤完成后,我们发现,我们还是得根据其自动分配的主设备号,手动创建其设备节点,这个还是很不利于我们驱动的开发。
于是,我们打算再对其进行进一步优化。其驱动程序的代码如下:
#include
#include
#include
#include
#include
#include
int major;
dev_t dev_num;
static struct class *led_drv_class;
static struct device *led_drv_dev;
static int led_drv_open(struct inode *inode, struct file *file)
{
printk("this is a led_drv_open\n");
return 0;
}
static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
printk("this is a led_drv_write\n");
return 0;
}
static struct file_operations led_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_drv_open,
.write = led_drv_write,
};
static int led_drv_init(void)
{
major = register_chrdev(0, "led_drv", &led_drv_fops); // 注册, 告诉内核
dev_num = MKDEV(major,0);
led_drv_class = class_create(THIS_MODULE, "led_drv");
if (IS_ERR(led_drv_class))
return PTR_ERR(led_drv_class);
led_drv_dev = device_create(led_drv_class, NULL, dev_num, NULL, "led_drv");
if (unlikely(IS_ERR(led_drv_dev)))
return PTR_ERR(led_drv_dev);
return 0;
}
static void led_drv_exit(void)
{
unregister_chrdev(major, "led_drv"); // 卸载
device_destroy(led_drv_class,dev_num);
class_destroy(led_drv_class);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");
注:
I>关于class_create,device_create,class_destroy,device_destroy几个函数的用法如下:
===============================================
1>class_create:
/* This is a #define to keep the compiler from merging different
* instances of the __key variable */
#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name, &__key); \
})
/**
* 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.
* @key: the lock_class_key for this class; used by mutex lock debugging
*
* 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 lock_class_key *key)
{
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, key);
if (retval)
goto error;
return cls;
error:
kfree(cls);
return ERR_PTR(retval);
}
===============================================
===============================================
2>device_create
/**
* 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
* @drvdata: the data to be added to the device for callbacks
* @fmt: string for the device's name
*
* This function 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 function must have previously
* been created with a call to class_create().
*/
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
{
va_list vargs;
struct device *dev;
va_start(vargs, fmt);
dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
va_end(vargs);
return dev;
}
===============================================
===============================================
3>class_destroy
/**
* class_destroy - destroys a struct class structure
* @cls: pointer to the struct class that is to be destroyed
*
* Note, the pointer to be destroyed must have been created with a call
* to class_create().
*/
void class_destroy(struct class *cls)
{
if ((cls == NULL) || (IS_ERR(cls)))
return;
class_unregister(cls);
}
===============================================
===============================================
4>device_destroy
/**
* device_destroy - removes a device that was created with device_create()
* @class: pointer to the struct class that this device was registered with
* @devt: the dev_t of the device that was previously registered
*
* This call unregisters and cleans up a device that was created with a
* call to device_create().
*/
void device_destroy(struct class *class, dev_t devt)
{
struct device *dev;
dev = class_find_device(class, NULL, &devt, __match_devt);
if (dev) {
put_device(dev);
device_unregister(dev);
}
}
===============================================
II>注意,在2.6较早的内核版本中,device_create(…)函数名称不同,是class_device_create(…),且这两者的返回值的结构体的类型也发生了变化。注意根据自己现有的内核进行相应的修改。与此同时,class_device_unregister()也不存在,取而代之的是device_destroy()。且其里边的参数也发生了些许变化。
0 0
- Linux设备驱动程序之二 ---- 完善上一节的驱动程序
- Linux驱动程序设计之二---Linux字符驱动程序(上)
- Linux驱动程序设计之二---Linux字符驱动程序(上)
- Linux设备驱动程序之三 ---- LED驱动程序的实现
- Linux设备驱动程序(二)
- 字符设备驱动程序之二
- Linux设备驱动程序学习之设备模型二
- Linux设备驱动程序之读书笔记
- Linux设备驱动程序之读书笔记
- 嵌入式Linux之设备驱动程序
- linux之块设备驱动程序
- Linux设备驱动程序之中断与时钟(二)
- Linux设备驱动程序架构分析之MMC/SD(二)
- Linux设备驱动程序(第三版)学习之字符驱动(二)
- linux设备驱动程序之并发和竞态(二)
- Linux设备驱动程序第三版之块设备驱动程序
- LINUX下的设备驱动程序
- Linux设备驱动程序的基本知识
- java中接口的定义与实现 http://blog.csdn.net/yjkwf/article/details/7238847
- Linux设备驱动之一 ---- 驱动的框架及其操作流程
- Linux设备驱动前的工作准备 ---- 内核的配置及Makefile编写
- patch命令的使用
- 任务中将某个提示语修改或去除的简便方法
- Linux设备驱动程序之二 ---- 完善上一节的驱动程序
- bloom filter 关键点 记录
- Linux设备驱动程序之三 ---- LED驱动程序的实现
- spark机器学习中安装ipython步骤
- 跟踪代码的方法
- linux命令:dmesg
- Linux常用命令
- 作为一个新人,怎样学习嵌入式Linux -----韦东山老师
- 网站发布