- Android板级支持与硬件相关子系统
- 韩超等
- 3034字
- 2020-08-28 12:21:34
5.5 用户输入BSP的实现
不同平台的键盘等输入设备,通常是处理器SOC之外的硬件。对于Android输入系统中的BSP支持部分的驱动程序和配置文件,和处理器的关系不大,而和其外部连接的硬件关系较大。
↘5.5.1 模拟器中的实现
1.驱动程序
goldfish虚拟处理器键盘输入部分的驱动程序是Event驱动程序,代码路径为:drivers/input/keyboard/goldfish_events.c。这个驱动程序是一个标准的Event驱动程序,在用户空间的设备节点为/dev/input/event0。
goldfish_events.c中实现其核心的内容:
static irqreturn_t events_interrupt(int irq, void *dev_id) { struct event_dev *edev = dev_id; unsigned type, code, value; type = __raw_readl(edev->addr + REG_READ); // 类型 code = __raw_readl(edev->addr + REG_READ); // 码 value = __raw_readl(edev->addr + REG_READ); // 数值 input_event(edev->input, type, code, value); return IRQ_HANDLED; }
events_interrupt实现的是按键事件的中断处理函数,当中断发生后,读取虚拟寄存器的内容,将信息上报。实际上,虚拟寄存器中的内容由模拟器根据主机环境键盘按下的情况得到。
2.用户空间的配置文件
在模拟器环境中,使用了默认的所有的kl和kcm文件,由于模拟器环境支持全键盘,因此基本上包含了大部分的功能。在模拟器环境中,实际上按键的扫描码对应的是桌面电脑的键盘(效果和鼠标点击模拟器的控制面板类似),键盘的某些按键按下后,转换为驱动程序中的扫描码,然后再由上层的用户空间处理,这个过程和实际系统中是类似的。显然,通过更改默认的kl文件,也可以更改实际按键的映射关系。
tuttle2.kl和tuttle2.kcm是额外的按键布局和按键字符影射文件。
↘5.5.2 Nexus One系统中的实现
1.触摸屏、轨迹球和按键驱动程序
Nexus One系统使用MSM的Mahimahi平台的用户输入设备包括以下几个和用户输入相关的Event设备。
·/dev/input/event4:几个硬件的按键。
·/dev/input/event2:触摸屏设备。
·/dev/input/event5:轨迹球设备。
触摸屏的驱动程序在drivers/input/touchscreen目录中的synaptics_i2c_rmi.c,这是一个I2C触摸屏的驱动程序。
按键和轨迹球的功能,具体的驱动程序在arch/arm/mach-msm/目录board-mahimahi-keypad.c文件中实现。
board-mahimahi-keypad.c中的全局定义如下所示:
static struct gpio_event_info *mahimahi_input_info[] = { &mahimahi_keypad_matrix_info.info, // 键盘矩阵 &mahimahi_keypad_key_info.info, // 键盘信息 &jogball_x_axis.info.info, // 轨迹球X方向信息 &jogball_y_axis.info.info, // 轨迹球Y方向信息 }; static struct gpio_event_platform_data mahimahi_input_data = { .names = {"mahimahi-keypad", "mahimahi-nav", NULL, }, // 按键轨迹球的设备名称 .info = mahimahi_input_info, .info_count = ARRAY_SIZE(mahimahi_input_info), .power = jogball_power, }; static struct platform_device mahimahi_input_device = { // GPIO的平台设备定义 .name = GPIO_EVENT_DEV_NAME, .id = 0, .dev = { .platform_data = &mahimahi_input_data, }, };
按键和轨迹球是通过GPIO系统来实现的,因此定义了gpio_event_info类型的数组。"mahimahi-keypad"和"mahimahi-nav"分别是两个设备的名称。gpio_event_info类型的指针数组mahimahi_input_info中包含了mahimahi_keypad_matrix_info.info,mahimahi_keypad_key_info.info、jogball_x_axis.info.info和jogball_y_axis.info.info。
按键驱动是一个利用GPIO矩阵的驱动,由gpio_event_matrix_info矩阵定义,定义还需要包含按键的GPIO矩阵和input设备的信息,内容如下所示:
static unsigned int mahimahi_col_gpios[] = { 33, 32, 3l }; static unsigned int mahimahi_row_gpios[] = { 42, 4l, 40 }; #define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(mahimahi_row_gpios) + (row)) #define KEYMAP_SIZE (ARRAY_SIZE(mahimahi_col_gpios) * \ ARRAY_SIZE(mahimahi_row_gpios)) static const unsigned short mahimahi_keymap[KEYMAP_SIZE] = { // 按键映射关系 [KEYMAP_INDEX(0, 0)] = KEY_VOLUMEUP, // KEY_VOLUMEUP == ll5 [KEYMAP_INDEX(0, l)] = KEY_VOLUMEDOWN, // KEY_VOLUMEDOWN == ll4 [KEYMAP_INDEX(l, l)] = MATRIX_KEY(l, BTN_MOUSE), }; static struct gpio_event_matrix_info mahimahi_keypad_matrix_info = { .info.func = gpio_event_matrix_func, // 关键函数实现 .keymap = mahimahi_keymap, .output_gpios = mahimahi_col_gpios, // GPIO的行列实现 .input_gpios = mahimahi_row_gpios, .noutputs = ARRAY_SIZE(mahimahi_col_gpios), .ninputs = ARRAY_SIZE(mahimahi_row_gpios), .settle_time.tv.nsec = 40 * NSEC_PER_USEC, .poll_time.tv.nsec = 20 * NSEC_PER_MSEC, .flags = (GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_REMOVE_PHANTOM_KEYS | GPIOKPF_PRINT_UNMAPPED_KEYS), }; static struct gpio_event_direct_entry mahimahi_keypad_key_map[] = { // Power按键 { .gpio = MAHIMAHI_GPIO_POWER_KEY,.code = KEY_POWER, }, }; static struct gpio_event_input_info mahimahi_keypad_key_info = { .info.func = gpio_event_input_func, // 关键函数实现 .info.no_suspend = true, .flags = 0, .type = EV_KEY, .keymap = mahimahi_keypad_key_map, .keymap_size = ARRAY_SIZE(mahimahi_keypad_key_map) };
mahimahi_keypad_key_matrix_info和mahimahi_keypad_info是gpio_event_matrix_info类型的结构体,分别负责两个和一个按键的处理,实际上,MSM的Mahimahi平台硬件上只有三个按键:Power、音量增加和音量减少。音量增加和音量减少的扫描码分别是KEY_VOLUMEUP(115)和KEY_VOLUMEDOWN(114)。
提示:音量控制的两个按键在全键盘的qwerty.kl有所定义,同时符合Linux的Input设备和Android的按键的数值。
轨迹球也是由GPIO实现的,由X方向和Y方向两部分组成,内容如下所示:
static uint32_t jogball_x_gpios[] = { MAHIMAHI_GPIO_BALL_LEFT, MAHIMAHI_GPIO_BALL_RIGHT, // 左键、右键 }; static uint32_t jogball_y_gpios[] = { MAHIMAHI_GPIO_BALL_UP, MAHIMAHI_GPIO_BALL_DOWN, // 上键、下键 }; static struct jog_axis_info jogball_x_axis = { // X轴的内容 .info = {
.info.func = gpio_event_axis_func, // 关键函数实现 .count = ARRAY_SIZE(jogball_x_gpios), .dev = l, .type = EV_REL, .code = REL_X, // 相对设备,X轴 .decoded_size = lU << ARRAY_SIZE(jogball_x_gpios), .map = jogball_axis_map, .gpio = jogball_x_gpios, .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION, } }; static struct jog_axis_info jogball_y_axis = { // Y轴的内容 .info = { .info.func = gpio_event_axis_func, // 关键函数实现 .count = ARRAY_SIZE(jogball_y_gpios) .dev = l, .type = EV_REL, .code = REL_Y, // 相对设备,Y轴 .decoded_size = lU << ARRAY_SIZE(jogball_y_gpios), .map = jogball_axis_map, .gpio = jogball_y_gpios, .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION, } };
这里的轨迹球是用jog_axis_info类型的结构体进行定义的,这种设备的类型(type)是相对设备EV_REL。
2.用户空间的配置文件
Nexus One系统平台增加了h2w_headset.kl和mahimahi-keypad.kl作为按键布局的配置文件,代码的路径为:device/htc/passion-common/。
h2w_headset.kl文件的内容如下所示:
key l07 ENDCALL WAKE_DROPPED key ll3 MUTE WAKE key ll4 VOLUME_DOWN WAKE key ll5 VOLUME_UP WAKE key l63 MEDIA_NEXT WAKE key l64 MEDIA_PLAY_PAUSE WAKE key l65 MEDIA_PREVIOUS WAKE key 226 HEADSETHOOK WAKE key 23l CALL WAKE_DROPPED
mahimahi-keypad.kl与默认的qwerty.kl文件类似,属于全键盘的定义,只是个别的键值的内容有所不同。
3.虚拟按键
虚拟按键将触摸屏边缘作为按键的方式,在这种系统中一般触摸屏都比显示屏略大,在触摸屏下方多处显示屏的区域,可以用作虚拟按键。
使用虚拟按键需要将触摸屏的区域影射成按键的坐标,Android的输入系统要使用虚拟按键定义文件。虚拟按键定义文件是/sys/board_properties/目录中的virtualkeys.<设备>文件。这是sys文件系统的文件,由内核中的代码生成,被Android的输入系统使用。
虚拟按键定义文件的格式如下所示:
0xl:扫描码:X:Y:W:H:0xl: ……
例如,在Nexus One的系统上查看虚拟按键的配置文件如下所示:
# cat /sys/board_properties/virtualkeys.synaptics-rmi-touchscreen 0x0l:l58:55:835:90:55:0x0l:l39:l72:835:l25:55:0x0l:l02:298:835:ll5:55:0x0l:2l7:4l2 :835:95:55
这里定义了4个按键,每个按键的内容如下所示。
·0x01:158:55:835:90:55:最左(90×55),Back按键,扫描码158。
·0x01:139:172:835:125:55:中左(125×55),Menu按键,扫描码139。
·0x01:102:298:835:115:55:中右(115×55),Home按键,扫描码102。
·0x01:217:412:835:95:55:最右(95×55),Search按键,扫描码217。
Msm内核生成sys文件系统的文件是arch/arm/mach-msm/board-mahimahi.c。它针对synaptics-rmi-touchscreen触摸屏的区域生成的虚拟按键文件。
↘5.5.3 Nexus S系统中的实现
1.驱动程序
Nexus One系统使用三星的herring平台的用户输入设备包括以下几个和用户输入相关的Event设备。
·/dev/input/event0:mxt224_ts_input触摸屏设备。
·/dev/input/event2:herring-keypad键盘设备。
·/dev/input/event5:cypress-touchkey虚拟按键,I2C总线的地址为10-0020。
herring-keypad键盘驱动的定义在板级移植文件arch/arm/mach-s5pv210/mach-herring.c中,内容如下所示:
static struct gpio_event_platform_data herring_input_data = { .names = {"herring-keypad", NULL, }, .info = herring_input_info, .info_count = ARRAY_SIZE(herring_input_info), };
mxt224_ts_input触摸屏设备的代码路径为:drivers/input/touchscreen/mxt224.c。mxt224.c通过控制I2C总线来实现触摸屏Input设备,也实现了一个名为"Atmel MXT224"的I2C驱动。
cypress-touchkey是虚拟按键的设备,驱动实现的路径为drivers/input/keyboard/目录中的cypress-touchkey.c和cypress-touchkey-firmware.c文件,cypress-touchkey.c中通过读取I2C总线获得按键的信息,并且调用input_report_key()等函数向上层汇报,其中还实现了一个I2C的驱动模块,cypress-touchkey-firmware.c则通过GPIO进行控制。设备相关的内容则在板级文件arch/arm/mach-s5pv210/mach-herring.c中定义,即touchkey_platform_data结构类型的数据。
2.用户空间的配置文件
除了默认的文件外,Nexus S系统增加了cypress-touchkey.kl、herring-keypad.kl、s3c-keypad.kl和sec_jack.kl作为按键布局的配置文件,路径为:device/samsung/crespo。
herring-keypad.kl是平台的键盘的配置文件,内容如下所示:
key ll5 VOLUME_UP WAKE key ll4 VOLUME_DOWN WAKE key ll6 POWER WAKE key l39 MENU VIRTUAL key l02 HOME VIRTUAL key l58 BACK VIRTUAL key 2l7 SEARCH VIRTUAL
Nexus S仅有电源(用于开机关机)、音量增加和音量减少3个硬件按键。cypress-touchkey.kl是按键触摸区域的专用文件,内容如下所示:
key l39 MENU VIRTUAL key l02 HOME VIRTUAL key l58 BACK VIRTUAL key 2l7 SEARCH VIRTUAL
其中定义的几个键值就是菜单、桌面、回退和搜索Nexus S显示屏下方的按键。
↘5.5.4 Galaxy Nexus系统中的实现
Galaxy Nexus系统的输入设备包括一个触摸屏,仅有的3个硬件按键,还可以支持耳机的线控。它们与处理器的连接方式各自不同。
1.驱动程序
Galaxy Nexus的几个输入设备在内核中都表现成Event输入设备,如下所示。
·/dev/input/event1:名称为"Melfas MMSxxx Touchscreen"的触摸屏。
·/dev/input/event2:名称为"tuna-gpio-keypad"的GPIO连接的键盘。
·/dev/input/event5:名称为"Tuna Headset Jack"的耳机线控输入设备。
触摸屏是连接在OMAP处理器的第3个I2C总线上的设备,地址为3-0048。其代码路径为:drivers/input/touchscreen/mms_ts.c,在sys文件系统看到这个设备的信息是:
shell@android:/sys/devices/platform/omap/omap_i2c.3/i2c-3/3-0048 $ cat name mms_ts
GPIO键盘的内容在Tuna板级支持的arch/arm/mach-omap2/board-tuna-input.c文件中定义,包括以下内容:
static struct gpio_event_direct_entry tuna_gpio_keypad_keys_map_high[] = { { .code = KEY_POWER, .gpio = 3,}, // Power按键 }; static struct gpio_event_input_info tuna_gpio_keypad_keys_info_high = { .info.func = gpio_event_input_func, .info.no_suspend = true, .type = EV_KEY, // 为Event设备中的按键类型 .keymap = tuna_gpio_keypad_keys_map_high, .keymap_size = ARRAY_SIZE(tuna_gpio_keypad_keys_map_high), .flags = GPIOEDF_ACTIVE_HIGH, .debounce_time.tv64 = 2 * NSEC_PER_MSEC, }; static struct gpio_event_direct_entry tuna_gpio_keypad_keys_map_low[] = { { .code = KEY_VOLUMEDOWN, .gpio = 8,}, // 两个音量按键 { .code = KEY_VOLUMEUP, .gpio = 30,}, }; static struct gpio_event_input_info tuna_gpio_keypad_keys_info_low = { .info.func = gpio_event_input_func, .info.no_suspend = true, .type = EV_KEY, // 为Event设备中的按键类型 .keymap = tuna_gpio_keypad_keys_map_low, .keymap_size = ARRAY_SIZE(tuna_gpio_keypad_keys_map_low), .debounce_time.tv64 = 2 * NSEC_PER_MSEC, }; static struct gpio_event_info *tuna_gpio_keypad_info[] = { // GPIO的事件的定义 &tuna_gpio_keypad_keys_info_high.info, &tuna_gpio_keypad_keys_info_low.info, }; static struct gpio_event_platform_data tuna_gpio_keypad_data = { .name = "tuna-gpio-keypad", // 驱动的名称 .info = tuna_gpio_keypad_info, .info_count = ARRAY_SIZE(tuna_gpio_keypad_info) };
其中包括了音量增加键、音量减少按键和电源按键(Power)的定义,它们都是连接在GPIO之上的。在驱动程序中,使用gpio_event_input_info结构直接将其实现成Event设备。
2.用户空间的配置文件
Galaxy Nexus系统平台增加了tuna-gpio-keypad.kl为Tuna平台的键盘布局文件,文件码路径为device/samsung/tuna/tuna-gpio-keypad.kl,内容如下所示:
$ cat tuna-gpio-keypad.kl key ll4 VOLUME_DOWN WAKE key ll5 VOLUME_UP WAKE key ll6 POWER WAKE
这里的3个按键均有WAKE,表示Galaxy Nexus的3个硬件的按键均可以唤醒。文件sec_jack.kl用于耳机上面的线控按键,内容如下所示:
此处的3个按键分别定义为KeycodeLabels.h中的87("MEDIA_NEXT")、88("MEDIA_PREVIOUS")和79("HEADSETHOOK")3个按键码。
另一个键盘布局文件sii9234_rcp.kl用于HDMI控制芯片MHD SiI9234。其中包括小键盘(NUMPAD)和多媒体控制的各个按键。
key l63 MEDIA_NEXT WAKE key l65 MEDIA_PREVIOUS WAKE key 226 HEADSETHOOK WAKE