EmuELEC系统的结构
阅读原文时间:2023年07月15日阅读:2

在img写入后, 会产生两个分区
EMUELEC: 用于启动的文件, 例如dtb文件等, 以及system.img & system.img.md5, EmuELEC的系统文件都在这个img里面
STORAGE:

/dev/mmcblk1p1 511.7M 373.6M 138.2M 73% /flash
/dev/loop0 357.5M 357.5M 0 100% /
/dev/mmcblk1p2 28.6G 3.5G 25.1G 12% /storage

启动后, EMUELEC分区被挂载为 /flash, STORAGE分区被挂载为 /storage, system.img 通过 /dev/loop0 被挂载为系统根目录 /

所以, 用户能修改的仅仅是 /flash 和 /storage 目录下的内容
root用户的home目录被定位到 /storage, 如果需要添加登录后自动执行的命令(例如添加alias), 可以直接在 /storage 目录下新建 .profile 文件来实现

这个是在uboot中进行管理的, 可以通过fw_printenv命令进行查看

EmuELEC:/usr/sbin # fw_printenv

baudrate=115200
boot_count=0
bootcmd=if test ${bootfromnand} = 1; then setenv bootfromnand 0; saveenv; else run bootfromsd; run bootfromusb; fi; run storeboot
bootcount_check=echo bootcounts=${boot_count}; if itest ${boot_count} == 0; then setenv boot_count 1;saveenv;else if itest ${boot_count} == 1; then setenv boot_count 2;saveenv;else if itest ${boot_count} == 2; then setenv boot_count 3;saveenv;else if itest ${boot_count} == 3; then setenv boot_count 4;saveenv;else if itest ${boot_count} == 4; then run recovery_from_flash;fi;fi;fi;fi;fi
bootdelay=0
bootfromnand=0
bootfromsd=mmcinfo; if fatload mmc 0 ${loadaddr} kernel.img; then run sddtb; setenv bootargs ${bootargs} bootfromsd; bootm; fi
bootfromusb=usb start 0; if fatload usb 0 ${loadaddr} kernel.img; then run usbdtb; setenv bootargs ${bootargs} bootfromusb; bootm; fi
bootmode_check=get_rebootmode; echo reboot_mode=${reboot_mode};if test ${reboot_mode} = factory_reset; then defenv_reserv;setenv upgrade_step 2; save;fi;
cmdline_keys=if keyman init 0x1234; then if sec_keyunify read mac ${loadaddr} str; then setenv bootargs ${bootargs} mac=${mac} androidboot.mac=${mac};fi;fi;

可以看到其中的 bootfromnand 变量是用于控制设备的启动顺序, 如果值为1, 那么从nand(设备内部存储, eMMC等), 如果值为0, 那么依次从sd, 从usb启动, 在这个过程中如果某个介质可以启动了, 就把这个方式加到bootargs变量的值当中去, 例如

setenv bootargs ${bootargs} bootfromsd;

.然后调用系统函数bootm启动内核. bootm会调用 ./lib_arm/armlinux.c的do_bootm() 方法, 里面会调用./common/cmd_bootm.c的do_bootm_linux()

如果这些都不成功, 那就调用storeboot

storeboot=if imgread kernel boot ${loadaddr}; then bootm ${loadaddr}; fi;run update;

而update会依次尝试从各个媒介升级

update=run usb_burning; run sdc_burning; if mmcinfo; then run recovery_from_sdcard;fi;if usb start 0; then run recovery_from_udisk;fi;run recovery_from_flash;

中间还会记录启动次数, 如果启动次数达到4, 就会执行 recovery_from_flash

recovery_from_flash=setenv bootargs ${bootargs} aml_dt=${aml_dt} recovery_part={recovery_part} recovery_offset={recovery_offset};if imgread kernel ${recovery_part} ${loadaddr} ${recovery_offset}; then wipeisb; bootm ${loadaddr}; fi

ES的Quit菜单中的Reboot From NAND, 实际执行的就是 /usr/sbin/rebootfromnand 这个命令, 里面将 bootfromnand 值设为了1

EmuELEC:/usr/sbin # more rebootfromnand
#!/bin/sh

SPDX-License-Identifier: GPL-2.0-or-later

Copyright (C) 2016-2018 kszaq (kszaquitto@gmail.com)

Copyright (C) 2018-present Team CoreELEC (https://coreelec.org)

if /usr/sbin/fw_printenv whereToBootFrom > /dev/null 2>&1; then /usr/sbin/fw_setenv whereToBootFrom internal; fi
/usr/sbin/fw_setenv bootfromnand 1

系统启动的服务是通过systemd管理的, 启动脚本位于 /usr/lib/systemd/system/ 下, 因为是过loop设备挂载的, 所以这里面的文件都不可修改. 默认的启动target为

EmuELEC:/usr/lib/systemd/system # systemctl get-default
emuelec.target
EmuELEC:/usr/lib/systemd/system # ll def*.*
lrwxrwxrwx 1 root root 14 Nov 19 00:42 default.target -> emuelec.target

服务依赖关系为

EmuELEC:/usr/lib/systemd/system # systemctl list-dependencies emuelec.target
emuelec.target
● ├─emuelec-autostart.service
● ├─emustation.service
● ├─retroarch.service
● ├─tmp-assets.mount
● ├─tmp-cores.mount
● ├─tmp-database.mount
● ├─tmp-joypads.mount
● ├─tmp-overlays.mount
● ├─tmp-shaders.mount
● ├─graphical.target
● │ ├─unbind-console.service
● │ └─multi-user.target
● │ ├─avahi-daemon.service
● │ ├─connman.service
● │ ├─dbus.service
● │ ├─entware.service
● │ ├─iptables.service
● │ ├─nmbd.service
● │ ├─pulseaudio.service
● │ ├─rpcbind.service
● │ ├─sixaxis@multi-user.service
● │ ├─smbd.service
● │ ├─sshd.service
● │ ├─systemd-ask-password-wall.path
● │ ├─systemd-logind.service
● │ └─basic.target
● │ ├─add-entropy.service
● │ ├─amlogic-dvb.service
● │ ├─fstrim.service
● │ ├─hwdb.service
● │ ├─kvimfan.service
● │ ├─openvfd.service
● │ ├─show-version.service
● │ ├─swap.service
● │ ├─tmp.mount
● │ ├─var.mount
● │ ├─wetekdvb.service
● │ ├─paths.target
● │ ├─slices.target
● │ │ ├─-.slice
● │ │ └─system.slice
● │ ├─sockets.target
● │ │ ├─dbus.socket
● │ │ ├─systemd-initctl.socket
● │ │ ├─systemd-journald-audit.socket
● │ │ ├─systemd-journald-dev-log.socket
● │ │ ├─systemd-journald.socket
● │ │ ├─systemd-udevd-control.socket
● │ │ └─systemd-udevd-kernel.socket
● │ ├─sysinit.target
● │ │ ├─debug-shell.service
● │ │ ├─debugconfig.service
● │ │ ├─dev-hugepages.mount
● │ │ ├─dev-mqueue.mount
● │ │ ├─kmod-static-nodes.service
● │ │ ├─machine-id.service
● │ │ ├─openssl-config.service
● │ │ ├─sys-fs-fuse-connections.mount
● │ │ ├─sys-kernel-config.mount
● │ │ ├─sys-kernel-debug.mount
● │ │ ├─systemd-ask-password-console.path
● │ │ ├─systemd-hwdb-update.service
● │ │ ├─systemd-journal-catalog-update.service
● │ │ ├─systemd-journal-flush.service
● │ │ ├─systemd-journald.service
● │ │ ├─systemd-modules-load.service
● │ │ ├─systemd-sysctl.service
● │ │ ├─systemd-tmpfiles-setup-dev.service
● │ │ ├─systemd-tmpfiles-setup.service
● │ │ ├─systemd-udev-trigger.service
● │ │ ├─systemd-udevd.service
● │ │ ├─tz-data.service
● │ │ ├─usercache.service
● │ │ ├─userconfig.service
● │ │ ├─local-fs.target
● │ │ │ ├─kernel-overlays.service
● │ │ │ ├─libmali.service
● │ │ │ ├─tmp.mount
● │ │ │ └─var.mount
● │ │ └─swap.target
● │ └─timers.target
● │ └─systemd-tmpfiles-clean.timer
● └─multi-user.target
● ├─avahi-daemon.service
● ├─connman.service
● ├─dbus.service
● ├─entware.service
● ├─iptables.service
● ├─nmbd.service
● ├─pulseaudio.service
● ├─rpcbind.service
● ├─sixaxis@multi-user.service
● ├─smbd.service
● ├─sshd.service
● ├─systemd-ask-password-wall.path
● ├─systemd-logind.service
● └─basic.target

在 emuelec-autostart.service 里, 执行了/storage/.config/autostart.sh

在autostart.sh的结尾, 又执行了 /storage/.config/custom_start.sh

最后一步, 通过 emustation.service, 把/usr/bin/emulationstation启动起来

首先到 https://www.screenscraper.fr/ 注册一个帐号, 需要邮箱验证

在EmuELEC界面上, 通过 SCRAPE 菜单, 填充帐号和口令, 依次选择
Scrape From: SCREENSCRAPER
Image Source: SCREENSHOT(游戏运行画面), TITLE SCREENSHOT(游戏开始画面), MIX (游戏运行截图+游戏盒子合并在一起的一张图)
Box Source: NONE (游戏包装, 2d或3d, 因为色深为24bit, 文件size会比较大, 都是200~400K大小, 如果用列表展示, 就不需要下载这个)
Logo Source: WHEEL
Scrape Ratings: YES
Scrape Videos: NO
然后点击Scrape Now, 选择要下载的集合, 选择处理冲突的方式, 建议自动.

系统就会在后台自动下载, 因为来源在国外所以速度会比较慢.

系统默认时区为墨西哥, 界面上没有修改时区的地方, 需要命令行登录后修改 /emuelec/configs/emuelec.conf , 里面有timezone配置. 改为

system.timezone=Asia/Shanghai

这个其实是RetroArch的配置, 和以往的连发键设置不太一样, RetroArch用的是开关触发的机制, 有三处相关的设置
Settings->Input->Turbo Period, 连发键开启时, 在连发当中每次按下的时间长度(多少帧)
Settings->Input->Duty Cycle, 连发键开启时, 在连发当中按下的时间占空比
Settings->Input->User/Port[1,2,3,4] Binds->User/Port[1,2,3,4] Turbo, 开启连发的键

使用方法是, 按住需要连发的按键后, 按一下开启连发的键, 这个按住的键就开启连发了. 这个开启连发的效果只在按住时有效, 松开按键后连发的效果就消失, 需要再来一遍.

查看所有输入设备, 列出各设备对应的event编号

cat /proc/bus/input/devices

输入设备测试

# 手柄测试, 需要对应上面命令输出的js编号
jstest --event /dev/input/js0

通用的输入事件测试, 需要对应上面命令产生的event编号

evtest /dev/input/event3

对于乐视尚酷版手柄, 无法设置select键的问题: 这个手柄在输入设备里会产生两个设备, 分别是

I: Bus=0003 Vendor=0101 Product=1d79 Version=0110
N: Name="MY-POWER LeWGP-201"
P: Phys=usb-xhci-hcd.0.auto-1.4/input0
S: Sysfs=/devices/c9000000.dwc3/xhci-hcd.0.auto/usb1/1-1/1-1.4/1-1.4:1.0/0003:0101:1D79.0003/input/input4
U: Uniq=
H: Handlers=js0 event4
B: PROP=0
B: EV=1b
B: KEY=7fff0000 0 0 0 0 0 0 0 0 0
B: ABS=3063f
B: MSC=10

I: Bus=0003 Vendor=0101 Product=1d79 Version=0110
N: Name="MY-POWER LeWGP-201"
P: Phys=usb-xhci-hcd.0.auto-1.4/input1
S: Sysfs=/devices/c9000000.dwc3/xhci-hcd.0.auto/usb1/1-1/1-1.4/1-1.4:1.1/0003:0101:1D79.0004/input/input5
U: Uniq=
H: Handlers=kbd event5
B: PROP=0
B: EV=1f
B: KEY=3007f 0 0 0 0 483ffff 17aff32d bf544446 0 0 1 120c13 b17c000 267bfa d941dfed 9e1680 4400 0 10000002
B: REL=40
B: ABS=1 0
B: MSC=10

其中js0:event4设备可以响应除了back键和底下一排三个键以外其他所有按键, 而kbd:event5设备则正好相反. 可以通过evremap将event5的按键映射到event4

# Enable 'BACK' key on LeWGP-201 gamepad
evremap /dev/input/by-id/usb-MY-POWER_LeWGP-201-event-if01 /dev/input/by-id/usb-MY-POWER_LeWGP-201-event-joystick

将其添加到 /storage/.config/custom_start.sh 文件中, 将来开机就会自动生效.