linux 字符设备驱动模板

学习Linux设备驱动已经有一段时间了,但是发现学习后很多的知识点记忆模糊了,因此对学习过的知识进行了梳理和总结。

1.一般的驱动都是以模块的形式存在的,那么在字符设备的模块加载函数中要完成设备号的申请(静态、动态两种方法)和cdev的注册,而在卸载函数中实现设备号的释放和cdev的注销。

2. 驱动编写模板:

/*
这个设备结构体是自己定义的结构体,包含字符设备结构体和自己定义的其他的成员。
*/
// 设备结构体
struct xxx_dev_t{

    struct cdev cdev;
    ...
}xxx_dev;

// 设备驱动模块加载函数

static int __init xxx_init(void)
{
    ...
    cdev_init(&xxx_dev.cdev,&xxx_fops);// 这个字符设备初始化函数是最关键的设备和驱动的绑定,这样才能使用驱动函数来操作字符设备。
    xxx_dev.cdev.owner=THIS_MODULE;
    // 获取字符设备号
    if(xxx_major){
        register_chrdev_region(xxx_dev_no,1,DEV_NAME); // 先是知道设备号静态的申请,不成功则动态的分配申请。
        }else{
           alloc_chrdev_region(&xxx_dev_no,0,1,DEV_NAME);
        }
}
// 注册设备
ret=cdev_add(&xxx_dev_cdev,xxx_dev_no,1);
}

// 设备驱动模块卸载函数
static void __exit xxx_exit(void)
{
    // 释放占用的设备号
    unregister_chrdev_region(xxx_dev_no,1);
       //    注销设备
     cdev_del(&xxx_dev.cdev);
....
}

3.驱动操作成员函数的编写,例如,open(),close(),read(),write(),release()等函数,先单独的编写在文件中,再赋给struct file_operations xxx_fops 结构体成员中。

// 读设备
ssize_t xxx_read(strcut file *filp,char __user *buf,size_t count,loff_t *f_pos)
{
    ...

    copy_to_user(buf,...,..);
}

ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
     ...
    copy_from_user(..., buf, ...);
     ...
}
/*
long xxx_ioctl() 函数等,根据自己的设备操作需求编写函数;

**/
// 关键的驱动文件操作结构体

struct file_operations xxx_fops = {
    .owner = THIS_MODULE,
    .read = xxx_read,
    .write = xxx_write,
    .unlocked_ioctl= xxx_ioctl,

};

注意:(1)文件操作函数中从读函数是从从内核空间读到用户空间读数据,因此使用copy_to_user()函数,to 到用户空间。

           (2)copy_from_user() 是把用户空间的数据复制到内核空间,from。

            ( 3 ) 下面是字符设备的示意图。

      (4)这个字符设备的模板是基本的字符设备、驱动的模板。一般的设备和驱动是以总线的形式来编写的,例如虚拟总线,这个我们在下一次笔记中记录学习。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章