歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

Linux 字符設備驅動結構(二)—— 自動創建設備節點

上一篇我們介紹到創建設備文件的方法,利用cat /proc/devices查看申請到的設備名,設備號。
第一種是使用mknod手工創建:mknod filename type major minor
第二種是自動創建設備節點:利用udev(mdev)來實現設備文件的自動創建,首先應保證支持udev(mdev),由busybox配置。
具體udev相關知識這裡不詳細闡述,可以移步Linux 文件系統與設備文件系統 —— udev 設備文件系統,這裡主要講使用方法。
在驅動用加入對udev 的支持主要做的就是:在驅動初始化的代碼裡調用class_create(...)為該設備創建一個class,再為每個設備調用device_create(...)創建對應的設備
內核中定義的struct class結構體,顧名思義,一個struct class結構體類型變量對應一個類,內核同時提供了class_create(…)函數,可以用它來創建一個類,這個類存放於sysfs下面,一旦創建好了這個類,再調用 device_create(…)函數來在/dev目錄下創建相應的設備節點。
這樣,加載模塊的時候,用戶空間中的udev會自動響應 device_create()函數,去/sysfs下尋找對應的類從而創建設備節點。
下面是兩個函數的解析:
1、class_create(...) 函數
功能:創建一個類;
下面是具體定義:
[cpp] view
plain copy





#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name, &__key); \
})
owner:THIS_MODULE
name : 名字

__class_create(owner, name, &__key)源代碼如下:
[cpp] view
plain copy





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);
}
EXPORT_SYMBOL_GPL(__class_create);
銷毀函數:void class_destroy(struct class *cls)
[cpp] view
plain copy





void class_destroy(struct class *cls)
{
if ((cls == NULL) || (IS_ERR(cls)))
return;
class_unregister(cls);
}
2、device_create(...) 函數
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)

功能:創建一個字符設備文件
參數:
struct class *class :類
struct device *parent:NULL
dev_t devt :設備號
void *drvdata :null、
const char *fmt :名字
返回:
struct device *
下面是源碼解析:
[cpp] view
plain copy





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;
}
device_create_vargs(class, parent, devt, drvdata, fmt, vargs)解析如下:
[cpp] view
plain copy





struct device *device_create_vargs(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt,
va_list args)
{
return device_create_groups_vargs(class, parent, devt, drvdata, NULL,
fmt, args);
}
現在就不繼續往下跟了,大家可以繼續往下跟;
下面是一個實例:
hello.c
[cpp] view
plain copy





#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
static int major = 250;
static int minor=0;
static dev_t devno;
static struct class *cls;
static struct device *test_device;
static int hello_open (struct inode *inode, struct file *filep)
{
printk("hello_open \n");
return 0;
}
static struct file_operations hello_ops=
{
.open = hello_open,
};
static int hello_init(void)
{
int ret;
printk("hello_init \n");
devno = MKDEV(major,minor);
ret = register_chrdev(major,"hello",&hello_ops);
cls = class_create(THIS_MODULE, "myclass");
if(IS_ERR(cls))
{
unregister_chrdev(major,"hello");
return -EBUSY;
}
test_device = device_create(cls,NULL,devno,NULL,"hello");//mknod /dev/hello
if(IS_ERR(test_device))
{
class_destroy(cls);
unregister_chrdev(major,"hello");
return -EBUSY;
}
return 0;
}
static void hello_exit(void)
{
device_destroy(cls,devno);
class_destroy(cls);
unregister_chrdev(major,"hello");
printk("hello_exit \n");
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);
test.c
[cpp] view
plain copy





#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
main()
{
int fd;
fd = open("/dev/hello",O_RDWR);
if(fd<0)
{
perror("open fail \n");
return ;
}
close(fd);
}
makefile
[cpp] view
plain copy





ifneq ($(KERNELRELEASE),)
obj-m:=hello.o
$(info "2nd")
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
all:
$(info "1st")
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order
endif
下面可以看幾個class幾個名字的對應關系:

上一篇我們介紹到創建設備文件的方法,利用cat /proc/devices查看申請到的設備名,設備號。
第一種是使用mknod手工創建:mknod filename type major minor
第二種是自動創建設備節點:利用udev(mdev)來實現設備文件的自動創建,首先應保證支持udev(mdev),由busybox配置。
具體udev相關知識這裡不詳細闡述,可以移步Linux 文件系統與設備文件系統 —— udev 設備文件系統,這裡主要講使用方法。
在驅動用加入對udev 的支持主要做的就是:在驅動初始化的代碼裡調用class_create(...)為該設備創建一個class,再為每個設備調用device_create(...)創建對應的設備
內核中定義的struct class結構體,顧名思義,一個struct class結構體類型變量對應一個類,內核同時提供了class_create(…)函數,可以用它來創建一個類,這個類存放於sysfs下面,一旦創建好了這個類,再調用 device_create(…)函數來在/dev目錄下創建相應的設備節點。
這樣,加載模塊的時候,用戶空間中的udev會自動響應 device_create()函數,去/sysfs下尋找對應的類從而創建設備節點。
下面是兩個函數的解析:
1、class_create(...) 函數
功能:創建一個類;
下面是具體定義:
[cpp] view
plain copy





#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name, &__key); \
})
owner:THIS_MODULE
name : 名字

__class_create(owner, name, &__key)源代碼如下:
[cpp] view
plain copy





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);
}
EXPORT_SYMBOL_GPL(__class_create);
銷毀函數:void class_destroy(struct class *cls)
[cpp] view
plain copy





void class_destroy(struct class *cls)
{
if ((cls == NULL) || (IS_ERR(cls)))
return;
class_unregister(cls);
}
2、device_create(...) 函數
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)

功能:創建一個字符設備文件
參數:
struct class *class :類
struct device *parent:NULL
dev_t devt :設備號
void *drvdata :null、
const char *fmt :名字
返回:
struct device *
下面是源碼解析:
[cpp] view
plain copy





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;
}
device_create_vargs(class, parent, devt, drvdata, fmt, vargs)解析如下:
[cpp] view
plain copy





struct device *device_create_vargs(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt,
va_list args)
{
return device_create_groups_vargs(class, parent, devt, drvdata, NULL,
fmt, args);
}
現在就不繼續往下跟了,大家可以繼續往下跟;
下面是一個實例:
hello.c
[cpp] view
plain copy





#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
static int major = 250;
static int minor=0;
static dev_t devno;
static struct class *cls;
static struct device *test_device;
static int hello_open (struct inode *inode, struct file *filep)
{
printk("hello_open \n");
return 0;
}
static struct file_operations hello_ops=
{
.open = hello_open,
};
static int hello_init(void)
{
int ret;
printk("hello_init \n");
devno = MKDEV(major,minor);
ret = register_chrdev(major,"hello",&hello_ops);
cls = class_create(THIS_MODULE, "myclass");
if(IS_ERR(cls))
{
unregister_chrdev(major,"hello");
return -EBUSY;
}
test_device = device_create(cls,NULL,devno,NULL,"hello");//mknod /dev/hello
if(IS_ERR(test_device))
{
class_destroy(cls);
unregister_chrdev(major,"hello");
return -EBUSY;
}
return 0;
}
static void hello_exit(void)
{
device_destroy(cls,devno);
class_destroy(cls);
unregister_chrdev(major,"hello");
printk("hello_exit \n");
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);
test.c
[cpp] view
plain copy





#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
main()
{
int fd;
fd = open("/dev/hello",O_RDWR);
if(fd<0)
{
perror("open fail \n");
return ;
}
close(fd);
}
makefile
[cpp] view
plain copy





ifneq ($(KERNELRELEASE),)
obj-m:=hello.o
$(info "2nd")
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
all:
$(info "1st")
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order
endif
下面可以看幾個class幾個名字的對應關系:
Copyright © Linux教程網 All Rights Reserved