Android input gpio driver手动对焦

通过按键中断驱动输入来调整马达的远近距离,加深对Input子系统的印象

整体流程

Input Kernel流程
Input Framewor流程

(1)具体的输入设备device(按键、鼠标等),通过input_event上报(input_event->input_handle_event->input_pass_values)
(2)input-core evdev事件驱动从各client(上述device)取buffer,(input_to_handler-> handler->events->evdev_events)
(3)framework中input主要的模块有InputReader::loopOnce -> EventHub::getEvents(event->code = iev.code) ->  
   processEventsLocked -> InputDevice::process ->  mapper.process(CursorButtonAccumulator.cpp)

Kernel驱动层

Linux内核原生就有功能强大的gpio-keys.c,中断上报等功能,所以仅需要适配dtsi

&soc {
        gpio_keys {
                status = "okay";
                compatible = "gpio-keys";
                input-name = "gpio-keys";
                label = "gpio-keys";
                pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
                pinctrl-0 = <&gpio_key_active>;
                pinctrl-1 = <&gpio_key_suspend>;

                af_far {
                        label = "af_far";
                        gpios = <&tlmm 85 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;  // EVENT TYPE 1: EV_KEY  ↓↓↓
                        linux,code = <259>;      // input子系统定义的按键功能 
                        debounce-interval = <1>; // 按键去抖时间
                        wakeup-source;           // 保持唤醒,开机键
                };

                af_near {
                        label = "af_near";
                        gpios = <&tlmm 96 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <260>;
                        debounce-interval = <11>;
                        wakeup-source;
                };
        };
};

gpio-keys解析dtsi的部分就很常规,主要是中断触发上报code的(很多usb设备也都有input_event的操作),不同的code对应不同的功能,有键盘的输入按钮(KEY_Q),有功能键(KEY_WAKEUP)等,

kernel/msm-4.19/drivers/input/keyboard/gpio_keys.c
#define AF_FAR     259
#define AF_NEAR    260

static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata){

    pr_err("jerry get the button->code = %d",button->code);
    if (button->code == AF_FAR || button->code == AF_NEAR){
        input_event(input, type, button->code, !!state); //input_event很重要
        input_sync(input);
    }


#include <uapi/linux/input-event-codes.h>

  #define KEY_RESERVED  0
  #define KEY_Q			16
  #define KEY_W			17
  #define KEY_WAKEUP	143
  
  #define EV_SYN		0x00
  #define EV_KEY		0x01
  #define EV_REL		0x02
  #define EV_ABS		0x03
  ...

Framework 应用层

framework层可以获取节点events中的buffer做处理,包括Input输入鼠标设备的左键右键的功能可以remap未其他function(例如返回)
当然如果是非Android系统,也同样可以通过read 节点"dev/input/event3"获取buffer,解析code/type/value

int position = 512;
#define AF_FAR     259
#define AF_NEAR    260
#define AF_PATH "/sys/devices/platform/soc/5c1b000.qcom,cci0/5c1b000.qcom,cci0:qcom,actuator0/position"

void moveLens(int value){

    int fd = ::open(AF_PATH, O_RDWR);
    if(fd < 0) {
        ALOGE("%s: failed to open %s: %s", __func__, AF_PATH, ::strerror(errno));
        return;
    }
    char buf[8];
    position += value;
    ALOGE("jerry position = %d",position);
    if(position > 1023) {
        position = 1023;
    }else if(position < 0){
        position = 0;
    }
    ::snprintf(buf, 8, "%d", position);
    ::write(fd, buf, strlen(buf));
    ::close(fd);

    return;

}

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    int32_t code = rawEvent->code;

    if(code == AF_FAR){
        moveLens(50);
    }else if(code == AF_NEAR){
        moveLens(-50);
    }

这玩意在正常的Camera Preview的情况下,由于Auto Focus和PDAF的原因,调整Lens 距离会被自动拉回来,在ProMode中的Manual下通过按键调整Lens距离,现象比较明显,会有失焦和恢复定焦的情况。

权限问题与日志

InputReader: moveLens: failed to open /sys/devices/platform/soc/5c1b000.qcom,cci0/5c1b000.qcom,cci0:qcom,actuator0/position: Permission denied

cd /sys/devices/platform/soc/5c1b000.qcom,cci0/5c1b000.qcom,cci0:qcom,actuator0
chmod 660 position

InputReader: type=1400 audit(0.0:3378): avc: denied { read write } for name="position" dev="sysfs" ino=55513 scontext=u:r:system_server:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=0
adb shell setenforce 0 


adb shell getevent
add device 6: /dev/input/event3                                                                                           
name:     "gpio-keys"
/dev/input/event3: 0001 0103 00000001    //input_event type code value                                                                               
/dev/input/event3: 0000 0000 00000000    //input_sync                                                                               
/dev/input/event3: 0001 0103 00000000                                                                                   
/dev/input/event3: 0000 0000 00000000                                                                                   
/dev/input/event3: 0001 0104 00000001                                                                                   
/dev/input/event3: 0000 0000 00000000                                                                                   
/dev/input/event3: 0001 0104 00000000                                                                                   
/dev/input/event3: 0000 0000 00000000


jerry get the button->code = 259
E InputReader: jerry position = 612
I CAM_INFO: CAM-SENSOR: cam_actuator_position_store: 151 cam_actuator_position_store: write addr 26 data 40
### 回答1: Android系统的GPIO(General Purpose Input/Output)读取是通过底层硬件接口实现的。GPIO是一种通用输入/输出接口,可以用于控制和读取外部电路中的信号。 要在Android中读取GPIO,首先需要加载GPIO驱动程序。在Android的内核配置文件中,可以启用GPIO子系统来支持GPIO的操作。然后,在设备初始化时加载GPIO驱动。 加载后,可以使用Java Native Interface (JNI)来从Java层调用底层C/C++代码。在C/C++代码中,可以通过特定的方法来读取有关GPIO引脚的状态。 对于某些特定的硬件平台,可能会提供特定的GPIO库或框架,以便更方便地读取和控制GPIO。这些库可以提供更高级的API,以简化GPIO的读取操作。 一般来说,读取GPIO需要以下步骤: 1. 找到GPIO的设备文件路径,通常位于/sys/class/gpio/目录下。 2. 打开对应的GPIO设备文件,并设置文件读取模式。 3. 读取GPIO引脚的状态,可以使用read()方法来实现。 4. 关闭GPIO设备文件。 需要注意的是,要读取GPIO引脚的状态,需要确保已正确配置GPIO的输入模式,并将外部电路与GPIO引脚正确连接。 在读取GPIO时,需要小心防止并发访问和资源竞争的问题。可以使用互斥锁或其他同步机制来保护对GPIO的访问。 总之,要在Android上读取GPIO,需要加载GPIO驱动程序并调用底层代码来读取GPIO引脚的状态。使用适当的方法和同步机制可以确保正确和安全地读取GPIO。 ### 回答2: 在Android系统中,可以通过使用Java语言和相关API来读取GPIO(通用输入输出)。 首先,要读取GPIO,需要在Android设备的硬件上进行设置。通常,GPIO是通过物理引脚连接到设备上的电子元件(如开关、传感器等),在Android系统中,需要确认设备的GPIO引脚是否可用以及如何访问它们。这通常需要对硬件做一些配置或者修改设备的设备树。 一旦GPIO引脚可用并正确设置,就可以通过使用AndroidGPIO API来读取。Android提供了一些类和方法,可以轻松地读取GPIO引脚的状态。 可以通过使用`GpioManager`类来管理GPIO引脚。可以通过调用`GpioManager.openGpio()`方法来打开指定的GPIO引脚。然后,可以使用`Gpio`对象的`getValue()`方法来读取引脚的状态,返回值可以是高电平(1)或低电平(0)。 下面是一个简单的示例代码: ```java GpioManager gpioManager = new GpioManager(); Gpio gpio = gpioManager.openGpio(GPIO_PIN_NUMBER); int value = gpio.getValue(); if (value == 1) { // GPIO引脚为高电平状态 } else { // GPIO引脚为低电平状态 } gpio.close(); ``` 需要注意的是,GPIO的读取操作通常需要在Android应用的后台线程中进行,避免阻塞主线程。如果需要持续读取GPIO的状态,可以使用循环或者定时器来实现。 总结起来,要在Android中读取GPIO,首先需要确认GPIO引脚是否可用并配置正确,然后可以使用AndroidGPIO API来管理和读取引脚的状态。 ### 回答3: Android是基于Linux内核的操作系统,可以通过编写驱动程序来读取GPIO(General Purpose Input/Output)引脚。下面是一个简单的300字中文回答。 在Android中,可以使用JNI(Java Native Interface)来访问C/C++编写的底层代码,从而控制硬件设备。要读取GPIO引脚,首先需要编写一个JNI方法,该方法将在Java代码中被调用。 在C/C++代码中,可以使用Linux内核提供的GPIO接口来控制GPIO引脚。可以使用sysfs接口(一种文件系统接口)来读取和设置GPIO的值。通过读取文件的方式,可以获得GPIO引脚的状态。 首先,要找到相应GPIO引脚所对应的GPIO编号。在Android中,可以通过查看设备树或者内核文档来确定GPIO编号。然后,需要通过打开/sys/class/gpio/gpioN目录,其中N是GPIO编号,来访问GPIO引脚。 通过读取/sys/class/gpio/gpioN/value文件可以获取到GPIO引脚的值,文件中的值为0表示低电平,为1表示高电平。可以使用标准的Linux文件读取函数来读取该文件。 在C/C++代码中,可以通过写入/sys/class/gpio/unexport文件来取消导出GPIO引脚,以释放资源。这是很重要的,因为GPIO资源是有限的。 使用这个方法可以在Android中读取GPIO引脚的状态。然后,可以通过JNI方法将GPIO引脚的状态传递给Java代码,以供Android应用程序使用。 当然,读取GPIO引脚的过程可能需要特定的权限或者在root权限下进行。因此,在开发过程中需要注意相关的权限设置和安全性考虑。 以上就是使用Android读取GPIO引脚的简单介绍。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值