栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

一、linux驱动开发-1.1-字符设备开发步骤

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

一、linux驱动开发-1.1-字符设备开发步骤

目录

一、字符设备简介

二、字符设备驱动开发步骤

2.1、驱动模块的加载和卸载

2.2、字符设备的注册和注销

2.3、实现设备的具体操作函数

2.4、添加license信息


一、字符设备简介

       字符设备就是一个一个字节,按照字节流进行读写的设备,读写数据分先后顺序的。常用的led、按键,i2c,spi,lcd等都是字符设备。

       应用程序调用驱动程序如图所示:

       当编号的驱动加载成功后,就会在/dev目录下生成一个相应的文件,如/dev/xxx,应用程序对这个文件进行相应的操作即可实现对硬件的操作。

       应用程序运行在用户空间,驱动运行在内核空间,因为用户空间不能对内核空间进行操作,必须使用一个叫做“系统调用”的方法实现从用户空间陷入到内核空间,C库中提供的open、close、write、read等函数就属于这种“系统调用”。具体的流程如下:

       在linux内核文件include/linux/fs.h中file_operations的结构体,就是内核驱动操作函数的集合,字符设备驱动开发中,最主要的工作就是实现这个结构体中的函数,具体实现哪些看具体的硬件要求,一般的open、close、write、read等是要实现的。

二、字符设备驱动开发步骤

       在linux中,驱动开发要按照规定的框架来编写,一般有驱动的加载和卸载,设备注册和注销,实现设备的具体操作,添加license信息。

2.1、驱动模块的加载和卸载

       linux驱动有两种运行模式:将驱动编译至内核中,内核启动后自动运行该驱动程序;将驱动编译成模块(扩展名为.ko),内核启动后用“insmod”加载驱动模块。

      推荐使用modprobe命令加载模块,因为insmod命令不能解决依赖关系,modprobe会分析模块的依赖关系,然后将所有依赖模块都加载到内核中,更智能一点。

       在调试阶段,一般是先编译成模块,没问题后再编译进内核,这样做的好处是不用编译整个linux代码,也不用重启整个系统,只需要加载卸载驱动模块即可。

       模块的加载和卸载函数如下,

module_init(xxx_init);    //注册模块加载函数
modele_exit(xxx_exit);    //注册模块卸载函数

       module_init函数用来向linux内核注册一个模块加载函数,参数xxx_init就是需要注册的具体函数,当使用“insmod”命令加载驱动的时候,xxx_init就会被调用。module_exit函数用来向linux内核注册一个模块卸载函数,参数xxx_exit就是需要注册的具体函数,当使用“rmmod”命令卸载具体的驱动时候,xxx_exit就会被调用。模板如下:

static int __init xxx_init(void)
{
    
    return 0;
}


static void __exit xxx_exit(void)
{
   
}


module_init(xxx_init);
module_exit(xxx_exit);

2.2、字符设备的注册和注销

       驱动模块加载成功后需要注册字符设备,卸载驱动模块的时候需要注销字符设备,函数原型如下:

static inline int register_chrdev(unsigned int major, 
                                  const char *name,
                                  const struct file_operations *fops);


static inline void unregister_chrdev(unsigned int major, 
                                     const char *name);

       设备号要用系统中没用掉的,用cat/proc/devices可以查看当前已经使用掉的设备号。   

        设备号链接如下:

         一般字符设备的注册在驱动模块的入口函数中进行,注销在出口函数中进行,即:

static struct file_operations fops;

static int __init xxx_init(void)
{
    register_chrdev(200, "chrtest", &fops);
}

static void __exit xxx_exit(void)
{
    unregister_chrdev(200, "chrtest");
}

module_init(xxx_init);
module_exit(xxx_exit);

2.3、实现设备的具体操作函数

         实现file_operations机构体中的函数 ,具体实现哪些看需求。一般包括open、close、write、read。

static int chrtest_open(struct inode *inode, struct file *filp)
{
    //用户代码
}

static ssize_t chrtest_read(struct file *filp, __user char *buf, size_t count,loff_t *ppos)
{
    //用户代码
}

static ssize_t chrtest_write(struct file *filp, const char __user *buf,
			 size_t count, loff_t *ppos)
{
    //用户代码
}

static int chrtest_close(struct inode *inode, struct file *filp)
{
    //用户代码
}

static const struct file_operations chrtest_fops = {
    .owner = THIS_MODULE,
    .open  = chrtest_open,
    .read  = chrtest_read,
    .write = chrtest_write,
    .close = chrtest_close,

};

static int __init xxx_init(void)
{
    int ret = 0;

    ret = register_chrdev(200, "chrtest", &chrtest_fops);
    if (ret < 0)
    {
        //注册失败处理
    }
    return 0;
}

static void __exit xxx_exit(void)
{
    unregister_chrdev(200, "chrtest");
}

module_init(xxx_init);
module_exit(xxx_exit);




2.4、添加license信息

        licence是必须添加的,否则编译会报错,作者信息可以不添加。

MODULE_LICENSE();    //添加模块license信息
MODULE_AUTHOR();     //添加模块作者信息

//eg:
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZK");

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/308151.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号