Linux设备驱动程序学习----11.字符设备的注册

11.字符设备的注册

更多内容请参考Linux设备驱动程序学习----目录

字符设备的注册

  内核内部使用struct cdev结构来表示字符设备,在内核调用设备的操作之前,必须分配注册一个或多个数据结构,参考上节重要的数据结构,因该包含头文件

  分配和初始化struct cdev的方式有两种,

struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;

  初始化一分配到的cdev结构:

void cdev_init(struct cdev *cdev, struct file_operations *fops);

  cdev结构的所有者字段,应该设置为THIS_MODULE:

.owner = THIS_MODULE

  cdev结构设置好之后,需要告诉内核该结构的信息:

int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
    dev: 是cdev结构
    num: 是该设备对应的第一个设备编号
    count: 是应该和该设备关联的设备编号的数量,经常取count = 1
    在某些情况下,会有多个设备编号对应于一个特定的设备;

  在使用cdev_add()函数时应注意,这个调用可能会失败,如果返回一个负的错误码,该设备不会被添加到系统中。因此,在驱动程序还没有完全准备好处理设备上的操作时,就不能调用cdev_add()函数。

  从系统中移除一个字符设备:

void cdev_del(struct cdev *dev);

  调用cdev_del()函数之后,就不应该再访问cdev结构了。

scull中的设备注册

  在scull驱动中,通过struct scull_dev结构来表示每个设备:

struct scull_dev {
    struct scull_qset *data;    // 指向第一个量子集的指针
    int quantum;    // 当前量子的大小
    int qset;   // 当前数组的大小
    unsigned long size; // 保存在其中的数据总量
    unsigned int access_key;    // 由sculluid和sculloriv使用
    struct semaphore sem;   // 互斥信号量
    struct cdev cdev;   // 字符设备结构
}

  在scull驱动中,将struct cdev结构初始化并添加到系统中的操作如下:

static void scull_setup_cdev(struct scull_dev *dev, int index)
{
    int err;
    dev_t 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);
    if (err)
        printk(KERN_NOTICE "Error %d adding scull: %d\n", err, index);
}

早期的办法

  在内核Linux-2.6之前的版本中,字符设备驱动程序没有使用cdev接口,而是使用老的接口,在新的代码中不应该使用老的接口,因为这种机制会在将来的内核中消失。

  注册一个字符设备驱动程序的经典方式是:

int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
    major:  是设备的主设备号
    name:   是驱动程序的名称(出现在/proc/devices中)
    fops:   是默认的file_operations结构

  register_chrdev()函数,可实现静态、动态注册:

  动态注册,即major = 0时,类似alloc_chrdev_region()函数,系统会动态为设备分配一个未被使用的主设备号,并将分配的主设备号作为返回值;

  静态注册,即major不为0,而是由驱动开发者指定,类似register_chrdev_region()函数,系统会检测指定的主设备号是否已经被使用,如果没有被使用,则分配给该设备使用,如果已经被占用,就返回一个错误值。

  对register_chrdev()函数的调用将为给定的主设备号注册0~255作为次设备号,并为每一个设备建立一个对应的默认cdev结构,不能使用大于255的主设备号和次设备号。

  注销一个已经注册的字符设备驱动程序,即将已经注册的设备从系统中移除的方式:

int unregister_chrdev(unsigned int major, const char *name);
    // major和name必须和传递给register_chrdev()函数的参数值保持一致,否则该调用会失败。

更多内容请参考Linux设备驱动程序学习----目录

你可能感兴趣的:(Linux设备驱动程序学习----11.字符设备的注册)