转自:https://blog.csdn.net/qingzhuyuxian/article/details/82895416

最近安卓项目中想要获取内核cmdline特定的启动参数,因为我们在他的U-BOOT中定制了启动参数,需要在驱动中处理,这个手段其实很常见,今天mark个脚印。

内核中如果你用cat /proc/cmdline,你会看见大致如下的打印:

console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0...。当然如果我也可以在我们的项目比如扫描头的型号加个字段scanner=se955,等号赋值,name和value跟前后字段以空格分割。

那么如何从中获取呢?!

方法一:直接获取原始的cmdline的,就是获取/proc/cmdline属性值,在代码中就是读取全局变量saved_command_line这个字符串,然后自行处理,缺点是这个处理的时机比较晚,在设备驱动中处理,优点开发者自由度比较大。

方法二:利用内核的__setup或者early_param。这个两个函数宏实质上是一样的,就是early_param比__setup先处理,优点他们在内核启动阶段运行,都在设备驱动前预先运行。上定义代码,

  1.  
    #define __setup_param(str, unique_id, fn, early) /
  2.  
    static char __setup_str_##unique_id[] __initdata = str; /
  3.  
    static struct obs_kernel_param __setup_##unique_id /
  4.  
    __attribute_used__ /
  5.  
    __attribute__((__section__(".init.setup"))) /
  6.  
    __attribute__((aligned((sizeof(long))))) /
  7.  
    = { __setup_str_##unique_id, fn, early }
  8.  
     
  9.  
    #define __setup(str, fn) /
  10.  
    __setup_param(str, fn, fn, 0)
  11.  
     
  12.  
    #define early_param(str, fn) /
  13.  
    __setup_param(str, fn, fn, 1)

其中结构体定义如下:

struct obs_kernel_param {
const char *str;
int (*setup_func)(char *);
int early;
};
链接时以这个结构体保存在.init.setup段,实际在存储上就是个结构体数组。仔细看链接文件vmlinux.lds时,你会发现.init.setup实际上就是大致有这样的描述

__setup_start = .; 
*(.init.setup) 
__setup_end = .;

它的意思就是你所有定义的struct obs_kernel_param结构体变量连续序排在__setup_start 和__setup_end 存储之间,到时候就可以在这2个标记之间搜索。而__setup_start这个标记只被do_early_param和obsolete_checksetup。而这2个函数都是在kernel/init/main.c下的函数start_kernel中运行,并且do_early_param先运行,接着obsolete_checksetup后运行。调用大致流程如下start_kernel->parse_early_param->parse_early_options->parse_args->parse_one->do_early_param,而start_kernel->parse_args->parse_one->unknown_bootoption->obsolete_checksetup。翻代码代码中可见先调用__early_param定义的解析参数函数及__setup定义的(console及earlycon)的参数解析函数

接着再调用__setup定义的其他解析参数函数。

使用例子:

  1.  
    static int __init scanner_setup(char *str)
  2.  
    {
  3.  
    if (!str)
  4.  
    return 0;
  5.  
    if(!strcmp("se955",str)){
  6.  
    scanner_id = SCANNER_SE955;
  7.  
    }else if(!strcmp("ue966",str)){
  8.  
    scanner_id = SCANNER_UE966;
  9.  
    }else if(!strcmp("n4313",str)){
  10.  
    scanner_id = SCANNER_N4313;
  11.  
    }else if(!strcmp("n5600",str)){
  12.  
    scanner_id = SCANNER_N5600;
  13.  
    }else if(!strcmp("se655",str)){
  14.  
    scanner_id = SCANNER_SE655;
  15.  
    }else if(!strcmp("se4710",str)){
  16.  
    scanner_id = SCANNER_SE4710;
  17.  
    }else{
  18.  
    scanner_id = SCANNER_SE4500;
  19.  
    }
  20.  
    printk("%s %d\n",__func__,scanner_id);
  21.  
    return 1;
  22.  
    }
  23.  
    __setup("scanner=", scanner_setup);

该段代码对应于cmdline中的... scanner=se955 ...,这样的话,kernel已启动会先搜索scanner=字符串,如果找到的话就把=号后面的字符串值传递给给回调函数scanner_setup,这样的话str参数就是se955,并且这些代码是在设备驱动运行之前。

NOTE:我碰到的问题,如果同一个字段被比如scanner字段,__setup使用两次,__setup(“scanner=”,fun_1)和__setup(“scanner=”,fun_2)在2个文件中,那么只会有1个被使用,谁先被链接,谁运行,另一个失效,因为运行不到他,代码决定,只匹配第一个。

--------------------- 本文来自 sgmenghuo 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/sgmenghuo/article/details/41251739?utm_source=copy

linux驱动——cmdline原理及利用【转】的更多相关文章

  1. linux驱动程序设计的硬件基础,王明学learn

    linux驱动程序设计的硬件基础(一) 本章讲总结学习linux设备程序设计的硬件基础. 一.处理器 1.1通用处理器 通用处理器(GPP)并不针对特定的应用领域进行体系结构和指令集的优化,它们具有一 ...

  2. Linux驱动学习步骤(转载)

    1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ls ...

  3. Linux驱动开发学习的一些必要步骤

      1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ...

  4. linux驱动面试题2

    1.什么是GPIO? general purpose input/output GPIO是相对于芯片本身而言的,如某个管脚是芯片的GPIO脚,则该脚可作为输入或输出高或低电平使用,当然某个脚具有复用的 ...

  5. Linux驱动之触摸屏程序编写

    本篇博客分以下几部分讲解 1.介绍电阻式触摸屏的原理 2.介绍触摸屏驱动的框架(输入子系统) 3.介绍程序用到的结构体 4.介绍程序用到的函数 5.编写程序 6.测试程序 1.介绍电阻式触摸屏的原理 ...

  6. Linux驱动之LCD驱动编写

    在Linux驱动之内核自带的S3C2440的LCD驱动分析这篇博客中已经分析了编写LCD驱动的步骤,接下来就按照这个步骤来字尝试字节编写LCD驱动.用的LCD屏幕为tft屏,每个像素点为16bit.对 ...

  7. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  8. linux驱动工程面试必问知识点

    linux内核原理面试必问(由易到难) 简单型 1:linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 2:linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化, ...

  9. linux驱动面试题整理

    1.字符型驱动设备你是怎么创建设备文件的,就是/dev/下面的设备文件,供上层应用程序打开使用的文件? 答:mknod命令结合设备的主设备号和次设备号,可创建一个设备文件. 评:这只是其中一种方式,也 ...

随机推荐

  1. 牛客国庆训练 H.千万别用树套树

    链接https://ac.nowcoder.com/acm/contest/1108/H 国庆队内训练的题,当时还完全没思路,就没补.现在会树状数组了,倒是能想一想,不过网上题解好多用线段树传数组的? ...

  2. 前端小白webpack学习(四)

    .less文件与.scss文件使用与.css文件相仿 less-loader使用需要借助less插件,终端输入npm i less less-loader -D安装; sass-loader使用需要借 ...

  3. 05-深入python的set和dict

    一.深入python的set和dict 1.1.dict的abc继承关系 from collections.abc import Mapping,MutableMapping #dict属于mappi ...

  4. RabbitMQ 备份交换机(alternate-exchange)介绍

    RabbitMQ之备份交换机(alternate-exchange) 1.备份交换器,AlternateExchange(AE) 备份交换器是为了实现没有路由到队列的消息,声明交换机的时候添加属性al ...

  5. JQuery之Ajax基础

    众所周知JQuery中的Ajax主要用于数据传输,其数据传输格式为JSON格式数据,比XML格式数据传输更快. ajax 是 Asynchronous JavaScript and XML的简写,aj ...

  6. Spring Cloud系列:不重启eureka,清除down掉的服务

    场景描述 做项目的时候,我的服务改了个ip,然后重新启动后,原ip的服务down掉了,但是没有清楚掉,还在上面,导致我用swagger测试的时候,访问不到真正up的程序.重启eureka又不划算,于是 ...

  7. reports buileder 触发器的写法

    触发器写法: function CF_SHOULD_BACK_TIMEFormula return Number is--其他:取MES工时按工段分别统计产量.投入工时合计:应回报工时=移动数量*[∑ ...

  8. Windows系统Git安装教程(详解Git安装过程)

    Windows系统Git安装教程(详解Git安装过程)   今天更换电脑系统,需要重新安装Git,正好做个记录,希望对第一次使用的博友能有所帮助! 获取Git安装程序   到Git官网下载,网站地址: ...

  9. C# SendAysnc 超时

      业务方法 @@@code public override async Task<List<(IPEndPoint endPoint, byte[] data)>> Send ...

  10. find 常用命令

    系统中总会不断产生一些文件,比如日志文件,不一定会用到也不会自动删除,这时候就需要手动删除,当然也可以转存到其他目录下.不好找的时候可以用find模糊查找,加个job定时任务自动执行定期删除文件1.添 ...