day47-驱动简介

day47-驱动简介

一、驱动简介

  在Linux中,驱动是一种特殊的程序,它允许操作系统与硬件设备进行交互。驱动程序通常在内核空间运行,这是因为它们需要执行一些只能在内核空间进行的操作,如直接访问硬件或使用特权指令。

  在Linux中,驱动程序通常被实现为内核模块。内核模块是一种可在运行时加载或卸载的代码,它们不是内核的固定部分,这提供了更大的灵活性。例如,如果你添加了一个新的硬件设备,只需要加载相应的驱动模块就可以使用它,而不需要重新编译整个内核。




二、驱动模块

  在Linux系统中,驱动程序通常被设计成内核模块的形式。一个内核模块是内核的一部分,它在系统启动时并不立即加载。只有在需要时,模块才会被动态加载到内核中;不再需要时,它们可以被卸载。这种机制提供了很大的灵活性和效率。

  驱动模块,就是作为内核模块的设备驱动。它们是用来管理和控制硬件设备的程序。例如,你的系统可能有一个用于管理你的网络接口卡的驱动模块,当你的系统启动时,这个模块会被加载到内核中,以便系统可以使用网络接口卡。

模块和应用程序的区别:
| | 应用程序 | 内核模块 |
| ———- | —————— | —————————- |
| 运行空间 | 用户空间 | 内核空间 |
| 访问权限 | 有限 | 完全 |
| 功能 | 执行特定任务 | 扩展内核功能 |
| 依赖 | 操作系统API | 内核API |
| 加载和卸载 | 通过用户启动和结束 | 可在系统运行时动态加载和卸载 |
| 错误处理 | 可以捕获并处理错误 | 错误可能导致整个系统崩溃 |

2.1 驱动模块编程

模块形式

驱动模块编程需要两个东西:.c和makefile
.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//1. 头文件
#include <linux/init.h>
#include <linux/module.h>

char *name = "ZhangSan";
int age = 20;
module_param(name, charp, 0);
module_param(age, int, 0);

//2. 加载函数与卸载函数的定义
static int mymod_init(void)
{
printk("Mymod init ok!\n");
printk("name = %s, age = %d\n", name, age);

return 0;
}

static void mymod_exit(void)
{
printk("Mymod exit ok!\n");
}

//3. 声明加载与卸载函数
module_init(mymod_init);
module_exit(mymod_exit);

//4. 模块信息
MODULE_LICENSE("GPL"); //许可证
MODULE_AUTHOR("LiuJ"); //作者
MODULE_DESCRIPTION("A sample test module!"); //描述

makefile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
KERNEL_DIR = /home/hqyj/Liuj/230301/linux-3.14   #内核源码路径
CUR_DIR = $(shell pwd) #当前路径

ifeq ($(KERNELRELEASE), )

all:
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules 用内核源码的makefile进行编译

clean:
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean

install:
cp *.ko /source/nfs/rootfs #将编译生成的.ko模块文件复制到指定的目录。

else

obj-m = module.o

endif

获得的.ko通过nfs挂载到板子上,通过指令进行加载和卸载:

lsmod:显示已加载模块
insmod *.ko:加载模块
rmmod *:卸载模块

模块参数

头文件下面使用下面的函数:

module_param(参数名,类型,权限);

在板子上加载时要输入对应参数:

insmod 模块 参数1=val1 参数2=val2

模块符号

EXPORT_SYMBOL(符号)

在Linux内核编程中,通常情况下一个内核模块不能直接访问另一个内核模块中定义的函数或者变量。但有时候,一个内核模块需要使用另一个内核模块提供的功能。为了实现这个目的,内核提供了EXPORT_SYMBOL和EXPORT_SYMBOL_GPL两个宏来导出函数或变量。

当一个内核模块使用EXPORT_SYMBOL或EXPORT_SYMBOL_GPL宏导出一个函数或变量时,其他的内核模块就可以使用extern关键字来声明并使用这个函数或变量。例如:

// 在module1中
void module1_func(void) {
    // ...
}

EXPORT_SYMBOL(module1_func);



// 在module2中
extern void module1_func(void);

void module2_func(void) {
    module1_func();
}

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2020-2024 nakano-mahiro
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信