Class create, device create, device create file【转】

来自:http://www.hovercool.com/en/Class_create,_device_create,_device_create_file

开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点(包括ldd3中不少例子也是这样),实际上现在Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点。

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

此外,利用device_create_file函数可以在/sys/class/下创建对应的属性文件,从而通过对该文件的读写实现特定的数据操作。

一、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().
 *
 * Returns &struct class pointer on success, or ERR_PTR() on error.
 *
 * 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)

关键的一句是:

 * This is used to create a struct class pointer that can then be used
 * in calls to device_create().
 -->这个函数用来创建一个struct class的结构体指针,这个指针可用作device_create()函数的参数。

也就是说,这个函数主要是在调用device_create()前使用,创建一个struct class类型的变量,并返回其指针。

二、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.
 *
 * Returns &struct device pointer on success, or ERR_PTR() on error.
 *
 * 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, ...)

首先解释一下"sysfs":sysfs是linux2.6所提供的一种虚拟档案系统;在设备模型中,sysfs文件系统用来表示设备的结构,将设备的层次结构形象的反应到用户空间中,从而可以通过修改sysfs中的文件属性来修改设备的属性值;sysfs被挂载到根目录下的"/sys"文件夹下。

三、device_create_file

官方说明:

/**
 * device_create_file - create sysfs attribute file for device.
 * @dev: device.
 * @attr: device attribute descriptor.
 */
int device_create_file(struct device *dev,
		       const struct device_attribute *attr)

使用这个函数时要引用 device_create所返回的device*指针,作用是在/sys/class/下创建一个属性文件,从而通过对这个属性文件进行读写就能完成对应的数据操作。

如:

a.在驱动程序中使用 device_create_file创建属性文件

static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);  

/*读取寄存器val的值到缓冲区buf中,内部使用*/
static ssize_t __hello_get_val(struct xxx_dev* dev, char* buf) {
    int val = 0;          

    /*同步访问*/
    if(down_interruptible(&(dev->sem))) {
        return -ERESTARTSYS;
    }          

    val = dev->val;
    up(&(dev->sem));          

    return snprintf(buf, PAGE_SIZE, "%d/n", val);
}  

/*把缓冲区buf的值写到设备寄存器val中去,内部使用*/
static ssize_t __hello_set_val(struct xxx_dev* dev, const char* buf, size_t count) {
    int val = 0;          

    /*将字符串转换成数字*/
    val = simple_strtol(buf, NULL, 10);          

    /*同步访问*/
    if(down_interruptible(&(dev->sem))) {
        return -ERESTARTSYS;
    }          

    dev->val = val;
    up(&(dev->sem));  

    return count;
}  

/*读取设备属性val*/
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {
    struct xxx_dev* hdev = (struct xxx_dev*)dev_get_drvdata(dev);          

    return __hello_get_val(hdev, buf);
}  

/*写设备属性val*/
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {
    struct xxx_dev* hdev = (struct xxx_dev*)dev_get_drvdata(dev);    

    return __hello_set_val(hdev, buf, count);
} 

/*模块加载方法*/
static int __init xxx_init(void){
    ... 

    /*在/sys/class/xxx/xxx目录下创建属性文件val*/
    err = device_create_file(temp, &dev_attr_val);
    if(err < 0) {
        printk(KERN_ALERT"Failed to create attribute val.");
        goto destroy_device;
    }

    ...
}

b.在用户空间读取属性

...
read(dev->fd, val, sizeof(*val));
...
write(dev->fd, &val, sizeof(val));
...

四、使用示例

    /*在/sys/class/目录下创建设备类别目录xxx*/
    g_vircdev_class = class_create(THIS_MODULE, VIRCDEV_CLASS_NAME);
    if(IS_ERR(g_vircdev_class)) {
        err = PTR_ERR(g_vircdev_class);
        printk(KERN_ALERT "Failed to create class.\n");
        goto CLASS_CREATE_ERR;
    }

    /*在/dev/目录和/sys/class/xxx目录下分别创建设备文件xxx*/
    dev = device_create(g_vircdev_class, NULL, devt, NULL, VIRCDEV_DEVICE_NAME);
    if(IS_ERR(dev)) {
        err = PTR_ERR(dev);
        printk(KERN_ALERT "Failed to create device.\n");
        goto DEVICE_CREATE_ERR;
    }

    /*在/sys/class/xxx/xxx目录下创建属性文件val*/
    err = device_create_file(dev, attr);
    if(err < 0) {
        printk(KERN_ALERT"Failed to create attribute file.");
        goto DEVICE_CREATE_FILE_ERR;
    }

参考资料:

sysfs:

http://blog.csdn.net/dianhuiren/article/details/6928500

http://tech.ccidnet.com/art/302/20080304/1379211_1.html

http://blog.csdn.net/chchchdx123/article/details/6248486

时间: 2024-10-06 11:11:07

Class create, device create, device create file【转】的相关文章

No space left on device: Couldn’t create accept lock

执行 apachectl start 时,error_log报错如下: [warn] pid file /usr/local/zend/apache2/logs/httpd.pid overwritten -- Unclean shutdown of previous Apache run? [emerg] (28)No space left on device: Couldn't create accept lock (/usr/local/zend/apache2/logs/accept.l

No space left on device: Couldn&#39;t create accept lock

原因: (1) 确认是否是硬盘空间不足:结果发现不是空间的问题: (2) 网上查看了下,发现是ipc不足.可以使用ipcs -s(|grep apache的group) 处理: (1) 可以使用$ ipcrm -s <semid>清理指定 semaphore (2) 也可以使用下面命令,清理所有的semaphore, 注:替换nobody为apache对应的用户名 for semid in `ipcs -s | grep nobody | cut -f2 -d" "`; d

解决方案:android monkeyrunner:Timeout while trying to create chimp mananger(device = MonkeyRunner.waitForConnection()一直报错的问题)

monkeyrunner在执行device = MonkeyRunner.waitForConnection()一直报错的问题 (或者[main] [com.android.chimpchat.adb.AdbChimpDevice] Timeout while trying to create chimp mananger) 看到这篇文章的童鞋们.是不是自己很郁闷呢.看了其他人一直都能好好的运行(就算官方的demo都是那样写.就是自己机子不行) 1.叫你重装JDK或者重新配环境的人.就千万不要相

Apache: No space left on device: Couldn’t create rewrite_map(XXXX)

启动apache的时候 有时候会遇到这样的错误:No space left on device: Couldn’t create rewrite_map(XXXX) 第一眼看以为是磁盘没有空间了,其实不然: 没有空间,不存在的.... 细究发现其实是:IPC的资源占用问题,先用”ipcs”命令查一下当前用于已经使用了的信号量集合:apache已经分配了这么多 可以使用如下的指令,删除对应服务的信号量结 sem_list=$(ipcs -s | grep apache | awk '{print

[转]Git – fatal: Unable to create &#39;XXX/.git/index.lock’: File exists.的解决办法

参考资料: http://sheshui.me/articles/git-quickly-tutorial-20120517 http://stackoverflow.com/questions/9282632/git-index-lock-file-exists-when-i-try-to-commit-but-cannot-delete-the-file 我的说明: 我操作的是ubuntu环境.window远程 1 若在window下远程打开操作窗口(不是console),进入.git目录删

git 提交出现这个错误fatal: Unable to create &#39;project_path/.git/index.lock&#39;: File exists.

git 提交出现这个错误fatal: Unable to create 'project_path/.git/index.lock': File exists. exists 解决办法 rm -f ./.git/index.lock on Windows del .git\index.lock git 提交出现这个错误fatal: Unable to create 'project_path/.git/index.lock': File exists.

[Hive - LanguageManual] Create/Drop/Alter Database Create/Drop/Truncate Table

Hive Data Definition Language Hive Data Definition Language Overview Create/Drop/Alter Database Create/Drop/Truncate Table Alter Table/Partition/Column Create/Drop/Alter View Create/Drop/Alter Index Create/Drop Function Create/Drop/Grant/Revoke Roles

[Hive - LanguageManual] Create/Drop/Alter View Create/Drop/Alter Index Create/Drop Function

Create/Drop/Alter View Create View Drop View Alter View Properties Alter View As Select Version information Icon View support is only available in Hive 0.6 and later. Create View CREATE VIEW [IF NOT EXISTS] view_name [(column_name [COMMENT column_com

实验:实现多实例 、数据库的create和alter、create表

多实例:软件程序运行了多次,规划:第一个端口在" 3306 ",第二个端口在" 3307 ",第三个端口在" 3308 ",在对外提供服务时,就感觉是三个mysql服务器一样.(此实验与mariadb的版本无关)1.安装mariadb,[root@centos7 ~]# yum install mariadbLoaded plugins: fastestmirror, langpacksLoading mirror speeds from cac

通过dbcp链接池对数据库操作报 Cannot create PoolableConnectionFactory (Could not create connection to database server. Attempted reconnect 3 times. Giving up.)--解决方案

org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (Could not create connection to database server. Atte