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);
                }
}
===============================================


II>注意,在2.6较早的内核版本中,device_create(…)函数名称不同,是class_device_create(…),且这两者的返回值的结构体的类型也发生了变化。注意根据自己现有的内核进行相应的修改。与此同时,class_device_unregister()也不存在,取而代之的是device_destroy()。且其里边的参数也发生了些许变化。


0 0
原创粉丝点击