Linux内核驱动开发的EXPORT_SYMBOL
前言
很抱歉各位粉丝啊,博主好久没有更新原创文章,从今天起开始恢复写文章的时光。前段时间各种不顺利,到时心情低落。现在恢复状态了。
简介
本文主要来讲讲Linux内核驱动中,EXPORT_SYMBOL()宏定义的用法。
在阅读的Linux内核驱动源码的时候,我们会发现很多的函数带有EXPORT_SYMBOL()宏定义。
从这个宏定义的理解为输出符号。那么他究竟有什么作用。
EXPORT_SYMBOL()宏定义作用
EXPORT_SYMBOL宏定义定义的函数或者符号将对内核代码公开,不用修改内核代码就在其他的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。
使用方法
在模块函数定义之后使用"EXPORT_SYMBOL(函数名)"来导出。
static int rice_func(void)
{return 0;
}
EXPORT_SYMBOL(rice_func);
在调用该函数的另外一个模块中使用extern对之声明。
extern int rice_func(void);
先加载定义该函数的模块,然后再加载调用该函数的模块,先后顺序必须注意。
实验
编写代码
编写两个模块:rice_export.ko 和 rice_import.ko,其中:
rice_export.ko:导出定义的函数
rice_import.ko:调用导出的函数
导出函数模块的代码(rice_export.c)
导出函数为:rice_drv_export,函数含义:外部输入一个字符串,然后打印出来
#include "rice_export.h"#define CLASS_NAME "rice_export"
#define DEVICE_NAME "rice_export"typedef struct {int major_number;struct device *device;struct class *class;
} Rice_Driver;Rice_Driver rice_drv;static int rice_drv_export(char *name) {printk(KERN_ALERT "Rice Export: %s\n", name);return 0;
}
EXPORT_SYMBOL(rice_drv_export);static int __init rice_export_init(void) {rice_drv.major_number = register_chrdev(0, DEVICE_NAME, NULL);if (rice_drv.major_number < 0) {printk(KERN_ALERT "Register fail!!\n");return rice_drv.major_number;}printk(KERN_ALERT "Registe success, major number is %d\n", rice_drv.major_number);rice_drv.class = class_create(THIS_MODULE, CLASS_NAME);if (IS_ERR(rice_drv.class)) {unregister_chrdev(rice_drv.major_number, DEVICE_NAME);return PTR_ERR(rice_drv.class);}rice_drv.device = device_create(rice_drv.class, NULL, MKDEV(rice_drv.major_number, 0), NULL, DEVICE_NAME);if (IS_ERR(rice_drv.device)) {class_destroy(rice_drv.class);unregister_chrdev(rice_drv.major_number, DEVICE_NAME);return PTR_ERR(rice_drv.device);}printk(KERN_ALERT "rice export ko init!!\n");return 0;
}static void __exit rice_export_exit(void) {device_destroy(rice_drv.class, MKDEV(rice_drv.major_number, 0));class_unregister(rice_drv.class);class_destroy(rice_drv.class);unregister_chrdev(rice_drv.major_number, DEVICE_NAME);printk(KERN_ALERT "rice export ko exit!!\n");
}module_init(rice_export_init);
module_exit(rice_export_exit);
MODULE_AUTHOR("RieChen");
MODULE_LICENSE("GPL");
电泳函数模块的代码(rice_import.c)
调用函数声明:extern int rice_drv_export(char *name);,含义:声明外部函数
#include "rice_import.h"#define CLASS_NAME "rice_import"
#define DEVICE_NAME "rice_import"typedef struct {int major_number;struct device *device;struct class *class;
} Rice_Driver;Rice_Driver rice_drv;extern int rice_drv_export(char *name);static int __init rice_import_init(void) {rice_drv.major_number = register_chrdev(0, DEVICE_NAME, NULL);if (rice_drv.major_number < 0) {printk(KERN_ALERT "Register fail!!\n");return rice_drv.major_number;}printk(KERN_ALERT "Registe success, major number is %d\n", rice_drv.major_number);rice_drv.class = class_create(THIS_MODULE, CLASS_NAME);if (IS_ERR(rice_drv.class)) {unregister_chrdev(rice_drv.major_number, DEVICE_NAME);return PTR_ERR(rice_drv.class);}rice_drv.device = device_create(rice_drv.class, NULL, MKDEV(rice_drv.major_number, 0), NULL, DEVICE_NAME);if (IS_ERR(rice_drv.device)) {class_destroy(rice_drv.class);unregister_chrdev(rice_drv.major_number, DEVICE_NAME);return PTR_ERR(rice_drv.device);}printk(KERN_ALERT "rice import ko init!!\n");rice_drv_export("RiceChen");return 0;
}static void __exit rice_import_exit(void) {device_destroy(rice_drv.class, MKDEV(rice_drv.major_number, 0));class_unregister(rice_drv.class);class_destroy(rice_drv.class);unregister_chrdev(rice_drv.major_number, DEVICE_NAME);printk(KERN_ALERT "rice import ko exit!!\n");
}module_init(rice_import_init);
module_exit(rice_import_exit);
MODULE_AUTHOR("RieChen");
MODULE_LICENSE("GPL");
编译运行
将两个模块编译完,push到板子,先加载导出模块--rice_export.ko,然后再加载调用模块--rice_import.ko
运行结果:
关注微信公众号『Rice嵌入式开发技术分享』,后台回复“微信”添加作者微信,备注”入群“,便可邀请进入技术交流群。
Linux内核驱动开发的EXPORT_SYMBOL相关推荐
- 树莓派基于Linux内核驱动开发详解
一.驱动认知 首先理解Linux内核框图 文件系统认知,Linux内核框图 1.什么是驱动 linux内核驱动.软件层面上的驱动 广义上是指:这一段代码操作了硬件去动,所以这一段代码就叫硬件的驱动程序 ...
- 嵌入式 Linux 内核驱动开发【The first day: 36093万字】
嵌入式 Linux 内核驱动开发[1] 嵌入式 Linux 内核驱动开发前言 第1章 Linux 内核裁剪和定制 [1]Linux 内核开发简介 [2] Linux 源码阅读工具 [1.2.1]Sou ...
- Linux内核驱动开发-USB热插拔信息调取
前言: 前段时间上科大嵌入式安卓开发溜了个作业,开发一个驱动,可以实现读取USB热插拔信息,程序调用显示USB设备名称和插拔时间.代码已经放在了我的Github上,供大家参考. 思路: USB热插拔的 ...
- Linux 内核驱动开发基础
1.裸板驱动和linux驱动的异同点 裸板驱动:uart驱动程序:uart_inituart_putsuart_getsi2c控制器驱动:i2c_starti2c_stopi2c_txi2c_rxg- ...
- 树莓派基于Linux内核驱动开发
一.驱动认知 1.1 为什么要学习写驱动 树莓派开发简单是因为有厂家提供的wiringPi库,实现超声波,实现继电器操作,做灯的点亮-都非常简单. 但未来做开发时,不一定都是用树莓派,则没有wirin ...
- 第三阶段:43-47.树莓派基于Linux内核驱动开发
目录 一.驱动认知 1.1 为什么要学习写驱动 1.2 文件名与设备号 1.3 open函数打通上层到底层硬件的详细过程 二.基于框架编写驱动代码 2.1 编写上层应用代码 2.2 修改内核驱动框架代 ...
- Linux内核驱动开发(一)
Linux内核初探 linux操作系统历史 开发模式 git 分布式管理 git clone 获取 git push 提交 git pull 更新 邮件组 mailing list patch 内核代 ...
- linux 内核驱动开发
一.为什么要学习内核? 有些人要学习内核,而有些人则可以不学习它.你如果以后要从事系统研发或驱动开发的话,就要学习内核. 刚刚接触内核,主要学习内核的接口函数.不要深入的去读内核,因为你读也读不懂,内 ...
- linux内核驱动开发 培训,嵌入式Linux驱动开发培训 - 华清远见教育集团官网
9.LINUX下USB驱动开发基础 9.1 USB规范介绍 9.2 USB主机控制器 9.3 USB HUB 9.4 USB设备状态 9.5 USB描述符 9.6 USB请求 9.7 USB通讯数据格 ...
最新文章
- OSI第七层:应用层功能及介绍
- 如何在无人机上部署YOLOv4
- java长度为100的数组_产生一个int数组,长度为100,并向其中随机插入1-100,不重复...
- 告别运营怪圈,不做“背锅侠+加班狗+低薪族”!
- 如果java使用什么声明类_如果声明一个类时使用abstract修饰符,则表明该类是()_学小易找答案...
- UI Personalization persistent DB database table
- intellij 使用_使用IntelliJ书签
- 离线安装PostgreSQL
- IIS故障问题(Connections_Refused)分析及处理【转】
- 【每日算法Day 78】面试经典题:能说出全部四种方法,不录用你都不可能!
- Java实现DFA算法对敏感词、广告词过滤功能
- Java实现获取汉字的拼音(首拼)
- 富勒wms系统里的定时器id_为什么物流行业非常推崇仓库管理系统?
- TensorFlow数据读取方式:Dataset用法
- RFID固定资产管理系统全生命周期管理办公资产
- Python match-search-findall-group(s)的区别
- Direct I/O in DOSBOX for COMM serial communications with QBasic, TBasic or Pbasic
- 文本摘要相关论文汇总
- Arale Base源码分析(含Attribute)
- 小组项目的初步构建与需求分析
热门文章
- SpringBoot配置全局日期格式转换器
- 百色计算机等级考试时间有哪些,2018年3月广西壮族自治区百色计算机等级考试简章...
- 全国口译笔译考试CATTI-笔译三级考试大纲
- 如何理解vue中 同步异步
- 2016-11-11 Redis
- 猫眼APP注册界面布局
- 吡啶修饰的BODIPY-560/613 氟化硼二吡咯560/613
- puppeteer调研--生成页面的屏幕截图和PDF
- php培训 pdf,php生成pdf
- oracle exfsys 下 rlm$evtcleanup,ORA-27468 EXFSYS.RLM$EVTCLEANUP任务引起的故障