33# script that can be added to kernel init= to have the BB64/PB2 Industrial
44# flash the eMMC when powered on. It will partition the device, possibly
55# reboot to get the new patition table, then install FPP onto the eMMC
6- # and then power attempt to power down. The power down usually will
7- # fail, but the indicator lights will stop flashing/cycling to
8- # indicate it's done
6+ # and then power down. The indicator lights also stop flashing/cycling to
7+ # indicate it's done, which is the signal to trust if the board is still powered
8+ # for any reason.
99
1010mount -o remount,rw /dev/mmcblk1p3 / || true
1111mkdir -p /proc
@@ -17,6 +17,16 @@ mount -t sysfs sysfs /sys
1717PATH=$PATH :/bin:/sbin:/usr/bin:/usr/sbin
1818DEVICE=/dev/mmcblk0
1919
20+ # This runs as init, so udev is never started -- and udev is what loads the driver
21+ # module for an i2c client, off the MODALIAS in its uevent. The kernel creates the
22+ # clients from the device tree either way, so without this the identity EEPROM and
23+ # the ADC beside it sit on the bus with no driver bound and no /sys attributes:
24+ # indistinguishable, from sysfs alone, from an MSPM0 that was never programmed.
25+ # Both are modules in the FPP kernel (CONFIG_EEPROM_AT24=m, CONFIG_AD7291=m).
26+ for mod in at24 ad7291; do
27+ modprobe ${mod} 2> /dev/null || true
28+ done
29+
2030mount -t vfat /dev/mmcblk1p1 /boot/firmware
2131mount -t tmpfs /tmp
2232
@@ -40,7 +50,16 @@ fail() {
4050 echo 120 > " $led /delay_on" 2> /dev/null
4151 echo 120 > " $led /delay_off" 2> /dev/null
4252 done
43- exit 1
53+ # This script IS init, so exiting is a kernel panic ("Attempted to kill init"),
54+ # and with no panic= on the command line the board just wedges -- no reboot, and
55+ # nothing left to ask questions of. Hand the serial console a shell instead: the
56+ # LEDs keep blinking from the kernel's timer trigger either way, so the board
57+ # still reads as failed to anyone who only has the lights.
58+ echo " "
59+ echo " Dropping to a shell on the console. The board stays unflashed."
60+ exec /bin/sh -i < /dev/console > /dev/console 2>&1
61+ # If /dev/console is not usable, hang rather than panic.
62+ while true ; do sleep 3600; done
4463}
4564
4665echo " ---------------------------------------"
@@ -79,17 +98,44 @@ rm -f /mnt/fpp_expand_rootfs
7998umount /mnt
8099
81100# Done. A sweep means working and a synchronised blink means failed, so darkness is
82- # the only remaining state -- and unlike "powered off" it survives the shutdown below
83- # failing, which in this environment it usually does .
101+ # the only remaining state -- and it is what remains readable if the power off below
102+ # does not take, since a board that never powered down still has to look finished .
84103for led in /sys/class/leds/* usr[0-9]; do
85104 [ -e " $led /trigger" ] || continue
86105 echo none > " $led /trigger" 2> /dev/null
87106 echo 0 > " $led /brightness" 2> /dev/null
88107done
89108
109+ # Shut down. Note what is NOT available here: /sbin/{shutdown,halt,poweroff,reboot}
110+ # are all symlinks to systemctl, and this script is PID 1, so there is no systemd for
111+ # any of them to talk to. sysrq is the only route out.
90112echo 1 > /proc/sys/kernel/sysrq
91- echo s > /proc/sysrq-trigger
92- echo u > /proc/sysrq-trigger
93- echo o > /proc/sysrq-trigger
113+
114+ # sysrq 'o' hands off to orderly_poweroff(), which first runs poweroff_cmd as a
115+ # usermode helper -- /sbin/poweroff, i.e. systemctl again -- and only forces a real
116+ # kernel_power_off() once that fails. Point it at something that cannot exist so it
117+ # fails immediately instead of grinding through that.
118+ echo /nonexistent-force-kernel-poweroff > /proc/sys/kernel/poweroff_cmd 2> /dev/null || true
119+
120+ echo s > /proc/sysrq-trigger # sync
121+ echo u > /proc/sysrq-trigger # remount everything read-only
122+ echo o > /proc/sysrq-trigger # power off
123+
124+ # 'o' is asynchronous -- it queues work and the write returns straight away -- so the
125+ # power off is still being set up when this line is reached. Waiting here is not
126+ # politeness: this script IS init, so running off the end is "Attempted to kill
127+ # init", a kernel panic that beats the shutdown to the finish and lands on a board
128+ # that flashed perfectly.
129+ #
130+ # The power off itself is real on this hardware. The TPS65219 PMIC at i2c 0x30 is
131+ # marked system-power-controller in the device tree, so the tps65219 driver registers
132+ # a SYS_OFF_MODE_POWER_OFF handler and the kernel can actually cut the rails -- there
133+ # is no psci node, but none is needed, the PMIC is the handler. So this loop should
134+ # never get more than a few seconds in. It is the backstop for the case where the
135+ # handler does not fire, where a parked init with everything synced and read-only,
136+ # and the LEDs dark, is still a correct and readable end state.
137+ while true ; do
138+ sleep 3600
139+ done
94140
95141
0 commit comments