Chinaunix首页 | 论坛 | 博客
  • 博客访问: 291135
  • 博文数量: 65
  • 博客积分: 1490
  • 博客等级: 上尉
  • 技术积分: 835
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-16 20:00
文章分类

全部博文(65)

文章存档

2015年(1)

2012年(3)

2010年(7)

2009年(54)

我的朋友

分类: LINUX

2009-08-31 19:43:44

 

      

在驱动开发的过程中,有时为了调试方便,需要给驱动传入参数。下面就简单说明,如何给驱动传递参数和驱动如何使用参数。

驱动可以编译成模块,在需要时加载;也可以编译进内核,和内核一起加载。

 

可以在驱动中定义如下的宏:(#include

module_param(name, type, perm)

name是变量名;type是变量类型(bool,charp,int等);perm是访问许可值,当perm=0时,不会在sysfs系统中生成相应的sysfs入口项;perm=S_IRUGO为对任何人只读;S_IRUGO|S_IWUSR为允许root用户修改参数。

例如:

static int max_loop;

module_param(max_loop, int, 0);

int loop(void)

{

int i=0;

for(i=0;i

  printk(“In loop!\n”);

return 0;

}

使用方法:

#insmod   test.ko   max_loop=10

 

这时,max_loop可以在内核启动时传入,驱动中实现时使用__setup宏。

__setup(str, fn)

str为传递参数时使用的字符串,fn是参数传递后对应的处理函数。

例如:

#ifndef MODULE

static int __init max_loop_setup(char *str)

{

       max_loop = simple_strtol(str, NULL, 0);

       return 1;

}

__setup("max_loop=", max_loop_setup);

#endif

x86grub(/boot/grub/menu.lst)中使用方法:

kernel   /vmlinuz-2.6.30.5  ro  root=/dev/sda1  max_loop=10

目前已有的内核启动参数可以在此文件查找:documentation/kernel-parameters.txt

 

__setup实现概述

module_param宏在头文件include/linux/moduleparam.h中定义,调用顺序如下:

module_paramàmodule_param_namedà module_param_callà__module_param_call(MODULE_PARAM_PREFIX,…)

最后,把用此宏定义的参数放在__param段中:__section__ ("__param")

__param段参数的读取,涉及到内核加载模块原理。在用户空间执行insmod命令来加载模块时,会调用glibc(uClibc)库中的init_module系统调用,并把系统调用号传递给内核,内核根据此系统调用号,到硬件相关的一个系统调用表中找到此offset的函数并执行。

 

对于__setup宏,在头文件include/linux/init.h中定义,最后把用此宏定义的参数放到.init.setup段中。

.init.setup段的读取在do_early_param函数中,实现如下:

static int __init do_early_param(char *param, char *val)

{

       struct obs_kernel_param *p;

       for (p = __setup_start; p < __setup_end; p++) {

//.init.setup段开始处__setup_start读取

              if ((p->early && strcmp(param, p->str) == 0) ||

                  (strcmp(param, "console") == 0 &&

                   strcmp(p->str, "earlycon") == 0)

              ) {

                     if (p->setup_func(val) != 0)

//调用__setup(str, fn)中指定的fn函数, val是从内核启动传入的参数值

                            printk(KERN_WARNING

                                   "Malformed early option '%s'\n", param);

              }

       }

       return 0;

}

调用顺序是:start_kernelàparse_early_paramàparse_early_optionsàdo_early_param

具体地说,首先,parse_early_param把传递给内核的命令行参数,复制到一个临时变量tmp_cmdline中,然后传递给parse_early_options处理如下:

void __init parse_early_param(void)

{

       strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);

       parse_early_options(tmp_cmdline);

}

parse_early_options调用parse_argsparse_args把类似“max_loop=10之类传给内核的字符分解为字符串”max_loop”10”,然后传递给parse_oneparse_one最后调用do_early_param

do_early_paramparam, val的处理上面已经说过了。

 

/*

*By Neil Chiao ()

*转载请注明出处:neilengineer.cublog.cn

*

*/

阅读(2246) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~