基于linux-2.6.35的class_create(),device_create解析
從linux內核2.6的某個版本之后,devfs不復存在,udev成為devfs的替代。提醒一點,udev是應用層的,不要試圖在內核的配置選項里找到它;加入對udev的支持很簡單,以作者所寫的一個字符設備驅動為例,在驅動初始化的代碼里調用class_create為該設備創建一個class,再為每個設備調用device_create創建對應的設備。大致用法如下:
struct class *myclass ;
????????class_create(THIS_MODULE, “my_device_driver”);
????????device_create(myclass, NULL, MKDEV(major_num, minor_num), NULL, “my_device”);
這樣的module被加載時,udev daemon就會自動在/dev下創建my_device設備文件。
我們在剛開始寫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 class和device_create(…) 以及device_create(…)都定義在/include/linux/device.h中,使用的時候一定要包含這個頭文件,否則編譯器會報錯。
在2.6.35內核版本中,struct class定義在頭文件include/linux/device.h中
????????/*
????????* device classes
????????*/
????????struct class {
????????????????const char *name;
????????????????struct module *owner;
????????????????struct class_attribute *class_attrs;
????????????????struct device_attribute *dev_attrs;
????????????????struct kobject *dev_kobj;
????????????????int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
????????????????char *(*devnode)(struct device *dev, mode_t *mode);
????????????????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);
????????????????const struct kobj_ns_type_operations *ns_type;
????????????????const void *(*namespace)(struct device *dev);
????????????????const struct dev_pm_ops *pm;
????????????????struct class_private *p;
????????????????};
????????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 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);
????????}
第一個參數指定類的所有者是哪個模塊,第二個參數指定類名。
在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 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;
????????}
第一個參數指定所要創建的設備所從屬的類,第二個參數是這個設備的父設備,如果沒有就指定為NULL,第三個參數是設備號,第四個參數是設備名稱,第五個參數是從設備號。
下面以一個簡單字符設備驅動來展示如何使用這幾個函數:
????????/*?
????????* Copyright (C) 2005 Farsight
????????*
????????* This program is free software; you can redistribute it and/or modify
????????* it under the terms of the GNU General Public License as published by
????????* the Free Software Foundation; either version 2 of the License, or
????????* (at your option) any later version.
????????* This program is distributed in the hope that it will be useful,
????????* but WITHOUT ANY WARRANTY; without even the implied warranty of
????????* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
????????* GNU General Public License for more details.
????????* You should have received a copy of the GNU General Public License
????????* along with this program; if not, write to the Free Software
????????* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
????????*
????????*/
????????#include <linux/module.h>
????????#include <linux/kernel.h>
????????#include <linux/init.h>
????????#include <linux/fs.h>
????????#include <linux/cdev.h>
????????#include <asm/uaccess.h>
????????#include <linux/device.h>
????????MODULE_LICENSE ("GPL");
????????int hello_major = 250;
????????int hello_minor = 0;
????????int number_of_devices = 1;
????????struct cdev cdev;
????????dev_t dev = 0;
????????struct file_operations hello_fops = {
????????????????.owner = THIS_MODULE,
???????? };
????????struct class *my_class;
????????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);
????????????????/* creating your own class */
???????? ????????my_class =class_create(THIS_MODULE, "farsight_class");
????????????????if(IS_ERR(my_class)) {
????????????????????????printk("Err: failed in creating class.\n");
????????????????????????return ;
????????????????}
????????????????/* register your own device in sysfs, and this will cause udevd to create corresponding device node */
????????????????device_create(my_class,NULL, devno, NULL,"hello");
????????????????}
????????static int __init hello_2_init (void)
????????{
????????????????int result;
????????????????dev = MKDEV (hello_major, hello_minor);
????????????????result = register_chrdev_region (dev, number_of_devices, "test");
????????????????if (result<0) {
????????????????????????printk (KERN_WARNING "hello: can't get major number %d\n", hello_major);
????????????????????????return result;
????????????????}
????????????????char_reg_setup_cdev ();
????????????????printk (KERN_INFO "char device registered\n");
????????????????return 0;
????????}
????????static void __exit hello_2_exit (void)
????????{
????????????????dev_t devno = MKDEV (hello_major, hello_minor);
????????????????cdev_del (&cdev);
????????????????unregister_chrdev_region (devno, number_of_devices);
????????????????device_destroy(my_class, devno);
????????????????class_destroy(my_class);
????????}
????????module_init (hello_2_init);
????????module_exit (hello_2_exit);
當加載模塊的時候,會在/dev/hello這個設備文件
總結
以上是生活随笔為你收集整理的基于linux-2.6.35的class_create(),device_create解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux之GPIO的使用
- 下一篇: 关于real210开发板linux系统可