• 简单的字符设备驱动


    下面是一个最简单的字符设备驱动。

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/slab.h>
    #include <linux/uaccess.h>
    
    
    static unsigned int simple_dev_major_num = 222;
    
    module_param(simple_dev_major_num, uint, S_IRUGO);
    
    struct simple_cdev{
        struct cdev scdev;
        unsigned char data;
    };
    
    static struct simple_cdev *psimle_cdev = NULL;
    
    
    int simple_cdev_open(struct inode *pinode, struct file *pfile)
    {
        return 0;
    }
    
    int simple_cdev_close(struct inode *pinode, struct file *pfile)
    {
        return 0;
    }
    
    
    static const struct file_operations simple_cdev_fopt = {
        .owner = THIS_MODULE,
        .open = simple_cdev_open,
        .release =simple_cdev_close,
    };
    
    static int __init simple_cdev_init(void)
    {
        int ret;
        dev_t devno = MKDEV(simple_dev_major_num, 0);
        
        //申请/注册设备号
        if ( 0 == simple_dev_major_num )
        {
            ret = register_chrdev_region(devno, 1, "simple cdev");
        }
        else
        {
            ret = alloc_chrdev_region(&devno, 0, 1, "simple cdev");
            simple_dev_major_num = devno;
        }
    
        if ( ret < 0 )
        {
            printk(KERN_ERR "simple cdev get device num error
    ");
            return ret;
        }
        
        psimle_cdev = kzalloc(sizeof(struct simple_cdev), GFP_KERNEL);
        if ( !psimle_cdev )
        {
            printk(KERN_ERR "simple cdev get memory failed
    ");
            unregister_chrdev_region(devno, 1);
            return -ENOMEM;
        }
        
        //初始化字符设备
        cdev_init(&psimle_cdev->scdev, &simple_cdev_fopt);
        
        psimle_cdev->scdev.owner = THIS_MODULE;
        
        //添加设备
        ret = cdev_add(&psimle_cdev->scdev, devno,  1);
        if ( ret < 0 )
        {
            printk(KERN_ERR "add cdev failed
    ");
            unregister_chrdev_region(devno, 1);
            return ret;
    
        }
        
    	printk(KERN_INFO "simple cdev enter
    ");
    	return 0;
    }
    module_init(simple_cdev_init);
    
    static void __exit simple_cdev_exit(void)
    {
        printk(KERN_INFO "simple cdev exit
     ");
        if ( NULL != psimle_cdev )
        {
            cdev_del(&psimle_cdev->scdev);
            kfree(psimle_cdev);
        }
        unregister_chrdev_region(simple_dev_major_num, 1);
    }
    module_exit(simple_cdev_exit);
    
    MODULE_AUTHOR("thammer@163.com");
    MODULE_LICENSE("GPL v2");
    
    

    其中包含了几个关键的结构体struct file,struct inode,struct cdev,struct file_operations。这几个结构体将应用层对设备文件的open,read,write等操作和实际的设备驱动关联起来。下图展示了字符设备驱动和文件系统的关系。

    通常一个具体的字符设备会以下面的方式描述:

    struct simple_cdev{
        struct cdev scdev;
        unsigned char data;
    	...
    	...
    };
    

    相当于struct cdev是struct simple_cdev的基类,如果用C++来描述:

    class cdev{
    };
    
    class simple_cdev::cdev{
        unsigned char data;
    	...
    	...
    };
    

    struct cdev的几个关键操作函数包含在文件 linux/fs/char_dev.c文件中

    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);
    void unregister_chrdev_region(dev_t from, unsigned count);
    void cdev_init(struct cdev *cdev, const struct file_operations *fops);
    int cdev_add(struct cdev *p, dev_t dev, unsigned count);
    void cdev_del(struct cdev *p);
    

    他们通过SYMBOL_EXPORT导出符号链接,以供其它LKM使用:

    EXPORT_SYMBOL(register_chrdev_region);
    EXPORT_SYMBOL(unregister_chrdev_region);
    EXPORT_SYMBOL(alloc_chrdev_region);
    EXPORT_SYMBOL(cdev_init);
    EXPORT_SYMBOL(cdev_alloc);
    EXPORT_SYMBOL(cdev_del);
    EXPORT_SYMBOL(cdev_add);
    

    前面三个x__chrdev_region函数都是和设备号申请,释放相关的操作函数。cdev_init将struct cdev和设备驱动里面定义的struct file_operations相关联。其实就是将struct cdev的成员ops赋值为指定的fops。cdev_add, cdev_del将设备向/从系统添加/删除,具体应该是kobject组织起来的相关的数据结构,暂时对kobject还不了解,不做分析。

    struct cdev {
    	struct kobject kobj;
    	struct module *owner;
    	const struct file_operations *ops;
    	struct list_head list;
    	dev_t dev;
    	unsigned int count;
    };
    
  • 相关阅读:
    清源CPM代码复现
    图像分类模型
    分享-微软亚洲研究院:NLP将迎来黄金十年
    表格生成本文-代码实践-data2text-plan-py
    了解一下BigBird
    《BERT模型精讲》徐路
    精读论文的步骤
    使用预训练编码器生成文本摘要
    Heap/Perm space
    静态代码块,代码块
  • 原文地址:https://www.cnblogs.com/thammer/p/12542652.html
Copyright © 2020-2023  润新知