内核模块module传参

linux 2.6允许用户insmod的时候往内核模块里面传递参数,它主要使用module_param宏定义来实现这一功能。

参数应用

module_param(name, type, perm);
module_param(参数名,参数类型,参数读写权限)

举例:

static int howmany=1;
module_param(howmany, int, 0);

在装载内核模块时,用户可以向模块传递参数,形式为:

insmod/modprobe 模块名 参数名=参数值

如果不传递,参数将使用模块内定义的缺省值。如果模块被内置,就无法insmod了,但bootloader可以通过在bootargs里设置

模块名.参数名=值

给该内置的模块传递参数。

参数类型

参数的类型可以是byte,short,ushort, int, uint, long, ulong, charp, bool或invbool(布尔的反)

除此之外,内核模块还支持参数数组:

module_param_array(数组名,数组类型,数组长,参数读写权限)

insmod时使用逗号分割数组元素。

参数目录

模块被加载后,在/sys/module/目录下将出现以此模块命名的目录。

当读写权限为0时,表示此参数不存在sysfs文件系统下对应的文件节点,如果此模块存在参数读写权限不为0的命令行参数,在此模块的目录下还将出现parameters目录,

其中包含一系列以参数名命名的文件节点,这些文件的权限值就是传入module_param()的参数的读写权限,而文件的内容为参数的值。

示例

// led.c
//********************************
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/io.h>

MODULE_LISENCE("GPL");
MODULE_AUTHOR("limingth");
MODULE_DESCRIPTION("led module driver");
MODULE_VERSION("version1.0");
MODULE_ALIAS("myled test");

static int *vmem;
static int led_no = 0;
module_param(led_no, int, 0);

static __init int led_init(void)
{
    printk("led init ok!\n");
    vmem = ioremap(0xe0200284, 4);
    printk("vmem = %p\n");
    *vmem &=  ~(1<<led_no);
    return 0;
}

static __exit led_exit(void)
{
    printk("led exit ok!\n");
    *vmem = 0xf;
    
    return ;
}

module_init(led_init);
module_exit(led_exit);
//*************************************
应用:
insmod led.ko led_no=1
rmmod led

注:在操作系统下,所有的地址均为虚拟地址,所以物理地址需要通过ioremap或mmap函数将物理地址转换为虚拟地址后,再对地址操作。

 

<think>问题:内核模块中,如果数组的第一维是枚举类型,第二维是宏(由Makefile传参),编译时报错“arraytypehasincompleteelementtype”,如何解决?原因分析:这个错误通常发生在数组元素的类型不完整时。当数组的第一维是枚举类型,而该枚举类型可能没有被完整定义(例如,在数组声明的位置,枚举类型只是前向声明而没有完整定义),或者数组的第二维大小(由宏定义)在编译时不可知(尽管宏在Makefile中传递,但可能由于包含关系导致编译器看不到宏的定义)。解决方案:1.确保枚举类型在数组声明之前已经完整定义。2.确保用于数组维度的宏在数组声明之前已经被定义,并且是一个整型常量。具体步骤:###步骤1:确保枚举类型完整定义在声明数组之前,确保枚举类型已经被完整定义。例如:```c//正确:在数组声明之前完整定义枚举enummy_enum{ENUM_VALUE1,ENUM_VALUE2,ENUM_MAX};//使用枚举作为第一维,宏作为第二维的数组intmy_array[ENUM_MAX][CONFIG_DIM];```###步骤2:确保宏在数组声明之前可见在Makefile中传递的宏(例如CONFIG_DIM)必须在数组声明之前被编译器知道。通常,在编译内核模块时,通过Makefile的`ccflags-y`传递宏定义:```makefileccflags-y:=-DCONFIG_DIM=10```在C代码中,确保在包含头文件之前或者数组声明之前,这个宏已经被定义。如果数组声明在头文件中,那么包含该头文件的源文件必须能够看到这个宏定义。###步骤3:避免在头文件中直接使用宏定义数组如果数组声明在头文件中,而宏定义在源文件中(通过Makefile传递),那么头文件可能看不到宏的定义。解决方法:-将数组声明放在源文件中,而不是头文件中。-或者在头文件中使用extern声明,在源文件中定义数组。###示例代码假设我们有一个枚举类型和一个二维数组,数组的第一维是枚举的大小,第二维是Makefile传递的宏CONFIG_DIM。**module.c**```c#include<linux/module.h>#include<linux/kernel.h>//定义枚举enummy_enum{ENUM_VAL0,ENUM_VAL1,ENUM_VAL2,ENUM_MAX//表示枚举元素个数};//声明数组,第二维使用宏CONFIG_DIM(由Makefile传递)intmy_array[ENUM_MAX][CONFIG_DIM];staticint__initmy_module_init(void){inti,j;for(i=0;i<ENUM_MAX;i++){for(j=0;j<CONFIG_DIM;j++){my_array[i][j]=i*j;}}pr_info("Moduleloaded\n");return0;}staticvoid__exitmy_module_exit(void){pr_info("Moduleunloaded\n");}module_init(my_module_init);module_exit(my_module_exit);MODULE_LICENSE("GPL");```**Makefile**```makefileobj-m:=module.oCONFIG_DIM?=5#默认值,可以在命令行覆盖ccflags-y:=-DCONFIG_DIM=$(CONFIG_DIM)all:make-C/lib/modules/$(shelluname-r)/buildM=$(PWD)modulesclean:make-C/lib/modules/$(shelluname-r)/buildM=$(PWD)clean```###解释1.**枚举类型**:在数组声明之前,枚举类型`my_enum`被完整定义,并且`ENUM_MAX`表示枚举元素的个数。2.**宏定义**:在Makefile中,我们使用`ccflags-y`将`CONFIG_DIM`作为宏定义传递给编译器。这样在编译`module.c`时,`CONFIG_DIM`会被替换为具体的值(例如5)。3.**数组声明**:数组`my_array`的声明中,第一维使用枚举常量`ENUM_MAX`(编译时已知),第二维使用宏`CONFIG_DIM`(在编译前由Makefile传递,因此也是编译时常量)。###可能遇到的问题及解决1.**头文件问题**:如果数组声明在头文件中,而该头文件被多个源文件包含,那么每个源文件在编译时都必须知道`CONFIG_DIM`的值。确保在编译每个源文件时,`CONFIG_DIM`都被正确定义(通过Makefile传递)。2.**宏未定义**:如果编译时出现`CONFIG_DIM`未定义的错误,检查Makefile是否正确传递了宏定义,并确保在数组声明之前没有#undefCONFIG_DIM。3.**枚举定义位置**:确保枚举定义在数组声明之前,且在同一作用域可见。###替代方案:使用指针数组如果第二维的大小在编译时无法确定(例如,需要运行时确定),那么可以考虑使用指针数组,并在模块初始化时动态分配内存。```cenummy_enum{ENUM_VAL0,ENUM_VAL1,ENUM_VAL2,ENUM_MAX};int*my_array[ENUM_MAX];//指针数组staticint__initmy_module_init(void){inti,j;for(i=0;i<ENUM_MAX;i++){my_array[i]=kmalloc(sizeof(int)*config_dim,GFP_KERNEL);if(!my_array[i]){//错误处理gotofail;}for(j=0;j<config_dim;j++){my_array[i][j]=i*j;}}return0;fail:while(i-->0){kfree(my_array[i]);}return-ENOMEM;}```###总结解决“arraytypehasincompleteelementtype”错误的关键是确保数组元素类型和数组维度在声明时都是完整的。对于枚举类型,确保其已经定义;对于宏定义的维度,确保宏在编译时可见且为常量。§§相关问题§§:1.如何在Linux内核模块中动态分配二维数组?2.枚举类型在C语言中是如何存储的?枚举常量是整数吗?3.Makefile如何传递多个宏定义给内核模块?4.在内核模块中,如何实现运行时可变的数组大小?</think>### 解决内核模块中枚举数组与宏组合的编译错误 当在内核模块中使用枚举作为数组第一维、宏定义作为第二维时,可能会遇到"array type has incomplete element type"错误。这是因为编译器无法在编译时确定枚举的实际大小或宏定义的值未被正确传递。 #### 问题分析 错误通常由以下原因引起: 1. **枚举未完全定义**:在数组声明位置编译器看不到完整的枚举定义 2. **宏未正确定义**:Makefile传递的宏未被正确解析 3. **作用域问题**:数组声明位置无法访问枚举和宏定义 4. **类型完整性**:编译器无法确定枚举类型的大小 #### 解决方案 ##### 1. 确保枚举完整定义在数组声明之前 ```c // 在数组声明之前完整定义枚举 enum sensor_type { TEMPERATURE, HUMIDITY, PRESSURE, LIGHT, SENSOR_COUNT // 明确枚举项数量 }; // 使用宏定义第二维 int sensor_data[SENSOR_COUNT][CONFIG_DATA_POINTS]; ``` ##### 2. 正确传递宏定义(Makefile配置) ```makefile # 确保传递正确的宏定义 CONFIG_DATA_POINTS ?= 64 # 默认值 ccflags-y := -DCONFIG_DATA_POINTS=$(CONFIG_DATA_POINTS) obj-m += my_module.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules ``` ##### 3. 使用静态断言验证枚举大小 ```c #include <linux/build_bug.h> enum sensor_type { TEMPERATURE, HUMIDITY, PRESSURE, LIGHT, SENSOR_COUNT }; // 确保枚举大小在编译时已知 static_assert(SENSOR_COUNT > 0, "SENSOR_COUNT must be positive"); int sensor_data[SENSOR_COUNT][CONFIG_DATA_POINTS]; ``` ##### 4. 完整内核模块示例 **my_module.c** ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/build_bug.h> // 完整定义枚举 enum sensor_type { TEMPERATURE, // 0 HUMIDITY, // 1 PRESSURE, // 2 LIGHT, // 3 SENSOR_COUNT // 4 - 表示传感器类型数量 }; // 使用Makefile传递的宏定义第二维 int sensor_readings[SENSOR_COUNT][CONFIG_DATA_POINTS]; static int __init sensor_module_init(void) { int i, j; // 静态断言确保数组维度有效 BUILD_BUG_ON(SENSOR_COUNT <= 0); BUILD_BUG_ON(CONFIG_DATA_POINTS <= 0); pr_info("Sensor module loaded\n"); pr_info("Array dimensions: %d x %d\n", SENSOR_COUNT, CONFIG_DATA_POINTS); // 初始化数组 for (i = 0; i < SENSOR_COUNT; i++) { for (j = 0; j < CONFIG_DATA_POINTS; j++) { sensor_readings[i][j] = i * 100 + j; } } // 示例:访问温度传感器的第5个数据点 pr_info("Temperature[5] = %d\n", sensor_readings[TEMPERATURE][5]); return 0; } static void __exit sensor_module_exit(void) { pr_info("Sensor module unloaded\n"); } module_init(sensor_module_init); module_exit(sensor_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); ``` ##### 5. 使用typedef增强可读性 ```c typedef enum { TEMPERATURE, HUMIDITY, PRESSURE, LIGHT, SENSOR_COUNT } sensor_t; // 数组声明更清晰 static int sensor_data[SENSOR_COUNT][CONFIG_DATA_POINTS]; ``` #### 关键注意事项 1. **枚举完整性**: - 在数组声明前完整定义枚举 - 包含明确的计数项(如`SENSOR_COUNT`) - 避免在头文件中部分定义 2. **宏传递**: - 使用`ccflags-y`正确传递宏 - 在Makefile中设置默认值(`?=`) - 在代码中使用`#ifdef`检查宏是否定义 3. **静态验证**: - 使用`static_assert`或`BUILD_BUG_ON`验证维度 - 确保维度值大于0 - 在运行时检查数组边界 4. **作用域管理**: - 将枚举定义放在头文件中(如果需要共享) - 使用`extern`声明全局数组 - 避免在头文件中定义大型数组 #### 替代方案:使用指针数组 如果维度在编译时无法确定,考虑动态分配: ```c enum sensor_type { /* ... */ }; int **sensor_data; // 二维指针 static int __init module_init(void) { sensor_data = kmalloc_array(SENSOR_COUNT, sizeof(int *), GFP_KERNEL); for (int i = 0; i < SENSOR_COUNT; i++) { sensor_data[i] = kmalloc_array(CONFIG_DATA_POINTS, sizeof(int), GFP_KERNEL); } // ... } ``` ### 总结 解决此问题的关键在于: 1. 确保枚举类型完整定义且包含明确的计数项 2. 正确通过Makefile传递宏定义 3. 使用静态断言验证数组维度 4. 在代码中合理组织声明顺序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值