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(...) 函式
功能:建立一個類;
下面是具體定義:
-
#define class_create(owner, name) \
-
({ \
-
static struct lock_class_key __key; \
-
__class_create(owner, name, &__key); \
-
})
owner:THIS_MODULE
name : 名字
-
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)
-
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 *
下面是原始碼解析:
-
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)解析如下:
-
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
-
#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
-
#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
-
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幾個名字的對應關係: