cdev方式注册驱动

来源:互联网 发布:安卓ar软件 编辑:程序博客网 时间:2024/06/03 17:26

1、简介

内核提供了三个函数来注册一组字符设备编号,这三个函数分别是 register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev()。

(1)register_chrdev 比较老的内核注册的形式 早期的驱动
(2)register_chrdev_region/alloc_chrdev_region + cdev 新的驱动形式

区别:register_chrdev()函数是老版本里面的设备号注册函数,可以实现静态和动态注册两种方法,主要是通过给定的主设备号是否为0来进行区别,为0的时候为动态注册。register_chrdev_region以及alloc_chrdev_region就是将上述函数的静态和动态注册设备号进行了拆分的强化。

1.2 使用流程

字符驱动cdev注册流程
1. 申请并注册主从设备号
2. 初始化已定义的cdev变量,cdev变量指定file_operations接口
3. 添加cdev变量到内核,完成驱动注册,添加cdev时需要一个已申请成功的主从设备号

 字符驱动cdev注销流程
4. 删除已添加的cdev
5. 注销申请的主从设备号

1.3 主要方法

//动态分配设备编号int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);dev:自动分配的主设备号将保存在dev中firstminor:第一个次设备号 一般为0count:要分配的设备数量name:设备名//指定一个主设备号和一个起始从设备号,如果成功返回0 失败返回错误码dev_t first = MKDEV(int major, int minor);int register_chrdev_region(dev_t first, unsigned int count, char *name);First :要分配的设备编号范围的初始值, 这组连续设备号的起始设备号, 相当于register_chrdev()中主设备号Count:连续编号范围.   是这组设备号的大小(也是次设备号的个数)Name:编号相关联的设备名称. (/proc/devices); 本组设备的驱动名称//注销设备void unregister_chrdev_region(dev_t from,unsigned count)//初始化cdev变量,并设置fopsvoid cdev_init(struct cdev *cdev, const struct file_operations *fops)//添加cdev到linux内核,完成驱动注册int cdev_add(struct cdev *p, dev_t dev, unsigned count)dev:申请好的主设备号+起始从设备号count:为该驱动所占用从设备号的数目//从内核中删除cdev数据void cdev_del(struct cdev *p)

demo

#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/uaccess.h>/*声明class_create 和device_create相关信息*/#include <linux/device.h>//cdev用到的头文件#include <linux/cdev.h>#define DEMO_DEBUG#ifdef  DEMO_DEBUG#define dem_dbg(fmt, arg...)        printk(KERN_WARNING fmt, ##arg)#else#define dem_dbg(fmt, arg...)        printk(KERN_DEBUG fmt, ##arg)#endif#define DEVICE_COUNT        1//1 定义cdev结构体变量和dev_nr主从设备号变量static struct cdev demo_cdev;static dev_t dev_nr;static int demo_open (struct inode *pnode, struct file *filp){    dem_dbg("==>%s  major: %d  minor: %d\n",            __FUNCTION__, imajor(pnode), iminor(pnode));    return 0;}static ssize_t demo_read (struct file *filp, char __user *buf, size_t count, loff_t *offp){    unsigned char ary[100] = "read successfully\n";    unsigned long len = min(count, sizeof(ary));    int retval;    printk("==>%s  major: %d  minor: %d\n",            __FUNCTION__, imajor(filp->f_dentry->d_inode),             iminor(filp->f_dentry->d_inode));    if(copy_to_user(buf, ary, len) != 0){        retval = -EFAULT;        goto cp_err;    }    return len;cp_err:    return retval;      }static int demo_release (struct inode *pnode, struct file *filp){    dem_dbg("==>%s  major: %d  minor: %d\n",            __FUNCTION__, imajor(pnode), iminor(pnode));    return 0;}static struct file_operations fops = {    .owner = THIS_MODULE,    .read = demo_read,    .open = demo_open,    .release = demo_release,};  static struct class *demo_class;static int __init demo_init(void){       int res, i;    struct device *demo_device;    dem_dbg("==>demo_init\n");    //2.1 动态申请主从设备号    res = alloc_chrdev_region(&dev_nr, 0, DEVICE_COUNT, "demo_chrdev");    //2.2 指定主从设备号    //dev_nr = MKDEV(200, 0);    //res = register_chrdev_region(dev_nr, DEVICE_COUNT, "demo_cdev");    if(res){        dem_dbg("==>alloc chrdev region failed!\n");        goto chrdev_err;    }     //3 初始化cdev数据    cdev_init(&demo_cdev, &fops);    //4 添加cdev变量到内核,完成驱动注册    res = cdev_add(&demo_cdev, dev_nr, DEVICE_COUNT);    if(res){        dem_dbg("==>cdev add failed!\n");        goto cdev_err;    }    //创建设备类    demo_class = class_create(THIS_MODULE,"demo_class");    if(IS_ERR(demo_class)){        res =  PTR_ERR(demo_class);        goto class_err;    }    for(i=0; i<DEVICE_COUNT; i++){        //创建设备节点        demo_device = device_create(demo_class,NULL, MKDEV(MAJOR(dev_nr), i), NULL,"demo%d",i);        if(IS_ERR(demo_device)){            res = PTR_ERR(demo_device);            goto device_err;        }    }    return 0;device_err:    while(i--)        device_destroy(demo_class,MKDEV(MAJOR(dev_nr), i));    class_destroy(demo_class);class_err:    cdev_del(&demo_cdev);    cdev_err:    unregister_chrdev_region(dev_nr, DEVICE_COUNT);chrdev_err:    //申请主设备号失败    return res;}static void __exit demo_exit(void){    int i;    dem_dbg("==>demo_exit\n");    //5 删除添加的cdev结构体,并释放申请的主从设备号    cdev_del(&demo_cdev);        unregister_chrdev_region(dev_nr, DEVICE_COUNT);    for(i=0; i<DEVICE_COUNT; i++)        device_destroy(demo_class,MKDEV(MAJOR(dev_nr), i));    class_destroy(demo_class);}module_init(demo_init);module_exit(demo_exit);MODULE_LICENSE("Dual BSD/GPL");
原创粉丝点击