之前我们用register_chrdev()注册字符设备驱动,如:major = register_chrdev(0, "hello", &hello_fops);
这样注册的驱动使主设备号major下所有次设备号0-255都对应一个fops,
即:(major, 0), (major, 1), ..., (major, 255)都对应hello_fops,这样可能浪费了很多次设备号,在2.6内
核后,使用register_chrdev_region(dev_t from, unsigned count, const char *name)注册字符设备,下面只
介绍一下怎么使用 register_chrdev_region() 函数注册字符设备:
register_chrdev_region()函数和 alloc_chrdev_region()函数是两个同等地位的函数,它们使得驱动可以
很灵活地与主次设备号对应。
当指定major和minor时,使用MKDEV(int major,int minor)来获得devid,然后用register_chrdev_region()
函数注册。它使主设备号 major下,次设备号从“devid = MKDEV(major, minor)”指定的开始共minorct个设备与
驱动name对应。
若自动分配主设备号则用alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
函数注册。使主设备号 major = MAJOR(devid); 下,次设备baseminor开始共minorct个设备与驱动name对应。
调用register_chrdev_region()或alloc_chrdev_region()注册后,要手工调用
cdev_init(struct cdev *cdev, const struct file_operations *fops);
和cdev_add(struct cdev *p, dev_t dev, unsigned count);
如:
cdev_init(&hello_cdev, &hello_fops);
cdev_add(&hello_cdev, devid, HELLO_CNT);
来真正注册内核。
这样注册的驱动使主设备号major下所有次设备号0-255都对应一个fops,
即:(major, 0), (major, 1), ..., (major, 255)都对应hello_fops,这样可能浪费了很多次设备号,在2.6内
核后,使用register_chrdev_region(dev_t from, unsigned count, const char *name)注册字符设备,下面只
介绍一下怎么使用 register_chrdev_region() 函数注册字符设备:
register_chrdev_region()函数和 alloc_chrdev_region()函数是两个同等地位的函数,它们使得驱动可以
很灵活地与主次设备号对应。
当指定major和minor时,使用MKDEV(int major,int minor)来获得devid,然后用register_chrdev_region()
函数注册。它使主设备号 major下,次设备号从“devid = MKDEV(major, minor)”指定的开始共minorct个设备与
驱动name对应。
若自动分配主设备号则用alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
函数注册。使主设备号 major = MAJOR(devid); 下,次设备baseminor开始共minorct个设备与驱动name对应。
调用register_chrdev_region()或alloc_chrdev_region()注册后,要手工调用
cdev_init(struct cdev *cdev, const struct file_operations *fops);
和cdev_add(struct cdev *p, dev_t dev, unsigned count);
如:
cdev_init(&hello_cdev, &hello_fops);
cdev_add(&hello_cdev, devid, HELLO_CNT);
来真正注册内核。
不想深究,不懂之处看实例照猫画虎即可:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>
#include <linux/cdev.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 0
major = register_chrdev(0, "hello", &hello_fops);
/* (major, 0), (major, 1), ..., (major, 255)都对应hello_fops */
#else
if (major) {
devid = MKDEV(major, 0);
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_add(&hello_cdev, devid, HELLO_CNT);
devid = MKDEV(major, 2); //指定了主设备号major,从此设备号2开始,共1个
register_chrdev_region(devid, 1, "hello2");
cdev_init(&hello2_cdev, &hello2_fops);
cdev_add(&hello2_cdev, devid, 1);
#endif
cls = class_create(THIS_MODULE, "hello");
class_device_create(cls, NULL, MKDEV(major, 0), NULL, "hello0"); /* /dev/hello0 */
class_device_create(cls, NULL, MKDEV(major, 1), NULL, "hello1"); /* /dev/hello1 */
class_device_create(cls, NULL, MKDEV(major, 2), NULL, "hello2"); /* /dev/hello2 */
class_device_create(cls, NULL, MKDEV(major, 3), NULL, "hello3"); /* /dev/hello3 */
return 0;
}
static void hello_exit(void)
{
class_device_destroy(cls, MKDEV(major, 0));
class_device_destroy(cls, MKDEV(major, 1));
class_device_destroy(cls, MKDEV(major, 2));
class_device_destroy(cls, MKDEV(major, 3));
class_destroy(cls);
cdev_del(&hello_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");