一、函数解析


1、 int register_chrdev_region(dev_t first, unsigned int count, char *name) ​为一个字符驱动获取一个或多个设备编号

     参数解析 : first:是你要分配的起始设备编号.,first 的次编号部分常常是 0。使用MKDEV(major, 0) 来获取dev_t类型的设备编号 count:是你请求的连续设备编号的总数   name:是应当连接到这个编号范围的设备的名字; 它会出现在 /proc/devices 和 sysfs 中       返回值:   如果分配成功进行, register_chrdev_region 的返回值是 0 2、int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name) ​动态分配设备编号

参数解析 : dev:动态分配的设备编号保存在dev上 firstminor:第一个次设备号(一般为0) count:是你请求的连续设备编号的总数    name:是应当连接到这个编号范围的设备的名字; 它会出现在 /proc/devices 和 sysfs 中 3、 void cdev_init(struct cdev *cdev, const struct file_operations *fops) ​静态初始化一个cdev结构体变量,内核中每个字符设备都对应一个 cdev 结构的变量


参数解析 : cdev:struct cdev结构体指针,初始化该结构体 fops: struct file_operations结构体指针,已经赋值了对应的函数 4、int cdev_add(struct cdev *p, dev_t dev, unsigned count) ​

把cdev添加到系统中去

参数解析 : p:struct cdev结构体指针 dev: dev_t类型的设备编号 count: 连续次设备号数 5、 void cdev_del(struct cdev *p) ​从系统移除cdev

参数解析: p:struct cdev结构体指针

二、例程



/*******************************************
使用linux3.2.81内核
********************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>

/* 1. 确定主设备号 */
static int major;

static int hello_open(struct inode *inode, struct file *file)
{
printk("hello_open\n");
return 0;
}

static int hello2_open(struct inode *inode, struct file *file)
{
printk("hello2_open\n");
return 0;
}


/* 2. 构造file_operations */
static struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
};

static struct file_operations hello2_fops = {
.owner = THIS_MODULE,
.open = hello2_open,
};


#define HELLO_CNT 2

static struct cdev hello_cdev;
static struct cdev hello2_cdev;
static struct class *cls;

static int hello_init(void)
{
dev_t devid;

/* 3. 告诉内核 */
if (major) {
devid = MKDEV(major, 0); //返回dev_t类型的设备编号
register_chrdev_region(devid, HELLO_CNT, "hello"); /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */
} else {
alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello"); /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */
major = MAJOR(devid); //获取主设备号
}

cdev_init(&hello_cdev, &hello_fops); //静态初始化一个cdev结构体变量,内核中每个字符设备都对应一个 cdev 结构的变量
cdev_add(&hello_cdev, devid, HELLO_CNT); //把cdev添加到系统中去

devid = MKDEV(major, 2);
register_chrdev_region(devid, 1, "hello2");
cdev_init(&hello2_cdev, &hello2_fops);
cdev_add(&hello2_cdev, devid, 1);

cls = class_create(THIS_MODULE, "hello");
device_create(cls, NULL, MKDEV(major, 0), NULL, "hello0"); /* /dev/hello0 */
device_create(cls, NULL, MKDEV(major, 1), NULL, "hello1"); /* /dev/hello1 */
device_create(cls, NULL, MKDEV(major, 2), NULL, "hello2"); /* /dev/hello2 */
device_create(cls, NULL, MKDEV(major, 3), NULL, "hello3"); /* /dev/hello3 */


return 0;
}

static void hello_exit(void)
{
device_destroy(cls, MKDEV(major, 0));
device_destroy(cls, MKDEV(major, 1));
device_destroy(cls, MKDEV(major, 2));
device_destroy(cls, MKDEV(major, 3));
class_destroy(cls);

cdev_del(&hello_cdev); //从系统中删除cdev
unregister_chrdev_region(MKDEV(major, 0), HELLO_CNT);

cdev_del(&hello2_cdev);
unregister_chrdev_region(MKDEV(major, 2), 1);
}

module_init(hello_init);
module_exit(hello_exit);


MODULE_LICENSE("GPL");


测试程序


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


/*
* hello_test /dev/hello0
*/

void print_usage(char *file)
{
printf("%s <dev>\n", file);
}

int main(int argc, char **argv)
{
int fd;
if (argc != 2)
{
print_usage(argv[0]);
return 0;
}

fd = open(argv[1], O_RDWR);
if (fd < 0)
printf("can't open %s\n", argv[1]);
else
printf("can open %s\n", argv[1]);

return 0;
}