udev的支持主要作用是:在驱动初始化的代码里调用class_create(...)为该设备创建一个class,再为每个设备调用device_create(...);
内核中定义的struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用 device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应 device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
下面写一个字符设备测试程序:
#include <linux/module.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <asm/uaccess.h> #define HELLO_MAJOR 250 #define HELLO_MINOR 0 #define NUMBER_OF_DEVICES 2 struct class *hello_class; static struct cdev cdev; dev_t devno; static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { char *str = "hello world"; copy_to_user(buf,str,strlen(str)); *(buf + strlen(str)) = '\n'; return count; } static ssize_t hello_open(struct inode *inode,struct file *file) { return 0; } static const struct file_operations hello_fops = { .open = hello_open, .read = hello_read, .owner = THIS_MODULE, }; static int __init hello_init(void) { int ret; devno = MKDEV(HELLO_MAJOR,HELLO_MINOR); if(HELLO_MAJOR){ ret = register_chrdev_region(devno,NUMBER_OF_DEVICES,"chrdev"); }else{ ret = alloc_chrdev_region(&devno, 0, NUMBER_OF_DEVICES, "chrdev"); } if(ret < 0){ printk("%s register chrdev error\n",__func__); return ret; } hello_class = class_create(THIS_MODULE,"hello_char_calss"); if(IS_ERR(hello_class)){ printk("%s create class error\n",__func__); return -1; } device_create(hello_class, NULL, devno, NULL, "chrdev"); cdev_init(&cdev, &hello_fops); cdev.owner = THIS_MODULE; cdev_add(&cdev, devno, NUMBER_OF_DEVICES); return 0; } static void __exit hello_exit(void) { printk("%s",__func__); cdev_del(&cdev); device_destroy(hello_class,devno); class_destroy(hello_class); unregister_chrdev_region(devno,NUMBER_OF_DEVICES); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("weed<[email protected]>");
ifeq ($(KERNELRELEASE),)
#KERNEL_DIR:=/lib/modules/$(shell uname -r)/build/
KERNEL_DIR:=/usr/src/linux-headers-3.2.0-29-generic-pae
PWD:=$(shell pwd)
modules:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install
clean:
rm -rf .*.cmd *.ko *.o modules.order Module.symvers *mod.c
.PHONY: modules modules_install clean
else
modules-objs := dev.o
obj-m := dev.o
endif
编译模块安装之后会在/sys/class/看到hello_char_class 以及目录内的chrdev,同时也会在/dev下看到udev为我们建立的节点chrdev.
测试程序:
#include <stdio.h> #include <fcntl.h> int main(void) { int fd; int i; char buf[50]; fd = open("/dev/chrdev",O_RDWR); if(fd < 0){ printf("can't open dev\n"); return -1; } read(fd,buf,11); printf("%s",buf); return 0; }