【Linux驱动编程】向驱动传递参数

文章目录

  • 1 前言
  • 2 驱动传参
    • 2.1 驱动传参意义
    • 2.2 驱动传参不足
    • 2.3 驱动传参适用场合
  • 3 驱动传参实现
    • 3.1 基本类型
    • 3.2 数组类型
    • 3.3 字符串类型
    • 3.4 参数描述
  • 4 驱动传参实例


1 前言

  在开发linux相关应用程序时,为了使应用程序更加灵活地执行用户的预期功能,我们会通过main函数参数传递一些参数到程序中,代码逻辑处理块根据不同的参数执行不同的任务。类似地,linux内核提供驱动传参机制,编写驱动程序时只要实现传参接口,用户在加载驱动时即可以传入指定参数,使得驱动模块更加灵活。


2 驱动传参

2.1 驱动传参意义

  • 驱动程序更加灵活,可以向上可以适配复杂的应用程序,向下兼容不同硬件设备
  • 通过参数选择,省去重新编译驱动
  • 更好兼容迭代产品

2.2 驱动传参不足

  • 增加驱动资源占用,包括内存空间、存储空间

  • 驱动复杂化,非单一功能,增加冗余代码


2.3 驱动传参适用场合

  驱动传参一般用于工作状态、处理逻辑、运作模式在使用过程中可能改变的驱动模块中,一方面适配用户业务繁琐逻辑,另一方面兼容不同的硬件设备。典型的应用有如下的场景。

  • 依赖于总线设备的驱动模块,连接的总线序号(i2c、spi、uart)可能会改变
  • 屏幕驱动,适配不同分辨率的LCD屏
  • 由于硬件迭代,通过驱动传参使得驱动程序兼容新旧硬件设备
  • 一个视频信号驱动,PAL、NTSC制式选择

3 驱动传参实现

  内核支持的驱动传递参数类型包含了C语言中常用的数据类型

  • 基本类型,字符型(char)、布尔型(bool)、整型(int)、长整型(long)、短整型(short),以及相关的无符号整型(unsigned)、指针(point)
  • 数组(array)
  • 字符串(string)。

  实现驱动传参,只需在驱动程序中调用module_param系列宏即可,module_param系列宏位于“/include/linux/moduleparam.h”中定义,包括module_param_arraymodule_param_string

#define module_param(name, type, perm)				\
	module_param_named(name, name, type, perm)

#define module_param_array(name, type, nump, perm)		\
	module_param_array_named(name, name, type, nump, perm)

#define module_param_string(name, string, len, perm)			\
	static const struct kparam_string __param_string_##name		\
		= { len, string };					\
	__module_param_call(MODULE_PARAM_PREFIX, name,			\
			    ¶m_ops_string,				\
			    .str = &__param_string_##name, perm, -1, 0);\
	__MODULE_PARM_TYPE(name, "string")

  module_param用于处理基本类型参数,module_param_array用于处理数组类型参数,module_param_string用于处理字符串类型参数。


3.1 基本类型

module_param(name, type, perm)
  • name,驱动程序中变量名称,同时又是用户传入参数时的名称
  • type,参数类型
  • perm,该参数指定sysfs访问权限,位于"/include/linux/stat.h"定义,一般使用S_IRUGO;也可以直接用数字表示,如0444表示S_IRUGO
/* include/linux/stat.h */
#define S_IRWXUGO	(S_IRWXU|S_IRWXG|S_IRWXO)	/* 所有用户可读、写、执行 */
#define S_IALLUGO	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)/* 所有用户可读、写、执行*/
#define S_IRUGO		(S_IRUSR|S_IRGRP|S_IROTH)	/* 所有用户可读 */
#define S_IWUGO		(S_IWUSR|S_IWGRP|S_IWOTH)	/* 所有用户可写 */
#define S_IXUGO		(S_IXUSR|S_IXGRP|S_IXOTH)	/* 所有用户可执行 */

/* include/uapi/linux/stat.h */
/* 三者分别表示用于者权限、用户组权限、其他访问者权限 
* bit[0]、bit[1]、bit[2]分别表示可执行、可写、可读属性
*/
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100

#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
 
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001

示例:

static int mode = 0;
static char *p = NULL;

module_param(mode, int , S_IRUGO);	/* int型 */   
module_param(p, charp, S_IRUGO);	/* 指针 */

3.2 数组类型

module_param_array(name, type, nump, perm)
  • name,驱动程序中数组名称,同时又是用户传入参数时的名称
  • type,数组类型,int、char等
  • nump,数组存储大小
  • perm,该参数指定sysfs访问权限,位于"/include/linux/stat.h"定义,一般使用S_IRUGO;也可以直接用数字表示,如0444表示S_IRUGO

示例:

static int array[3] = {0};
static int array_size = 5;

module_param_array(array, int, &array_size, S_IRUGO);

3.3 字符串类型

module_param_string(name, string, len, perm)
  • name,用户传入参数时的名称,可以与驱动程序中变量名称string相同
  • string,驱动程序中变量名称
  • len,缓存大小
  • perm,该参数指定sysfs访问权限,位于"/include/linux/stat.h"定义,一般使用S_IRUGO;也可以直接用数字表示,如0444表示S_IRUGO

示例:

static char string[6] = {0};

module_param_string(usestr, string, sizeof(string), S_IRUGO);

3.4 参数描述

  用户向驱动模块传递参数时,参数较多的情况下,应用开发工程师不易记住;因此,一般都会增加准确、清晰的参数描述信息,描述不同参数代表的含义,用户调用时首先查询驱动模块的参数描叙信息,进而有目的地传入具体参数。参数描述信息通过MODULE_PARM_DESC宏实现,该宏位于“/include/linux/moduleparam.h”中定义

#define MODULE_PARM_DESC(_parm, desc) \
	__MODULE_INFO(parm, _parm, #_parm ":" desc)
  • _parm,参数名称
  • desc,描述信息,字符串类型

示例:

static int mode = 0;

module_param(mode, int , S_IRUGO);
MODULE_PARM_DESC(mode, "0:mode0; 1:mode1; 2:mode2");

4 驱动传参实例

  编写一个基本的linux驱动,实现用户往驱动传递参数的功能,加载驱动时传入指定参数。


驱动源码:

#include 
#include 
#include 
#include 
#include 

static int mode = 0;
static char *p = NULL;
static int array[3] = {0};
static int array_size = 5;
static char string[6] = {0};

/* 驱动传递参数一般放置于程序开头处,但也有放置于程序结尾处 */
module_param(mode, int , S_IRUGO);	/* 整型 */
MODULE_PARM_DESC(mode, "0:mode0; 1:mode1; 2:mode2");
   
module_param(p, charp, S_IRUGO);	/* 指针 */
MODULE_PARM_DESC(p, "pointer select:i2c0; i2c1; i2c2");
   
module_param_array(array, int, &array_size, S_IRUGO);/* 数组 */
MODULE_PARM_DESC(array, "set array value");
   
module_param_string(usestr, string, sizeof(string), S_IRUGO);/* 字符串 */
MODULE_PARM_DESC(usestr, "string select:spi00; spi01; spi10");
  
static int __init base_init(void)
{
	int i = 0;
  
	printk("base driver init\n");
	printk("mode: %d\n", mode);
	printk("p: %s\n", p);
 	for(i = 0; i < array_size; i++)
	{
		printk("array[%d]:%d\n", i, array[i]);
	}
	printk("string: %s\n", string);
  
	return 0;
}

static void __exit base_exit(void)
{

}
  
module_init(base_init);
module_exit(base_exit);
MODULE_LICENSE("GPL");


Makefile文件:

ifeq ($(KERNELRELEASE),)

KERNELDIR = /usr/src/linux-headers-4.15.0-107-generic
PWD := $(shell pwd)

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
	rm -rf *.o *.ko .mod.o *.mod.c *.symvers

else
	obj-m := base.o
endif


编译并执行测试:

  • 查看驱动模块信息

  执行"modinfo base.ko"查看驱动模块信息,可看到我们在驱动程序中添加的参数,以及参数描述信息。

root@ubuntu:/mnt/hgfs/LSW/STHB/drivers64/base# modinfo base.ko
filename:       /mnt/hgfs/LSW/STHB/drivers64/base/base.ko
license:        GPL
srcversion:     4219F31AD24A00B43DC97BC
depends:        
retpoline:      Y
name:           base
vermagic:       4.15.0-107-generic SMP mod_unload 
parm:           mode:0:mode0; 1:mode1; 2:mode2 (int)
parm:           p:pointer select:i2c0; i2c1; i2c2 (charp)
parm:           array:set array value (array of int)
parm:           usestr:string select:spi00; spi01; spi10 (string)


  • 加载驱动

  加载驱动同时指定传递参数;内核默认是不开启将printk信息输出到终端,可以执行"dmesg -c"将驱动程序的printk信息输出到终端;如果开启了内核打印等级,加载驱动后会立即输出参数信息。

root@ubuntu:/mnt/hgfs/LSW/STHB/drivers64/base# insmod base.ko mode=1 p="i2c0" array=1,2,3 usestr="spi00"
root@ubuntu:/mnt/hgfs/LSW/STHB/drivers64/base# dmesg -c
[  378.047187] base driver init
[  378.047188] mode: 1
[  378.047188] p: i2c0
[  378.047188] array[0]:1
[  378.047189] array[1]:2
[  378.047189] array[2]:3
[  378.047189] string: spi00

你可能感兴趣的:(Linux驱动编程,linux驱动,驱动传递参数)