每个设备对应一个设备号,由主设备号(major number)和次设备号(minor number)
类型为 dev_t:有以下三个宏进行操作,位置include/linux/kdev_t.h
#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) //根据设备号获取主设备号
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) //根据设备号获取次设备号
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) //根据主次设备号生成设备号
分配和释放设备号接口,位置 fs/char_dev.c:
注册一个预定设备号
/**
* register_chrdev_region() - register a range of device numbers
* @from: the first in the desired range of device numbers; must include
* the major number.
* @count: the number of consecutive device numbers required
* @name: the name of the device or driver.
*
* Return value is zero on success, a negative error code on failure.
*/
int register_chrdev_region(dev_t from, unsigned count, const char *name)
动态分配一个设备号
/**
* alloc_chrdev_region() - register a range of char device numbers
* @dev: output parameter for first assigned number
* @baseminor: first of the requested range of minor numbers
* @count: the number of minor numbers required
* @name: the name of the associated device or driver
*
* Allocates a range of char device numbers. The major number will be
* chosen dynamically, and returned (along with the first minor number)
* in @dev. Returns zero or a negative error code.
*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name)
设备号
描述字符设备的结构体位置在include/linux/cdev.h,为
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
对应的接口函数位置在fs/char_dev.c,有
静态初始化函数
/**
* cdev_init() - initialize a cdev structure
* @cdev: the structure to initialize
* @fops: the file_operations for this device
*
* Initializes @cdev, remembering @fops, making it ready to add to the
* system with cdev_add().
*/
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
动态初始化函数
/**
* cdev_alloc() - allocate a cdev structure
*
* Allocates and returns a cdev structure, or NULL on failure.
*/
struct cdev *cdev_alloc(void)
{
struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
if (p) {
INIT_LIST_HEAD(&p->list);
kobject_init(&p->kobj, &ktype_cdev_dynamic);
}
return p;
}
添加cdev设备 :用于模块加载函数中
/**
* cdev_add() - add a char device to the system
* @p: the cdev structure for the device
* @dev: the first device number for which this device is responsible 设备号
* @count: the number of consecutive minor numbers corresponding to this
* device 对应设备的次设备号数量
*
* cdev_add() adds the device represented by @p to the system, making it
* live immediately. A negative error code is returned on failure.
*/
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
p->dev = dev;
p->count = count;
return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}
删除设备:用于模块卸载函数中
/**
* cdev_del() - remove a cdev from the system
* @p: the cdev structure to be removed
*
* cdev_del() removes @p from the system, possibly freeing the structure
* itself.
*/
void cdev_del(struct cdev *p)
{
cdev_unmap(p->dev, p->count);
kobject_put(&p->kobj);
}
1.分配设备号 register_chrdev_region 或 alloc_chrdev_region
2.初始化cdev cdev_init() 初始化时会将cdev和file_operations关联
3.添加cdev cdev_add
如果同时存在多个字符设备,可以通过inode->i_cdev区分,如下:
struct my_dev * dev;
dev = container_of(inode->i_cdev, my_dev, cdev)
filp->private_data = dev;
驱动模块使用:
1.insmod
2.创建节点 mknod /dev/my_dev c major minor
3.操作/dev/my_dev