通过按键中断驱动输入来调整马达的远近距离,加深对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