一、基本概念
主设备号与次设备号: 可以理解为主设备号对应一个驱动程序,次设备号对应一个设备。
二、重要的数据结构
struct file_operations : 文件操作 可参考: http://blog.csdn.net/sunsea1026/article/details/6586143
struct file : 文件 可参考: http://blog.csdn.net/yuzhihui_no1/article/details/51272563
struct inode : 内部节点 可参考: http://blog.csdn.net/fantasyhujian/article/details/9151615
三、分配及释放设备号
int register_chrdev_region(dev_t first, unsigned int count, char *name);
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
register_chrdev_region : 明确主设备号时使用
alloc_chrdev_region :主设备号未明确时使用
count : 决定了可以使用的设备数量,即在 在调用cdev_add 后,mknod /dev/* c major minor /dev/* 下面有效的设备数量。 如 name=”scull”, count=4, minor =0, 则对应的 通过mknod /dev/* c $major [0-3] /dev/* 建立的设备节点 /dev/scull[0-3]设备节点一一对应。
倾向于 使用alloc_chrdev_region 动态分配主设备号
字符设备注册模型
static void scull_setup_cdev(struct scull_dev *dev, int index)
{
int err, devno = MKDEV(scull_major, scull_minor + index);
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
早期也用进行设备注册
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
int unregister_chrdev(unsigned int major, const char *name);
container_of :函数通过inode 节点中的i_cdev 字段,找到字符结构的首地址
container_of(pointer, container_type, container_field);
eg:
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
scull_trim(dev); /* ignore errors */
}
return 0; /* success */
}
此inode 是内存中的inode, 需要时才创建