Linux 字符设备驱动结构

1 cdev结构体

struct cdev{
  struct kobject kobj; /* 内嵌的kobject对象*/
  struct module *owner; /* 所属模块 */
  struct file_operations *ops; /* 文件操作结构体 */
  struct list_head list;
  dev_t dev; /* 设备号 */
  unsigned int count;
}

 

cdev 结构体的dev_t成员定义了设备号, 为32位,其中12位主设备号,20位次设备号。使用下列宏可以从dev_t获得主设备号和次设备号:

MAJOR(dev_t dev)

MINOR(dev_t dev)

 

而使用下列宏则可以通过主设备号和次设备号生成dev_t:

MKDEV(int major, int minor)

 

cdev 结构体的另一个重要成员file_operations定义了字符设备驱动提供给虚拟文件系统的接口函数。

 

Linux2.6 内核提供了一组函数用于操作cdev结构体:

void  cdev_init(struct cdev *, struct file_operation *);
struct cdev *cdev_alloc(void);
void cdev_put(struct cdev *p);
int  cdev_add(struct cdev *, dev_t, unsigned);
void cdev_del(struct cdev *);

 

cdev_init()函数用于初始化cdev的成员,并建立cdev和file_operations之间的链接,其源代码清单如下所示:

void cdev_init(struct cdev *cdev, 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的ops */ }

cdev_alloc()函数用于动态申请一个cdev内存,其源代码如下所示

struct cdev *cdev_alloc(void)
{
    struct cdev *p = kzalloc(sizeof(struct dev), GFP_KERNEL);
    if(p){
        INIT_LIST_HEAD(&p->list);    
        kobject_init(&p->kobj, &ktype_cdev_dynamic);
    }
    return p;
}

cdev_add()函数和cdev_del()函数分别向系统添加和删除一个dev,完成字符设备的注册和注销。

对cdev_add()的调用通常发生在字符设备驱动模块加载函数中,而对cdev_del()函数的调用则通常发生在字符设备驱动模块卸载函数中。

 

2 分配和释放设备号 

    在调用cdev_add()函数向系统注册字符设备之前,应首先调用register_chrdev_region()或alloc_chrdev_region()函数向系统申请设备号,这两个函数原型是 

int register_chrdev_region(dev_t from, unsigned count, const char *name);
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);

 

register_chrdev_region()用于已知启示设备的设备号的情况,而alloc_chrdev_region()用于设备号未知,向系统动态申请未被占用的设备号的情况,函数调用成功以后,会把设备号放入第一个参数dev中。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。