驱动开发--驱动模块

news2024/12/27 5:25:10

目录

1.驱动模块 

hello.c

Makefile

2.内核中的打印函数(编写第一个驱动程序)

Source Insight 使用:

3.打印函数编写

分析

4、驱动的多文件编译

5、模块传递参数

6、安装好驱动之后如何传参?

 7、字符设备驱动

8、字符设备驱动的注册

9、总结归纳:


1.驱动模块 

入口(安装):资源的申请

出口(卸载):资源的释放

许可证:GPL

hello.c

//声明函数

static int  __init hello_init(void) //入口,static :只能在当前程序使用,防止其他驱动重名

{
   return 0;
}

static void __exit hello_exit(void)//出口
{

}
module_init(hello_init);//告诉内核驱动的入口

module_exit(hello_exit);//告诉内核驱动的出口

MODULE_LICENSE("GPL");

Makefile

                     ==/lib/modules/4.15.0-142-generic/build

KERNELDIR:= /lib/modules/$(shell uname -r)/build/              Ubuntu内核目录

#KERNELDIR:= /home/hq/fs6818_uboot/kernel-3.4.39/        开发板内核目录

PWD:=$(shell pwd)

all:

    make -C $(KERNELDIR) M=$(PWD) modules

clean:

    make -C $(KERNELDIR) M=$(PWD) clean

obj-m:=hello.o 

 编写完后执行make编译,sudo insmod hello.ko安装

$make

$sudo insmod hello.ko

$sudo rmmod hello  //卸载

 

2.内核中的打印函数(编写第一个驱动程序)

Source Insight 使用:

1)打开Source Insight,新建项目 Project-->New Project

2)添加自己的工程名与存放路径 ,点击OK

3)选择解压后的内核代码,点击Add All全部添加 

 

3.打印函数编写

分析

--------------------------------------------------------打印级别-----------------------------------------------------

#define KERN_EMERG "<0>" /* system is unusable */

#define KERN_ALERT "<1>" /* action must be taken immediately */

#define KERN_CRIT "<2>" /* critical conditions */

#define KERN_ERR "<3>" /* error conditions */

#define KERN_WARNING "<4>" /* warning conditions */

#define KERN_NOTICE "<5>" /* normal but significant condition */

#define KERN_INFO "<6>" /* informational */

#define KERN_DEBUG "<7>" /* debug-level messages */

       4                        4                                 1                          7

终端的级别          消息的默认级别          终端的最大级别     终端的最小级别     

#define console_loglevel (console_printk[0])

#define default_message_loglevel (console_printk[1])

#define minimum_console_loglevel (console_printk[2])

#define default_console_loglevel (console_printk[3])

------------------------------------------------------打印函数-------------------------------------------------------

printk(KERN_ERR "BFS-fs: %s(): " format, __func__, ## args)

功能:消息打印

参数:

   第一个参数:打印的级别

   第二个参数:打印的内容

   第三个参数:和printf一样,需要打印的参数

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
static int __init hello_init(void)//入口
{
  printk(KERN_ERR "hello word\n");
  return 0;
}
static void __exit hello_exit(void)//出口
{
  printk(KERN_ERR "baibai\n");
}
module_init(hello_init);//告诉内核驱动的入口
module_exit(hello_exit);//告诉内核驱动的出口
MODULE_LICENSE("GPL");

没有打印信息,解决方法如下: 

PM:

方法一:虚拟控制台

       ctrl+alt+F5 或者ctrl+Fn+alt+F5(F1-F5)(进入虚拟控制台)

       ctrl+alt+F7或者ctrl+Fn+alt+F7(退出虚拟控制台)-》有的退出是F2

       sudo insmod  hello.ko(安装驱动)sudo rmmod  hello(卸载驱动)

方法二:在终端输入

  dmesg (查看消息的回显)  dmesg -c  (查看回显并清空)dmesg -C  (清空回显)

 cat /proc/sys/kernel/printk(查看ubuntu终端显示级别 消息默认级别 消息最大级别  消息最小级别)

  su root  echo 4 3 1 7 > /proc/sys/kernel/printk(修改ubuntu终端显示级别 消息默认级别 消息最大级别  消息最小级别)

       echo  4 3 1 7 > /proc/sys/kernel/printk (修改开发板)

       =     赋值 需要等待其他文件全部执行完,才执行调用的

      :=   立即赋值

      +=   附加赋值

      ?= 询问变量之前是否被赋值过,如果赋值过本次赋值不成立,否则成立

4、驱动的多文件编译

hello . c   add . c

 Makefile

 obj-m:=demo.o

 demo-y+=hello.add.o

最终生成demo.ko文件

 

5、模块传递参数

module_param(name, type, perm) 

功能:接收命令行传递的参数

参数:

name: 变量的名字  type:变量的类型  perm:权限 0664 0775 

name: 变量的名字  type:变量的类型  perm:权限 0664 0775 

#include <linux/init.h>
#include <linux/module.h>
int a=10;
module_param(a,int,0664);                   
static int __init hello_init(void)
{
 printk("sum= %d\n",a);
 return 0;
}
static void __exit hello_exit(void)
{
 printk(KERN_ERR"bai");                
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

 

传递两个参数程序

int  a = 10 ;

module_param(a,int,0664);

int b=10;

module_param(b,int,0664);

问:安装时怎么区分a和b的作用,自己写的知道那如果移植其他厂商的呢比如LCD屏

使用modinfo hello.ko查看

且需要程序里使用如下函数进行配置:

MODULE_PARM_DESC(_parm, desc)

功能:对变量的功能进行描述

参数:@_parm:变量

           @desc :描述字段

int a=10;
module_param(a,int,0664);
MODULE_PARM_DESC(a,"light");//描述信息
short b=123;
module_param(b,short,0664);
MODULE_PARM_DESC(b,"color");
char c='c';
module_param(c,byte,0664);
MODULE_PARM_DESC(c,"light_c");
 static int __init hello_init(void)
{ 
    printk("sum= %d\n",a);
    printk("sum= %d\n",b);
    printk("sum= %c\n",c);                                                                                                                                                                                
return 0;
}
static void __exit hello_exit(void)
 {
  printk(KERN_ERR"bai");
}
 module_init(hello_init);
 module_exit(hello_exit);
 MODULE_LICENSE("GPL");

练习:其他类型

数组传参:

module_param_array(name,type,nump,perm)

功能:接收命令行传递的数组

参数:name:数组名 type :数组类型  nump:参数的个数,变量的地址 perm 权限

int ww[10]={0}; 
int num;
module_param_array(ww,int,&num,0664)
static int __init hello_init(void)
{
    int i;
    for(i=0;i<num;i++)
    {
     printk("ww[%d]=%d\n",i,ww[i]);
    }
}

sudo insmod hello.ko ww=1,2,3,4,5 

 

6、安装好驱动之后如何传参?

  1. lsmod查看驱动名字

2、找路径 /sys/module/驱动模块的名字/parameters

3、修改-》su root-》echo  需要改为多少> 需要修改的参数名

4、cat 需要修改的参数名  (查看是否修改成功)多驱动之间调用(导出符号表)

假如有两个驱动模块,modul1和modu2 。这两个是可以调用的

cp  ../day1/module  .  -a    拷贝module到当前目录下

makdir export   mv module/  export/ 

mv module/   A 重命名moudule为A

cp A B -a  拷贝一份并命名为B

#include <linux/intt.h>
#include <linux/module.h>
int add(int a,int b)
{
 return (a+b);
}
EXPORT_SYMBOL_GPL(add);//导出符号表
static int __init hello_init(void)
{
 return 0;
}
staic int __exit hello_exit(void)
{
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

进入B,mv hello.c demo.c改下名字

然后vi打开

extern int add ( int  a , int  b );

static int __init hello_init(void)

{

printk("sum = %d\n",add(10,345));

}

编译: make         发现报错,提示add没有定义

 所以在执行之前把A里面大M开头文件复制到当前目录下   

mv  cp  ../A/Module.symvers               然后再make

安装:

 先安装提供者 sudo insmod hello.ko

 再安装调用者 sudo insmod  demo.ko

查看信息:dmesg

卸载:先卸载 demo.ko  再卸载 

 7、字符设备驱动

8、字符设备驱动的注册

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

   功能:注册一个字符设备驱动

参数:

@major:主设备号  

  :如果你填写的值大于0,它认为这个就是主设备号

  :如果你填写的值为0,操作系统给你分配一个主设备号   

@name :名字    cat /proc/devices 查看设备名和主设备号

@fops :操作方法结构体

返回值:major>0 ,成功返回0,失败返回错误码(负数) (vi -t EIO 可以查看错误码)

major=0,成功主设备号,失败返回错误码(负数)      

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

功能:注销一个字符设备驱动

参数:

@major:主设备号

@name:名字

返回值:无

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/fs.h>
int major=0;
#define CNAME "hello"
ssize_t mycdev_read (struct file *file, char __user *user, size_t size, loff_t * loff)
{
   printk("this is read");
   return 0;
}
ssize_t mycdev_write (struct file *file, const char __user *user, size_t, loff_t *loff)
{
   printk("this is write");
   return 0;
}
int mycdev_open (struct inode *inode, struct file *file)
{
   printk("this is open");
   return 0;
}
int mycdev_release (struct inode *inode, struct file *file)
{
   printk("this is close");
   return 0;
}
	
const struct file_operations fops={
   .open=mycdev_open,
   .read=mycdev_read,
   .write=mycdev_write,
   .release=mycdev_release,
};

static int __init hello_init(void)//入口
{
  major=register_chrdev(major,CNAME,&fops);
  if(major<0)
  {
   printk("register chrdev error");
  }
  return 0;
}
static void __exit hello_exit(void)//出口
{
  unregister_chrdev(major,CNAME);
}
module_init(hello_init);//告诉内核驱动的入口
module_exit(hello_exit);//告诉内核驱动的出口
MODULE_LICENSE("GPL");

9、总结归纳:

字符设备驱动:

 1、注册驱动register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)

major=0  自动分配设备号  name:驱动的名字   fops:结构体

 2、声明结构体-》注册驱动时第三个参数

 3、open、read、write、release-》按照内核的格式自己写的

 4、把自己写的这些函数->给到结构体里-》.open .read .write .release

 5、注销设备驱动

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/617617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python如何突破VIP限制

Python如何突破VIP限制 在这个数字内容时代&#xff0c;我们经常使用各种网站和应用程序来获取视频、音乐、软件等数字资源。但是&#xff0c;某些资源可能受到VIP限制&#xff0c;这意味着我们需要付费才能获得完整的访问权限。但是&#xff0c;如果你了解Python编程&#xf…

Agile | 聊聊敏捷开发

什么是敏捷开发 敏捷开发是一种迭代和增量的项目管理方法&#xff0c;优先考虑适应性、协作和快速交付&#xff0c;而不是遵循严格的计划[0]。它是在《敏捷软件开发宣言》和《12项原则》中表达的一组价值观和原则[1]。敏捷是基于这些价值观和原则的一组框架和实践的总称。敏捷…

【数据库】修改数据库密码及端口

一、修改MySQL配置文件 想要在没有密码的状态下修改MySQL的密码&#xff0c;必须跳过MySQL登录时的登录密码权限的验证&#xff0c;取消掉这个验证的方式如下&#xff1a; 1、找到MySQL的安装文件中的my.ini文件 一般人应该能找到的吧&#xff0c;配置MySQL的环境变量中也有安…

关于数据中心机房动环监控系统的应用与设计 安科瑞 许敏

摘 要&#xff1a; 机房动力和环境监控系统是对分布的精密机房及通信局&#xff08;站&#xff09;内的电源、空调、油机、蓄电池、高低压配电等多种设备和环境的各种参数、图像、声音等进行遥测、并对设备进行集中监控、集中维护和集中管理&#xff0c;是现代化机房管理手段和…

【Leetcode -138.复制带随机指针的链表 -2130.链表最大孪生和】

Leetcode Leetcode -138.复制带随机指针的链表Leetcode -2130.链表最大孪生和 Leetcode -138.复制带随机指针的链表 题目&#xff1a;给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构…

chatgpt赋能python:Python如何设置画笔颜色

Python如何设置画笔颜色 在Python中&#xff0c;有很多库可以用来画图&#xff0c;比如常用的Matplotlib、Seaborn和Plotly等等&#xff0c;但无论是哪种库&#xff0c;设置画笔颜色都是非常基础且重要的操作&#xff0c;因为它可以让我们更好地展示数据图表&#xff0c;突出重…

【TCP/IP】基于UDP的服务器端/客户端实现 II - 实践与实现

基于UDP的回声服务器端/客户端 结合之前基于TCP实现的回声服务器&#xff0c;我们尝试再用UDP来完成对回声服务器/客户端的设计。 echo_server: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa…

内蒙古自治区关于加快充换电基础设施建规划 安科瑞 许敏

摘要&#xff1a;为深入贯彻落实《国务院办公厅关于印发新能源汽车产业发展规划&#xff08;2021—2035年&#xff09;的通知》&#xff08;国办发 ﹝2020﹞39号&#xff09;、《国家发展改革委等部门关于进一步提升电动汽车充电基础设施服务保障能力的实施意见》&#xff08;发…

异常值检验(t分布查表)、方差分析

异常值检验 T-test 参考&#xff1a;1.ttest和ttest2 区别 2. ttest在 matlab 3.T test分布表 单侧 方差分析&#xff08;ANOVA&#xff09; Def: 方差分析&#xff08;analysis of variance, ANOVA&#xff09;是一种统计检验&#xff0c;用于检验两组或更多组样本的均值是…

PRL:上海交大张文涛团队实现量子材料相关突破

来源&#xff1a;上海交通大学 近期&#xff0c;上海交通大学物理与天文学院张文涛研究组利用自行研制的高能量和高时间分辨率角分辨光电子能谱系统对量子材料1T-TiSe₂电子结构进行了超快激光操控研究。利用超快光激发与电荷密度波相有关的相干声子&#xff0c;引起晶格内原子…

高压放大器在微波光子雷达中的应用有哪些

微波光子雷达是一种新型的雷达技术&#xff0c;它利用微波和光子相结合的方式进行探测和成像。在微波光子雷达系统中&#xff0c;高压放大器作为一个关键的组件&#xff0c;主要用于对微波信号进行放大&#xff0c;以增强雷达系统的探测能力和成像精度。本文将详细介绍高压放大…

20230606夏新(Amoi)的4K显示器D320B2000的亮点检测

20230606夏新&#xff08;Amoi&#xff09;的4K显示器D320B2000的亮点检测 2023/6/7 0:14 https://item.jd.com/63690000655.html 夏新&#xff08;Amoi&#xff09;电脑显示器高清家用办公电竞吃鸡游戏液晶监控直播大屏便携显示屏幕 32英寸【直面 4k/144hz双模式 全面屏】黑 …

Linux内核文件写入流程

文本代码基于Linux 5.15 。 当用户层调用write 去做写入&#xff0c; linux 内核里面是如何处理的&#xff1f; 本文以exfat 为例&#xff0c; 讨论这个流程 入口函数 write 系统调用的定义如下&#xff1a; fs/read_write.c ssize_t ksys_write(unsigned int fd, const ch…

数据库期末复习(7.2)查询优化

查询优化的概述 商用数据库花了很多的资金投入到查询优化。 查询优化的分类 逻辑查询优化 物理查询优化 比逻辑查询计划多了怎么去执行的方式,为的是数据操作速度更快 逻辑查询优化的三种关键技术 在科学研究的道路上我们往往不是一帆风顺的,人的认识也是局限的,但是我…

SciencePub学术 | 计算机科学类重点SCIEI征稿中

SciencePub学术刊源推荐: 计算机科学类SCI&EI征稿中&#xff01;录用率高&#xff0c;自引率低&#xff0c;进展顺利。信息如下&#xff0c;录满为止&#xff1a; 一、期刊概况&#xff1a; 【期刊简介】IF&#xff1a;4.0-4.5↑&#xff0c; JCR 2区&#xff0c;中科院3区…

抖音seo源码·源代码搭建·支持二开(开源)系统

抖音seo源码&#xff0c;抖音seo系统&#xff0c;抖音搜索排名&#xff0c;源码系统开发 场景&#xff1a;公认的视频发布功能可是必备的&#xff0c;智能剪辑和智能客服更不用说&#xff0c;作为产品中粉丝转化的重要一环也是必不可少的 抖音seo源码开发&#xff0c;即抖音搜…

Firefox插件(拓展)开发

目录 0、一些概念 1、创建一个项目 2、创建内容脚本 3、将拓展临时添加到浏览器中进行测试 3-1、CtrlShiftA 或&#xff1a; 3-2、选择调试附加组件 3-3、选择临时加载附加组件 3-4、选择我们项目中的 manifest.json 文件打开 3-5、如果打开成功&#xff1a; 4、继续开…

【Java】深入理解Java虚拟机 | 垃圾收集器GC

《深入理解Java虚拟机》的阅读笔记——第三章 垃圾收集器与内存分配策略。 参考了JavaGuide网站的相关内容&#xff1a;https://javaguide.cn/ Q&#xff1a;哪些内存需要回收&#xff1f;什么时候回收&#xff1f;如何回收&#xff1f; 2 对象已死吗&#xff1f; 2.1 引用…

4种普遍的机器学习分类算法

朴素贝叶斯分类 朴素贝叶斯分类是基于贝叶斯定理与特征条件独立假设的分类方法&#xff0c;发源于古典数学理论&#xff0c;拥有稳定的数学基础和分类效率。它是一种十分简单的分类算法&#xff0c;当然简单并不一定不好用。通过对给出的待分类项求解各项类别的出现概率大小&a…

Linux驱动开发(使用I2C总线设备驱动模型编写AT24C02驱动程序)

文章目录 前言一、I2C总线设备驱动模型二、设备树编写三、驱动程序编写1.提供i2c_driver结构体变量并且注册2.注册file_operations结构体3.操作AT24C02 四、应用程序编写五、上机测试总结 前言 本篇文章将讲解如何使用I2C总线设备驱动模型编写AT24C02驱动程序。 一、I2C总线设…