Dts 里gpio的那些事儿

本文介绍了GPIO配置和调试过程中的关键步骤,包括DTS文件的正确配置、GPIO函数的使用方法以及通过debugfs查看GPIO状态等内容。同时,还详细阐述了SELinux权限问题的解决方法,包括如何通过修改SEPolicy文件来解决权限拒绝问题。

目录

项目背景

Gpio Debug

Selinux权限问题 标志性log 格式:


项目背景

   最近调试一个项目,在gpio,dts上闷逼了一把。搞了很多问题。

1. 添加Dts文件里GPIO,同时去掉相同的GPIO配置项,注意去掉要干净,否则会导致死机

         pio: pinctrl@1000b000 {
        compatible = "mediatek,pinctrl";
        reg = <0 0x1000b000 0 0x1000>;
        mediatek,pctl-regmap = <&syscfg_pctl_a>,
                       <&syscfg_pctl_lt>,
                       <&syscfg_pctl_lm>,
                       <&syscfg_pctl_lb>,
                       <&syscfg_pctl_bl>,
                       <&syscfg_pctl_bm>,
                       <&syscfg_pctl_rb>,
                       <&syscfg_pctl_rt>;

      sec_nfc_pin: sec-nfc {
        compatible = "sum,sec_nfc_pin";
    };

  &节点名字, &表示的意思是,取“引用字符对应的节点”

      &sec_nfc_pin {
    pinctrl-names = "default", "sec_pd_high", "sec_pd_low", "sec_wake_high", "sec_wake_low", "sec_irq_inpull";
    pinctrl-0 = <&sec_nfc_default>;
    pinctrl-1 = <&sec_nfc_pd_high>;
    pinctrl-2 = <&sec_nfc_pd_low>;
    pinctrl-3 = <&sec_nfc_wake_high>;
    pinctrl-4 = <&sec_nfc_wake_low>;
    pinctrl-5 = <&sec_nfc_irq_inpull>;
    status = "okay";
};

    中断Gpio方式

        #address-cells = <1>;
        #size-cells = <0>;
        status = "okay";

        sec-nfc@27 {
                compatible = "sec-nfc";
                reg = <0x27>;
                sec-nfc,ven-gpio = <&pio 10 0>;/*pw rst gpio_10*/
                sec-nfc,firm-gpio = <&pio 27 0>;/*wake gpio_12*/
                sec-nfc,irq-gpio = <&pio 12 0>;/*irq gpio_27*/
                sec-nfc,clk_req-gpio = <&pio 136 0>;/*gpio_136*/
        };

          sec_nfc_irq_inpull: state_sec_irq_inpull {

               pins_cmd_dat {

                  pins = <PINMUX_GPIO12__FUNC_GPIO12>;

                   input-enable;
                };

2, 使用GPIO函数

       共用设备Dts节点

              of_get_named_gpio(spi->dev.of_node,"nfc,irq-gpio", 0);

       独立gpio节点方式:

        node = of_find_compatible_node(NULL, NULL, "vendor,sec_nfc_pin");
        pdev = of_find_device_by_node(node);
        pinctrl_gpios = devm_pinctrl_get(&pdev->dev);

        pinctrl_lookup_state(pinctrl_gpios, "sec_power_high");

        pinctrl_select_state(pinctrl_gpios, pins_pd_high); // 输出高低电平,需要预先在dts里定义好

       irq_num = of_get_named_gpio_flags(np, "nfc,irq-gpio", 0, NULL);

       gpio_get_value(irq_num);     // 标准Linux系统调用函数,注意参数gpio的获取

       gpio_set_value()

      

GPIO函数另外一种使用组合

      gpio_request(pdata->ven, "nfc_wake");
      gpio_direction_output(pdata->ven,  NFC_PW_OFF);
      gpio_direction_input()

3、中断号获取和设置

        node = of_find_compatible_node(NULL, NULL, "mediatek,irq_nfc-eint"); // 通过DWS工具生成关联节点

        irq = irq_of_parse_and_map(node, 0);

        request_threaded_irq(client->irq, NULL, sec_nfc_irq_thread_fn,

Gpio Debug

  • 使用 mount -t debugfs debugfs /tmp 把debugfs挂接到/tmp下,再重新进入/tmp后就能看到一个名为gpio的文件
  • cat /tmp/gpio即可得到gpio的所有信息,使用完后umount /tmp卸载掉debugfs

of_get_named_gpio_flags 函数返回值: gpio组数 * gpio寄存器 size + 偏移

  例子:gpio3—A4   3 * 32 + 4 = 100

GPIOs 0-31, platform/pinctrl, gpio0:
 gpio-1   (                    |bt_default_reset    ) out lo    
 gpio-2   (                    |reset               ) out hi    
 gpio-5   (                    |GTP_INT_IRQ         ) in  lo    
 gpio-11  (                    |bt_default_wake_host) in  lo    
 gpio-12  (                    |GTP_RST_PORT        ) out hi    

GPIOs 32-63, platform/pinctrl, gpio1:
 gpio-51  (                    |bt_default_rts      ) in  hi    

GPIOs 64-95, platform/pinctrl, gpio2:
 gpio-72  (                    |bt_default_wake     ) in  hi    
 gpio-77  (                    |mdio-reset          ) out hi    

GPIOs 96-127, platform/pinctrl, gpio3:

查看 gpio 的状态
cat /sys/kernel/debug/gpio, 通过这个命令可以知道当前一些 GPIO 的状态, 确认和屏相关的 GPIO
是否有被正常设置。

Selinux权限问题 标志性log 格式:

avc: denied  { 操作权限 }  for pid=7201 comm=“进程名”  scontext=u:r:源类型:s0  tcontext=u:r:目标类型:s0  tclass=访问类别  permissive=0

   allow   scontext    tcontext tclass 

Kenel log:

avc: denied { execheap } for pid=7201 comm="com.baidu.input" scontext=u:r:untrusted_app:s0tcontext=u:r:untrusted_app:s0tclass=processpermissive=0

Logcat log:

com.baidu.input: type=1400audit(0.0:29): avc: denied { execheap } for scontext=u:r:untrusted_app:s0tcontext=u:r:untrusted_app:s0tclass=processpermissive=0

2. 在sepolicy中添加相应权限

2.1 修改依据:

log 信息:

avc: denied  { 操作权限  }  for pid=7201  comm=“进程名”  scontext=u:r:源类型:s0  tcontext=u:r:目标类型:s0  tclass=访问类别  permissive=0

2.2 修改步骤:

找相应的“源类型.te ”文件

有两个位置可能存在相应的te文件:

位置一:LINUX/android/external/sepolicy
位置二:LINUX/android/device/qcom/sepolicy/common 
 

2.3 按如下格式在该文件中添加: 

allow  源类型 目标类型:访问类别 {权限};

3. 添加权限后的neverallowed冲突

3.1 编译报错:

libsepol.check_assertion_helper: neverallow on line xxx ofexternal/sepolicy/domain.te ……

3.2 原因:

新添加的sepolicy项目违反了domain.te 中规定的的总策略原则。所以该条权限策略不能添加,如果强行添加的话有CTS测试失败的风险。

3.3 解决方法:

1.从运行log中找到要访问的目标名称,一般是name字段后的名称

avc: denied { read write } for pid=303 comm="mediaserver" name="tfa9890"dev="tmpfs" ino=3880 scontext=u:r:mediaserver:s0tcontext=u:object_r:device:s0tclass=chr_file permissive=0

2.找到相应的*_contexts文件。

  一般有file_contexts, genfs_contexts,  property_contexts,  service_contexts 等文件

3.在contexts文件中指定要访问的目标为一个“源类型 ”有权限访问的“目标类型”

  如:在file_contexts中添加: /dev/tfa9890     u:object_r:audio_device:s0


 

<think>我们正在处理一个关于内核设备树(DTS)解析GPIO编号的问题。根据用户的问题,他/她希望了解内核如何从设备树中解析GPIO编号。 根据引用[1],我们知道在内核初始化过程中,会调用`unflatten_device_tree()`函数将设备树数据转换为运行时表示。然后,会调用机器特定的设置钩子,如ARM架构上的`machine_desc`结构体中的`.init_early()`, `.init_irq()`和`.init_machine()`。设备树信息将在这些阶段被使用。 对于GPIO编号的解析,通常是在设备驱动程序初始化时,通过设备树节点获取GPIO信息。内核提供了一系列的API来从设备树节点中获取GPIO编号。 常见的步骤和API如下: 1. 在设备树中,GPIO通常使用`gpios`属性来描述。例如: ``` mydevice { compatible = "my,device"; gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; /* 表示使用gpio0控制器的第15个引脚,高电平有效 */ }; ``` 2. 在驱动程序中,首先需要使用`of_find_node_by_name()`或`of_find_compatible_node()`等函数找到设备树节点(通常驱动框架会自动处理,将节点传递给驱动的probe函数)。 3. 然后,使用`of_get_named_gpio()`函数从节点中获取GPIO编号。例如: ```c int gpio = of_get_named_gpio(node, "gpios", index); ``` 其中,`node`是设备树节点,`"gpios"`是属性名,`index`是属性中GPIO的索引(如果属性中有多个GPIO,则可以通过索引来获取)。 4. 获取到GPIO编号后,可以使用标准的GPIO函数如`gpio_request()`申请GPIO,`gpio_direction_output()`设置方向,`gpio_set_value()`设置值等。 需要注意的是,设备树中的GPIO编号是相对于该GPIO控制器的本地编号。但是,`of_get_named_gpio()`返回的是全局的GPIO编号(即系统中唯一的编号),这个编号可以直接用于后续的GPIO操作函数。 另外,在设备树中,GPIO还可以通过其他属性名指定,比如`enable-gpios`、`reset-gpios`等,这时在获取时就需要使用对应的属性名。 以上是基本的方法。不同版本的内核可能会有一些API的变化,但基本思路一致。 为了更详细地说明,我们可以参考内核源代码中相关的实现。例如,在`drivers/gpio/gpiolib-of.c`中,有`of_get_named_gpiod_flags`等函数,它是`of_get_named_gpio`的内部实现。 由于用户要求使用中文回答,并且要求结构清晰,我们将按照步骤解释。 总结步骤: 1. 设备树中定义GPIO属性。 2. 驱动中通过设备节点获取GPIO编号(使用`of_get_named_gpio`等函数)。 3. 使用获取到的GPIO编号进行后续操作。 注意:设备树中的GPIO属性需要按照指定的格式编写,通常包括phandle(指向GPIO控制器)、引脚号、标志(如有效电平)等。 下面我们生成相关问题。 </think>### 内核设备树(DTS)解析GPIO编号的方法 在内核中,设备树源文件(DTS)解析GPIO编号的过程主要发生在设备树转换为运行时数据结构后,通过专用的GPIO子系统API实现。以下是关键步骤: 1. **设备树初始化阶段** 内核启动时调用 `unflatten_device_tree()` 将DTS二进制数据(DTB)转换为可操作的`device_node`结构体[^1]。此时设备树节点信息已载入内存,但尚未与驱动绑定。 2. **GPIO属性定义规则** 在DTS文件中,GPIO引脚需按标准格式声明: ```dts device_node { gpios = <&gpio_controller 引脚编号 标志>; // 示例:<&gpio1 5 GPIO_ACTIVE_HIGH> }; ``` 其中: - `&gpio_controller`:指向GPIO控制器的phandle - `引脚编号`:控制器内的GPIO索引(如5表示GPIO1组的第5个引脚) - `标志`:电气特性标志(如`GPIO_ACTIVE_LOW`) 3. **驱动中的GPIO解析API** 驱动程序在初始化时(通常在`probe()`函数中)通过以下API获取GPIO: ```c #include <linux/gpio/consumer.h> int gpio_num = of_get_named_gpio(dev->of_node, "gpios", 0); // 或使用更安全的版本: struct gpio_desc *desc = gpiod_get(dev, "gpios", GPIOD_OUT_HIGH); ``` 关键函数: - `of_get_named_gpio()`:直接返回全局GPIO编号 - `gpiod_get()`:返回GPIO描述符(推荐方式) - 索引参数(如`0`)用于处理多GPIO属性(如`gpios[0]`, `gpios[1]`) 4. **编号映射机制** - GPIO子系统通过`gpiochip_add()`注册控制器时建立本地引脚与全局编号的映射 - 全局编号计算公式: $$ \text{全局编号} = \text{gpiochip.base} + \text{引脚索引} $$ - 可通过`/sys/kernel/debug/gpio`查看映射关系 5. **硬件关联流程** ```mermaid graph LR A[DTS文件] --> B[DTB编译] B --> C[unflatten_device_tree] C --> D[设备节点注册] D --> E[驱动GPIO API调用] E --> F[GPIO子系统映射] F --> G[硬件操作] ``` > **注意**:现代内核推荐使用`gpiod_*`API替代过时的`gpio_*`函数,因其支持更安全的引用计数和错误处理机制。实际编号解析依赖于架构特定的GPIO控制器驱动实现,如ARM平台通过`machine_desc.init_machine()`完成最终硬件绑定[^1]。 --- ### 相关问题 1. 如何在设备树中正确声明多个GPIO引脚? 2. GPIO全局编号与硬件引脚号的映射关系如何验证? 3. 设备树GPIO标志(如`GPIO_ACTIVE_LOW`)如何影响驱动代码逻辑? 4. 当GPIO控制器未初始化时,驱动获取GPIO会返回什么错误码? 5. 在ARM架构中,`machine_desc`结构体如何参与GPIO的初始化过程?[^1]
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值