当前位置: 首页 > news >正文

驱动开发1:内核程序框架

驱动编程

.ko 文件

可加载的内核模块,包含可以动态加载到运行中的 Linux 内核的代码

程序1:内核入口和出口

#include <linux/init.h>
#include <linux/module.h>static int __init my_init(void){printk("%s\n,%s\n,%s\n,%s\n,%d\n",__DATE__,__TIME__,__FILE__,__FUNCTION__,__LINE__);return 0;//0表示insmod成功
}static void __exit my_exit(void){printk("%s\n,%s\n,%s\n,%s\n,%d\n",__DATE__,__TIME__,__FILE__,__FUNCTION__,__LINE__);}module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

C/C++ 的预定义宏(Predefined Macros

  • __TIME__ hh:mm:ss
  • __DATE__ Mmm dd yyyy"
  • __FILE__ 当前源文件的路径
  • __FUNCTION__ 当前函数名
  • __LINE__ 当前行号

程序二:内核传参

内核传参的三大原则:

  1. 必须是全局变量

  2. 数据类型没有浮点数

    bool  invbool  char   uchar
    short ushort int uint long ulong charp(char *)
    
  3. 内核参数接受的全局变量必须用宏来进行传参说明

module_param(name,tyoe,perm)
  • name → 参数变量名(你在代码里定义的全局变量)

  • type → 参数类型(bool, int, long, charp 等)

  • perm → 权限(决定是否能通过 sysfs 读写,通常写 00644

#include <linux/init.h>
#include <linux/module.h>//全局变量传参
static int irq;
static char* pstring;//传参说明
module_param(irq,int,0664);
module_param(pstring,charp,0);static int __init my_init(void){printk("函数%s:irq=%d,pstring=%s\n",__func__,irq,pstring);return 0;//0表示insmod成功
}static void __exit my_exit(void){printk("函数%s:irq=%d,pstring=%s\n",__func__,irq,pstring);
}module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

内核直接传参,不需要用“”

在这里插入图片描述

可以在这个文件路径下修改变量值

//全局变量传参
static int irq;
static char* pstring
//传参说明
module_param(irq,int,0664);
module_param(pstring,charp,0);MODULE_PARM_DESC(irq,"this is a int");
MODULE_PARM_DESC(irq,"that is a string");

可以用:MODULE_PARM_DESC增加变量描述,用modinfo命令查看ko文件

在这里插入图片描述

程序三:多文件之间的混合调用

符号导出:让别的内核程序访问到变量和函数

#ifndef __MYTEST_H_
#define __MYTEST_H_
//声明一个函数
extern void mytest(void);
struct mystruct{int a;char b;
};
extern struct mystruct g_str;
#endif
#include <linux/init.h>
#include <linux/module.h>
#include "mytest.h"void mytest(void){printk("function:%s\n",__func__);	
}
//符号导出
EXPORT_SYMBOL(mytest);/*导出结构体*/
struct mystruct g_str={100,'c'};EXPORT_SYMBOL(g_str);
//GPL标准
MODULE_LICENSE("GPL");

这里需要用EXPORT_SYMBOL导出的函数或变量一定不能用static修饰

因为这里相当于给其他内核程序使用该内容,不涉及硬件的申请资源等,不需要module_init和module_exit

#include <linux/init.h>
#include <linux/module.h>
#include "mytest.h"
static int __init my_init(void){printk("%s\n",__func__);mytest();printk("%d,%c\n",g_str.a,g_str.b);return 0;
}static void __exit my_exit(void){printk("%s\n",__func__);mytest();printk("%d,%c\n",g_str.a,g_str.b);
}module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

符号导出就是可以借助头文件访问内容

程序运行:

一定要先加载定义内容的,在加载内核主程序入口

在这里插入图片描述

在这里插入图片描述

其实是因为在/porc/kallsyms可以找到

在这里插入图片描述

注意:EXPORT_SYMBOL_GPL

#include <linux/init.h>
#include <linux/module.h>
#include "mytest.h"void mytest(void){printk("function:%s\n",__func__);	
}
struct mystruct g_str={100,'c'};//符号导出GPL
EXPORT_SYMBOL_GPL(mytest);
EXPORT_SYMBOL_GPL(g_str);
//GPL标准
MODULE_LICENSE("GPL");//----------------------------------//
#include <linux/init.h>
#include <linux/module.h>
#include "mytest.h"
static int __init my_init(void){printk("%s\n",__func__);mytest();printk("%d,%c\n",g_str.a,g_str.b);return 0;
}static void __exit my_exit(void){printk("%s\n",__func__);mytest();printk("%d,%c\n",g_str.a,g_str.b);
}module_init(my_init);
module_exit(my_exit);
//MODULE_LICENSE("GPL");注释

在这里插入图片描述

程序四:printk使用

printk(KERN_LEVEL "format string", arguments...);
级别常量数值描述
KERN_EMERG0系统不可用,紧急情况
KERN_ALERT1必须立即采取行动
KERN_CRIT2临界条件
KERN_ERR3错误条件
KERN_WARNING4i警告条件
KERN_NOTICE5正常但重要的条件
KERN_INFO6信息性消息
KERN_DEBUG7调试级消息
#include <linux/init.h>
#include <linux/module.h>static int __init my_init(void){printk(KERN_EMERG"system cannot work\n");printk(KERN_ALERT"take messages immediately\n");printk(KERN_CRIT"linjie condition\n");printk(KERN_ERR"error condition\n");printk(KERN_WARNING"warning condition\n");printk(KERN_NOTICE"notice message\n");printk(KERN_INFO"information\n");printk(KERN_DEBUG"debug message\n");return 0;
}static void __exit my_exit(void){printk("<0>""system cannot work\n");printk("<1>""take messages immediately\n");printk("<2>""linjie condition\n");printk("<3>""error condition\n");printk("<4>""warning condition\n");printk("<5>""notice message\n");printk("<6>""information\n");printk("<7>""debug message\n");
}module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

一定要注意:

只有一个参数,也就是多个小串拼成一个大串

在这里插入图片描述

可以修改内核的printk

在这里插入图片描述

在这里插入图片描述

程序五:gpio开关灯的使用

内核提供的GPIO操作函数

int gpio_request(unsigned gpio, const char *label);
//内核程序要想访问操作某个GPIO硬件,必须利用此函数先向内核申请这个GPIO资源
GPIO硬件GPIO编号
GPIOC12PAD_GPIO_C + 12
GPIOB26PAD_GPIO_B + 26
void gpio_free(unsigned gpio)
//功能:如果内核程序不再使用某个GPIO硬件,记得要释放资源
//返回值:不用记,只需参考内核大神如何使用判断此函数的返回值即可
gpio_direction_output(unsigned gpio, int value);
//功能:配置GPIO为输出功能同时输出value(1高/0低)
gpio_direction_output(unsigned gpio, int value);
//功能:配置GPIO为输出功能同时输出value(1高/0低)gpio_direction_input(unsigned gpio);
//功能:配置GPIO为输入功能
gpio_set_value(unsigned gpio, int value);
//设置GPIO的输出值为value(1/0)
//此函数使用的前提是提前配置为输出功能int gpio_get_value(unsigned gpio);
//获取GPIO的电平状态,返回值保存状态
//此函数对输入还是输出无要求
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <mach/platform.h>struct led_resource{char* name;int gpio;
};
static struct led_resource led_info[]={{.name="LED1",.gpio=PAD_GPIO_C+12},{.name="LED2",.gpio=PAD_GPIO_C+11}
};
static int __init led_init(void){int i;for(i=0;i<ARRAY_SIZE(led_info);++i){struct led_resource* p=&led_info[i];gpio_request(p->gpio,p->name);gpio_direction_output(p->gpio,0);printk("%s:第%d的灯亮了\n",__func__,i+1);}return 0;
}
static void __exit led_exit(void){int i;for(i=0;i<ARRAY_SIZE(led_info);++i){struct led_resource* p=&led_info[i];gpio_set_value(p->gpio,1);gpio_free(p->gpio);//必须在setValue后再释放	printk("%s第%d的灯灭了\n",__func__,i+1);}	
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

http://www.dtcms.com/a/389605.html

相关文章:

  • 生产制造如何应对客户的订单变更
  • 深入浅出SpringMVC:从入门到实战指南
  • 深度学习入门:从感知机到多层感知机,用逻辑电路讲透神经网络的进化
  • macos m1 芯片无法安装kubeedge keadm 解决办法
  • 猎板 PCB:以全维度工艺突破,构建 PCB 制造技术壁垒
  • android12 SDK31 wifi开发(仅提供连接wifi的工具类)
  • Android播放视频适配黑边问题类型总结
  • 第十一章:AI进阶之--模块的概念与使用(二)
  • 异常检测patchcore 学习笔记 2025
  • [iOS] 网络 - AFNetWorking
  • iOS App 混淆与性能稳定性优化 混淆开销、崩溃风险、CI 集成与落地实务(
  • Freertos系统(任务挂起和恢复)
  • Git更新仓库时,忽略指定文件
  • 告别“瞎练”!数据闭环正成机器人智能进化核心引擎!
  • 基于MATLAB的无人机遥感数据预处理与农林植被性状估算
  • MATLAB基于AHP-模糊综合评价法的工程实践能力评价
  • 特征选择+优化算法+GBDT+SHAP分析!ReliefF-CPO-GBDT分类预测结合SHAP可解释分析MATLAB
  • 设计模式-外观模式详解
  • 《FastAPI零基础入门与进阶实战》第19篇:消息管理
  • 类和对象(下):static成员、友元类、内部类、匿名对象、优化——对象拷贝时的编译器优化
  • 虚拟线程(Virtual Thread)
  • 1688 店铺全商品接口技术全解:从页面解析到分页采集的完整实现方案
  • 日志轮转策略针对香港VPS存储空间的设置标准
  • 线性分组码及其相关概念
  • JWT的工作流程
  • Java 25 新特性 更简洁、更高效、更现代
  • 探讨前端与后端的安全策略:保护用户数据的关键措施
  • 如何使用DeepSeek等AI工具来帮助自己的工作
  • 灵途科技亮相CIOE2025 | 光电感知赋能具身智能升级
  • 我的云端影院:LibreTV+cpolar的异地观影记