mirror of
				https://github.com/riptidewave93/UNVR-NAS.git
				synced 2025-03-09 15:40:13 +00:00 
			
		
		
		
	feat: initial bluetooth support (#9)
* Enable Bluetooth LE radio support * Build our own bccmd which we need to setup/enable this BT chipset sadly * Use our own tool we build to interface with the ubnt eeprom, so we can not rely on their custom kernel module * Also fix HDDs not spinning down on shutdown, doing something similar to how unifi does it but a tad more generic.
This commit is contained in:
		
							parent
							
								
									fe3b4cd76f
								
							
						
					
					
						commit
						9ef1a72228
					
				
					 15 changed files with 678 additions and 20 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -2,4 +2,5 @@ | |||
| unifi-firmware/*.bin | ||||
| BuildEnv | ||||
| output | ||||
| downloads | ||||
| downloads | ||||
| tools/ubnteeprom/test-files | ||||
							
								
								
									
										15
									
								
								Dockerfile
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								Dockerfile
									
										
									
									
									
								
							|  | @ -13,6 +13,7 @@ RUN apt-get update && apt-get install -yq \ | |||
|     bsdextrautils \ | ||||
|     build-essential \ | ||||
|     cpio \ | ||||
|     curl \ | ||||
|     debootstrap \ | ||||
|     debhelper \ | ||||
|     device-tree-compiler \ | ||||
|  | @ -26,9 +27,14 @@ RUN apt-get update && apt-get install -yq \ | |||
|     kpartx \ | ||||
|     libconfuse-common \ | ||||
|     libconfuse-dev \ | ||||
|     libdbus-1-dev \ | ||||
|     libelf-dev \ | ||||
|     libglib2.0-dev \ | ||||
|     libical-dev \ | ||||
|     libncurses-dev \ | ||||
|     libreadline-dev \ | ||||
|     libssl-dev \ | ||||
|     libudev-dev \ | ||||
|     lvm2 \ | ||||
|     mtools \ | ||||
|     parted \ | ||||
|  | @ -47,4 +53,11 @@ RUN apt-get update && apt-get install -yq \ | |||
|     && apt-get clean \ | ||||
|     && rm -rf /var/lib/apt/lists/* \ | ||||
|     && /setup_mkimage.sh \ | ||||
|     && rm /setup_mkimage.sh | ||||
|     && rm /setup_mkimage.sh \ | ||||
|     && curl -fsSL "https://go.dev/dl/go1.22.4.linux-amd64.tar.gz" -o golang.tar.gz \ | ||||
|     && tar -C /usr/local -xzf golang.tar.gz \ | ||||
|     && rm golang.tar.gz \ | ||||
|     && for bin in `ls /usr/local/go/bin/`; do \ | ||||
|         update-alternatives --install "/usr/bin/$bin" "$bin" "/usr/local/go/bin/$bin" 1; \ | ||||
|         update-alternatives --set "$bin" "/usr/local/go/bin/$bin"; \ | ||||
|     done | ||||
|  | @ -4,7 +4,8 @@ Description=UBNT bootup init script | |||
| [Service] | ||||
| User=root | ||||
| Type=oneshot | ||||
| ExecStart=/usr/lib/init/boot/ubnt-init.sh | ||||
| ExecStart=/usr/lib/init/boot/ubnt-init.sh start | ||||
| ExecStop=/usr/lib/init/boot/ubnt-init.sh stop | ||||
| RemainAfterExit=yes | ||||
| 
 | ||||
| [Install] | ||||
|  |  | |||
|  | @ -1,13 +1,7 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| if [ "$1" == "id" ]; then | ||||
|     BOARD_SYSID=$(grep systemid /proc/ubnthal/system.info | sed 's|systemid=||g') | ||||
|     BOARD_SERIALNO=$(grep serialno /proc/ubnthal/system.info | sed 's|serialno=||g') | ||||
|     # BOM is in SPI on EEPROM part, offset D000 is start of TlvInfo. BOM starts with 113- | ||||
|     BOARD_BOM=$(dd if=/dev/mtd4 bs=64 skip=832 count=1 status=none | strings | grep 113-) | ||||
|     echo "board.sysid=0x${BOARD_SYSID}" | ||||
|     echo "board.serialno=${BOARD_SERIALNO}" | ||||
|     echo "board.bom=${BOARD_BOM}" | ||||
|     ubnteeprom -tools | ||||
| else | ||||
|     echo "Unknown ubnt-tools cmd: $@" >> /tmp/ubnt-tools-unknown.log | ||||
| fi | ||||
|  |  | |||
							
								
								
									
										178
									
								
								overlay/filesystem/usr/lib/init/boot/ubnt-bt.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										178
									
								
								overlay/filesystem/usr/lib/init/boot/ubnt-bt.sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,178 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| function log_error() { | ||||
| 	echo "<3> ${*}" 1>&2 | ||||
| } | ||||
| 
 | ||||
| function get_bt_mac() { | ||||
| 	local bt_device_num="$1" | ||||
| 	if [ -z "${bt_device_num}" ]; then | ||||
| 		log_error "get_bt_mac: Unknown device num" | ||||
| 		return 1 | ||||
| 	fi | ||||
| 
 | ||||
| 	local hw_addr_base=$(ubnteeprom -board -key "hwaddrbbase") | ||||
| 	local eth_count=$(ubnteeprom -board -key "EthMACAddrCount") | ||||
| 	local wifi_count=$(ubnteeprom -board -key "WiFiMACAddrCount") | ||||
| 	local bt_count=$(ubnteeprom -board -key "BtMACAddrCount") | ||||
| 
 | ||||
| 	if [ -z "${hw_addr_base}" ] || [ -z "${eth_count}" ] || [ -z "${wifi_count}" ] || [ -z "${bt_count}" ]; then | ||||
| 		log_error "Unexpected contents in $UBNTHAL_BOARD" | ||||
| 		return 2 | ||||
| 	fi | ||||
| 
 | ||||
| 	if [ ${bt_device_num} -ge ${bt_count} ]; then | ||||
| 		log_error "Unsupported device number (bt_device_num[${bt_device_num}] >= bt_count[${bt_count}])" | ||||
| 		return 3 | ||||
| 	fi | ||||
| 
 | ||||
| 	local mac=$(echo "${hw_addr_base}" | sed s/":"//g) | ||||
| 	local mac_dec=$(printf '%d\n' 0x${mac}) | ||||
| 	local bt_mac_dec=$(expr ${mac_dec} + ${eth_count} + ${wifi_count} + ${bt_device_num}) | ||||
| 
 | ||||
| 	printf '%012X\n' "${bt_mac_dec}" | tr A-Z a-z | ||||
| } | ||||
| 
 | ||||
| function main(){ | ||||
| 	BT_DEVICE="$1" | ||||
| 	[ -z "$BT_DEVICE" ] && return 2 | ||||
| 
 | ||||
| 	BT_DEVICE_NUM=$(echo "${BT_DEVICE}" | sed s/"hci"//g) | ||||
| 	if [[ ! "${BT_DEVICE_NUM}" =~ ^[0-9]+$ ]]; then | ||||
| 		log_error "Invalid bluetooth device number [${BT_DEVICE_NUM}]" | ||||
| 		return 3 | ||||
| 	fi | ||||
| 
 | ||||
| 	BT_MAC=$(get_bt_mac "${BT_DEVICE_NUM}") | ||||
| 	[ $? -eq 0 ] || return 4 | ||||
| 
 | ||||
| 	local board_id=$(ubnteeprom -board -key "boardid") | ||||
| 	case ${board_id} in | ||||
| 		ea16) | ||||
| 			# unvr: nothing to do here | ||||
| 			;; | ||||
| 		ea1a) | ||||
| 			usb_based_init | ||||
| 			;; | ||||
| 		ea20|ea50|ea51) | ||||
| 			gpio_num=$(find_gpio_on_expander 0 0020 8) | ||||
| 			if [ $gpio_num -lt 0 ]; then | ||||
| 				return 5 | ||||
| 			fi | ||||
| 			gpio_reset $gpio_num | ||||
| 			uart_based_init /dev/ttyS3 "/lib/firmware/csr8x11/csr8x11-a12-bt4.2-patch-2018_uart.psr" | ||||
| 			;; | ||||
| 		ea2c|ea15|ea11|ea32) | ||||
| 			gpio_reset 37 | ||||
| 			uart_based_init /dev/ttyS1 "/lib/firmware/csr8x11/csr8x11-a12-bt4.2-patch-2018_uart.psr" | ||||
| 			;; | ||||
| 		ea3d|ea3e) | ||||
| 			gpio_num=$(find_gpio_on_expander 3 0029 13) | ||||
| 			if [ $gpio_num -lt 0 ]; then | ||||
| 				return 5 | ||||
| 			fi | ||||
| 			gpio_reset $gpio_num | ||||
| 			uart_based_init /dev/ttyAMA1 "/lib/firmware/csr8x11/pb-207-csr8x11-rev7-flowcontrol.psr" "flow" | ||||
| 			;; | ||||
| 		a678|a690|a69a) | ||||
| 			gpio_reset 490 | ||||
| 			usb_based_init | ||||
| 			;; | ||||
| 		e990) | ||||
| 			gpio_reset 306 | ||||
| 			usb_based_init | ||||
| 			;; | ||||
| 		*) | ||||
| 			return 4 | ||||
| 			;; | ||||
| 	esac | ||||
| } | ||||
| 
 | ||||
| function find_gpio_on_expander() { | ||||
| 	local bus=$1 | ||||
| 	local addr=$2 | ||||
| 	local pin=$3 | ||||
| 	local gpiochip_dir="/sys/bus/i2c/devices/$bus-$addr/gpio" | ||||
| 	local base | ||||
| 
 | ||||
| 	for chip in $(find $gpiochip_dir -maxdepth 1 -name 'gpiochip*' -printf "%f\n"); do | ||||
| 		base=$(echo $chip | sed 's/gpiochip//g') | ||||
| 		echo $((base + pin)) | ||||
| 		return | ||||
| 	done | ||||
| 
 | ||||
| 	echo -1 | ||||
| } | ||||
| 
 | ||||
| function gpio_reset(){ | ||||
| 	local gpio=$1 | ||||
| 
 | ||||
| 	if [ ! -d /sys/class/gpio/gpio${gpio} ]; then | ||||
| 		echo ${gpio} > /sys/class/gpio/export | ||||
| 	fi | ||||
| 	echo out > /sys/class/gpio/gpio${gpio}/direction | ||||
| 	echo 1 > /sys/class/gpio/gpio${gpio}/value | ||||
| 	sleep 1 | ||||
| 	echo 0 > /sys/class/gpio/gpio${gpio}/value | ||||
| 	sleep 1 | ||||
| 	echo 1 > /sys/class/gpio/gpio${gpio}/value | ||||
| 	sleep 1 | ||||
| 	echo ${gpio} > /sys/class/gpio/unexport | ||||
| } | ||||
| 
 | ||||
| function uart_based_init(){ | ||||
| 	local bt_serial_dev="$1" | ||||
| 	local bt_serial_speed="115200" | ||||
| 	local bt_fw="$2" | ||||
| 	local bt_option="$3" | ||||
| 	local bt_proto="bcsp" | ||||
| 	local loop_no=10 | ||||
| 	local i=0 | ||||
| 
 | ||||
| 	for i in $(seq 0 ${loop_no}); do | ||||
| 		if [ ${i} -gt 0 ]; then | ||||
| 			if [ ${i} -eq ${loop_no} ]; then | ||||
| 				log_error "Failed to initialize bluetooth (BT is not operational)" | ||||
| 				break | ||||
| 			fi | ||||
| 			log_error "Unable to initialize bluetooth. Give it another try (${i})" | ||||
| 		fi | ||||
| 
 | ||||
| 		#load psr file | ||||
| 		bccmd -t "${bt_proto}" -b "${bt_serial_speed}" -d "${bt_serial_dev}" psload -r ${bt_fw} || continue | ||||
| 
 | ||||
| 		#set bt address: <device index> <mac byte 4> 0x00 <mac byte 6> <mac byte 5> <mac byte 3> 0x00 <mac byte 2> <mac byte 1> | ||||
| 		bccmd -t "${bt_proto}" -d "${bt_serial_dev}" -b "${bt_serial_speed}" psset -r \ | ||||
| 			0x$((BT_DEVICE_NUM+1)) \ | ||||
| 			0x${BT_MAC:6:2} \ | ||||
| 			0x00 \ | ||||
| 			0x${BT_MAC:10:2} \ | ||||
| 			0x${BT_MAC:8:2} \ | ||||
| 			0x${BT_MAC:4:2} \ | ||||
| 			0x00 \ | ||||
| 			0x${BT_MAC:2:2} \ | ||||
| 			0x${BT_MAC:0:2} \ | ||||
| 			2>&1 | ||||
| 
 | ||||
| 		# attach UART interface | ||||
| 		hciattach -s "${bt_serial_speed}" "${bt_serial_dev}" "${bt_proto}" "${bt_serial_speed}" "${bt_option}" | ||||
| 		sleep 0.5 | ||||
| 
 | ||||
| 		# check if the device exists | ||||
| 		[ -d "/sys/class/bluetooth/${BT_DEVICE}" ] && break | ||||
| 
 | ||||
| 	done | ||||
| 
 | ||||
| 	hciconfig ${BT_DEVICE} up | ||||
| } | ||||
| 
 | ||||
| function usb_based_init(){ | ||||
| 	hciconfig ${BT_DEVICE} up; hciconfig ${BT_DEVICE} up | ||||
| 	sleep 1 | ||||
| 	bccmd psset -r 0x$((BT_DEVICE_NUM+1)) 0x${BT_MAC:6:2} 00 0x${BT_MAC:10:2} 0x${BT_MAC:8:2} 0x${BT_MAC:4:2} 00 0x${BT_MAC:2:2} 0x${BT_MAC:0:2} | ||||
| 	sleep 2 | ||||
| 	hciconfig ${BT_DEVICE} down | ||||
| 	hciconfig ${BT_DEVICE} up; hciconfig ${BT_DEVICE} up | ||||
| } | ||||
| 
 | ||||
| main "$@" | ||||
|  | @ -1,8 +1,22 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| # Load our kernel modules | ||||
| /usr/sbin/modprobe ubnthal | ||||
| /usr/sbin/modprobe btrfs | ||||
| case "$1" in | ||||
|     start) | ||||
|         # Load our kernel modules | ||||
|         /usr/sbin/modprobe ubnthal | ||||
|         /usr/sbin/modprobe btrfs | ||||
| 
 | ||||
| # Set our kernel panic timeout SUPER short so we reboot on crash | ||||
| echo 2 > /proc/sys/kernel/panic | ||||
|         # Set our kernel panic timeout SUPER short so we reboot on crash | ||||
|         echo 2 > /proc/sys/kernel/panic | ||||
| 
 | ||||
|         # Setup bluetooth hci0 device | ||||
|         /usr/lib/init/boot/ubnt-bt.sh hci0 | ||||
|         ;; | ||||
|     stop) | ||||
|         # Tear down BT | ||||
|         hciconfig hci0 down | ||||
|         ;; | ||||
|     *) | ||||
|         echo "Invalid command $1" | ||||
|         ;; | ||||
| esac | ||||
|  |  | |||
							
								
								
									
										29
									
								
								overlay/filesystem/usr/lib/systemd/system-shutdown/unifi-shutdown
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										29
									
								
								overlay/filesystem/usr/lib/systemd/system-shutdown/unifi-shutdown
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| # turn off fans for shutdown | ||||
| if [ -d "/sys/class/hwmon/hwmon0/device" ]; then | ||||
| 	for pwm in `ls /sys/class/hwmon/hwmon0/device/pwm[0-6]`; do | ||||
| 		echo 0 > ${pwm} | ||||
| 	done | ||||
| fi | ||||
| 
 | ||||
| # Ensure all mounts in /srv from OMV are cleaned up | ||||
| for dir in `ls /srv | grep dev-disk`; do | ||||
| 	umount -q /srv/${dir}; | ||||
| done | ||||
| 
 | ||||
| # Now for all disks, delete from bus | ||||
| for dsk in sd{a..z}; do | ||||
| 	if [ -d "/sys/block/${dsk}/device" ]; then | ||||
| 		echo 1 > "/sys/block/${dsk}/device/delete" | ||||
| 	fi | ||||
| done | ||||
| 
 | ||||
| # Now for all disks, remove them with ui-hdd-pwrctl-v2 if we have it | ||||
| if [ -d "/sys/bus/platform/drivers/ui-hdd-pwrctl-v2" ]; then | ||||
| 	for bay in `seq 0 7`; do | ||||
| 		echo ${bay} > "$(realpath /sys/bus/platform/drivers/ui-hdd-pwrctl-v2/*hdd_pwrctl-v2)/hdd_force_poweroff" | ||||
| 	done | ||||
| fi | ||||
| # Let the disks spool down a sec... | ||||
| sleep 2 | ||||
|  | @ -24,4 +24,10 @@ if [ ! -f ${root_path}/downloads/${kernel_filename} ]; then | |||
|     wget ${kernel_src} -O ${root_path}/downloads/${kernel_filename} | ||||
| fi | ||||
| 
 | ||||
| # Bluez | ||||
| if [ ! -f ${root_path}/downloads/${bluez_filename} ]; then | ||||
|     debug_msg "Downloading Package Bluez..." | ||||
|     wget ${bluez_src} -O ${root_path}/downloads/${bluez_filename} | ||||
| fi | ||||
| 
 | ||||
| debug_msg "Finished 02_download_dependencies.sh" | ||||
|  |  | |||
|  | @ -18,6 +18,10 @@ if [ ! -d ${build_path}/kernel ]; then | |||
|     debug_msg "Docker: Building Kernel..." | ||||
|     docker run --ulimit nofile=1024 --rm -v "${root_path}:/repo:Z" -it ${docker_tag} /repo/scripts/docker/build_kernel.sh | ||||
| fi | ||||
| if [ ! -d ${build_path}/packages ]; then | ||||
|     debug_msg "Docker: Building Packages..." | ||||
|     docker run --ulimit nofile=1024 --rm -v "${root_path}:/repo:Z" -it ${docker_tag} /repo/scripts/docker/build_packages.sh | ||||
| fi | ||||
| 
 | ||||
| debug_msg "Doing safety checks... please enter your password for sudo if prompted..." | ||||
| # Before we do anything, make our dirs, and validate they are not mounted atm. If they are, exit! | ||||
|  |  | |||
|  | @ -32,7 +32,10 @@ apt-get -o Dpkg::Options::="--force-confold" -y --allow-downgrades \ | |||
|     bsdextrautils git binutils ca-certificates e2fsprogs haveged parted curl \ | ||||
|     locales console-common openssh-server less vim net-tools wireguard-tools \ | ||||
|     ntpsec u-boot-tools wget initramfs-tools python3-flask gnupg libc-ares2  \ | ||||
|     dfu-util | ||||
|     dfu-util bluez | ||||
| 
 | ||||
| # Enable bluetooth | ||||
| systemctl enable bluetooth | ||||
| 
 | ||||
| # Locale gen | ||||
| locale-gen | ||||
|  |  | |||
|  | @ -37,9 +37,9 @@ fi | |||
| # some modules. This is why some lines below are commented out. | ||||
| 
 | ||||
| # Build as normal, with our extra version set to a timestamp | ||||
| make ${kernel_config}  | ||||
| make ${kernel_config} | ||||
| make -j`getconf _NPROCESSORS_ONLN` EXTRAVERSION=-alpine-unvr # Build kernel and modules | ||||
| #make -j`getconf _NPROCESSORS_ONLN` EXTRAVERSION=-alpine-unvr Image.gz # makes gzip image | ||||
| #make -j`getconf _NPROCESSORS_ONLN` EXTRAVERSION=-alpine-unvr Image.gz # makes gzip image (we should just do this ourselves, skip using make) | ||||
| make INSTALL_MOD_PATH=./modules-dir -j`getconf _NPROCESSORS_ONLN` EXTRAVERSION=-alpine-unvr modules_install # installs modules to dir | ||||
| #mkimage -A arm64 -O linux -T kernel -C gzip -a 04080000 -e 04080000 -n "Linux-UNVR-NAS-$(date +%Y%m%d-%H%M%S)" -d ./arch/arm64/boot/Image.gz uImage | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										55
									
								
								scripts/docker/build_packages.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										55
									
								
								scripts/docker/build_packages.sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,55 @@ | |||
| #!/bin/bash | ||||
| set -e | ||||
| 
 | ||||
| scripts_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )" | ||||
| . ${scripts_path}/vars.sh | ||||
| 
 | ||||
| # Exports baby | ||||
| export PATH=${build_path}/toolchain/${toolchain_bin_path}:${PATH} | ||||
| export GCC_COLORS=auto | ||||
| export CROSS_COMPILE=${toolchain_cross_compile} | ||||
| export ARCH=arm64 | ||||
| 
 | ||||
| # Make our temp builddir for bluez so we can make bccmd | ||||
| bluez_builddir=$(mktemp -d) | ||||
| tar -xzf ${root_path}/downloads/${bluez_filename} -C ${bluez_builddir} | ||||
| 
 | ||||
| # Start with Bluez | ||||
| cd ${bluez_builddir}/${bluez_repopath} | ||||
| 
 | ||||
| # If we have patches, apply them | ||||
| if [[ -d ${root_path}/patches/bluez/ ]]; then | ||||
|     for file in ${root_path}/patches/bluez/*.patch; do | ||||
|         echo "Applying bluez patch ${file}" | ||||
|         patch -p1 < ${file} | ||||
|     done | ||||
| fi | ||||
| 
 | ||||
| # Build bccmd from bluez | ||||
| ./bootstrap | ||||
| ./configure --disable-systemd \ | ||||
|     --enable-deprecated \ | ||||
|     --disable-library \ | ||||
|     --disable-cups \ | ||||
|     --disable-datafiles \ | ||||
|     --disable-manpages \ | ||||
|     --disable-pie \ | ||||
|     --disable-client \ | ||||
|     --disable-obex \ | ||||
|     --disable-udev \ | ||||
|     --build=x86_64-linux-gnu \ | ||||
|     --host=aarch64-none-linux-gnu \ | ||||
|     --target=aarch64-none-linux-gnu | ||||
| make lib/bluetooth/hci.h lib/bluetooth/bluetooth.h lib/libbluetooth-internal.la tools/bccmd -j`getconf _NPROCESSORS_ONLN` | ||||
| 
 | ||||
| # Save our binary | ||||
| mkdir -p ${build_path}/packages/bluez | ||||
| mv ./tools/bccmd  ${build_path}/packages/bluez/ | ||||
| 
 | ||||
| # Build ubnteeprom (our own tool) | ||||
| mkdir -p ${build_path}/packages/ubnteeprom | ||||
| env GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o ${build_path}/packages/ubnteeprom/ubnteeprom ${root_path}/tools/ubnteeprom/main.go | ||||
| 
 | ||||
| # Cleanup | ||||
| cd - > /dev/null | ||||
| rm -rf ${bluez_builddir} | ||||
|  | @ -35,8 +35,8 @@ if [[ -d ${root_path}/overlay/${fs_overlay_dir}/ ]]; then | |||
| fi | ||||
| 
 | ||||
| # Apply our part UUIDs to fstab | ||||
| sed -i "s|BOOTUUIDPLACEHOLDER|$(blkid -o value -s UUID ${build_path}/boot.ext4)|g" ${build_path}/rootfs/etc/fstab | ||||
| sed -i "s|ROOTUUIDPLACEHOLDER|$(blkid -o value -s UUID ${build_path}/rootfs.ext4)|g" ${build_path}/rootfs/etc/fstab | ||||
| #sed -i "s|BOOTUUIDPLACEHOLDER|$(blkid -o value -s UUID ${build_path}/boot.ext4)|g" ${build_path}/rootfs/etc/fstab | ||||
| #sed -i "s|ROOTUUIDPLACEHOLDER|$(blkid -o value -s UUID ${build_path}/rootfs.ext4)|g" ${build_path}/rootfs/etc/fstab | ||||
| 
 | ||||
| # Hostname | ||||
| echo "${distrib_name}" > ${build_path}/rootfs/etc/hostname | ||||
|  | @ -56,6 +56,18 @@ for file in libgrpc++.so.1 libgrpc.so.10 libprotobuf.so.23 \ | |||
| 	cp -H ${build_path}/fw-extract/rootfs/usr/lib/aarch64-linux-gnu/${file} "${build_path}/rootfs/usr/lib/ubnt-fw/" | ||||
| done | ||||
| 
 | ||||
| # Copy over bluetooth firmware files | ||||
| mkdir -p "${build_path}/rootfs/lib/firmware" | ||||
| cp -R "${build_path}/fw-extract/rootfs/lib/firmware/csr8x11" "${build_path}/rootfs/lib/firmware/" # LCD panel firmwares | ||||
| 
 | ||||
| # Install our bccmd we compiled (less we use from unifi the better) | ||||
| cp -R "${build_path}/packages/bluez/bccmd" "${build_path}/rootfs/usr/bin" | ||||
| chmod +x "${build_path}/rootfs/usr/bin/bccmd" | ||||
| 
 | ||||
| # Install our ubnteeprom tool | ||||
| cp -R "${build_path}/packages/ubnteeprom/ubnteeprom" "${build_path}/rootfs/usr/bin" | ||||
| chmod +x "${build_path}/rootfs/usr/bin/ubnteeprom" | ||||
| 
 | ||||
| # Kick off bash setup script within chroot | ||||
| cp ${docker_scripts_path}/bootstrap/001-bootstrap ${build_path}/rootfs/bootstrap | ||||
| chroot ${build_path}/rootfs /bootstrap | ||||
|  |  | |||
|  | @ -27,6 +27,11 @@ genimage_src="https://github.com/pengutronix/genimage/releases/download/v16/geni | |||
| genimage_filename="$(basename ${genimage_src})" | ||||
| genimage_repopath="${genimage_filename%.tar.xz}" | ||||
| 
 | ||||
| # bluez | ||||
| bluez_src="https://github.com/bluez/bluez/archive/refs/tags/5.55.tar.gz" | ||||
| bluez_filename="bluez-$(basename ${bluez_src})" | ||||
| bluez_repopath="${bluez_filename%.tar.gz}" | ||||
| 
 | ||||
| # Distro | ||||
| distrib_name="debian" | ||||
| #deb_mirror="http://ftp.us.debian.org/debian" | ||||
|  |  | |||
							
								
								
									
										343
									
								
								tools/ubnteeprom/main.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								tools/ubnteeprom/main.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,343 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // Type for EEPROM structure | ||||
| type EEPROM_Value struct { | ||||
| 	name, description, vtype string | ||||
| 	offset, length           int64 | ||||
| } | ||||
| 
 | ||||
| // Build our BOARD eeprom structure | ||||
| var BOARD = []EEPROM_Value{ | ||||
| 	{ | ||||
| 		name:        "format", | ||||
| 		description: "EEPROM Format", | ||||
| 		offset:      0x800C, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "version", | ||||
| 		description: "EEPROM Version", | ||||
| 		offset:      0x800E, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "boardid", | ||||
| 		description: "Board Identifier (bomrev+model identifier)", | ||||
| 		offset:      0x8012, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "vendorid", | ||||
| 		description: "Vendor Identifier", | ||||
| 		offset:      0x8010, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "bomrev", | ||||
| 		description: "Bill of Materials Revision", | ||||
| 		offset:      0x8014, | ||||
| 		length:      0x4, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "hwaddrbbase", | ||||
| 		description: "Base Mac Address for Device", | ||||
| 		offset:      0x8018, | ||||
| 		length:      0x6, | ||||
| 		vtype:       "hexmac", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "EthMACAddrCount", | ||||
| 		description: "Number of MAC addresses for ethernet interfaces", | ||||
| 		offset:      0x801E, | ||||
| 		length:      0x1, | ||||
| 		vtype:       "hexint", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "WiFiMACAddrCount", | ||||
| 		description: "Number of MAC addresses for WiFi interfaces", | ||||
| 		offset:      0x801F, | ||||
| 		length:      0x1, | ||||
| 		vtype:       "hexint", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "BtMACAddrCount", | ||||
| 		description: "Number of MAC addresses for Bluetooth interfaces", | ||||
| 		offset:      0x8070, | ||||
| 		length:      0x1, | ||||
| 		vtype:       "hexint", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "regdmn[0]", | ||||
| 		description: "Region Domain 0", | ||||
| 		offset:      0x8020, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "regdmn[1]", | ||||
| 		description: "Region Domain 1", | ||||
| 		offset:      0x8022, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "regdmn[2]", | ||||
| 		description: "Region Domain 2", | ||||
| 		offset:      0x8024, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "regdmn[3]", | ||||
| 		description: "Region Domain 3", | ||||
| 		offset:      0x8026, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "regdmn[4]", | ||||
| 		description: "Region Domain 4", | ||||
| 		offset:      0x8028, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "regdmn[5]", | ||||
| 		description: "Region Domain 5", | ||||
| 		offset:      0x802A, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "regdmn[6]", | ||||
| 		description: "Region Domain 6", | ||||
| 		offset:      0x802C, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "regdmn[7]", | ||||
| 		description: "Region Domain 7", | ||||
| 		offset:      0x802E, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| // Build our SYSTEM_INFO eeprom structure | ||||
| var SYSTEM_INFO = []EEPROM_Value{ | ||||
| 	// Missing values: | ||||
| 	// cpu | ||||
| 	// cpuid | ||||
| 	// flashSize (this is static in unifi's kernel module -_-) | ||||
| 	// ramsize | ||||
| 	{ | ||||
| 		name:        "vendorid", | ||||
| 		description: "Vendor Identifier", | ||||
| 		offset:      0x8010, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "systemid", | ||||
| 		description: "Device Model/Revision Identifier", | ||||
| 		offset:      0xC, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	// shortname (we may wanna map boardid for this) | ||||
| 	{ | ||||
| 		name:        "boardrevision", | ||||
| 		description: "Board Revision for the device", | ||||
| 		offset:      0x13, | ||||
| 		length:      0x1, | ||||
| 		vtype:       "hextobase10", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "serialno", | ||||
| 		description: "Serial Number", | ||||
| 		offset:      0x0, | ||||
| 		length:      0x5, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	// manufid | ||||
| 	// mfgweek | ||||
| 	// qrid | ||||
| 	// eth*.macaddr (generated mac's for all eth interfaces) | ||||
| 	// device.hashid | ||||
| 	// device.anonid | ||||
| 	// bt0.macaddr (generated bt mac) | ||||
| 	{ | ||||
| 		name:        "regdmn[]", | ||||
| 		description: "Region Domain", | ||||
| 		offset:      0x8020, | ||||
| 		length:      0x10, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	// cpu_rev_id | ||||
| } | ||||
| 
 | ||||
| // Build our vars that are similar to running ubnt-tools id | ||||
| var UBNT_TOOLS = []EEPROM_Value{ | ||||
| 	{ | ||||
| 		name:        "board.sysid", | ||||
| 		description: "Device Model/Revision Identifier", | ||||
| 		offset:      0xC, | ||||
| 		length:      0x2, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "board.serialno", | ||||
| 		description: "Serial Number", | ||||
| 		offset:      0x0, | ||||
| 		length:      0x5, | ||||
| 		vtype:       "hex", | ||||
| 	}, | ||||
| 	{ | ||||
| 		name:        "board.bom", | ||||
| 		description: "Board Bill of Materials Revision Code", | ||||
| 		offset:      0xD024, | ||||
| 		length:      0xC, | ||||
| 		vtype:       "str", | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| func check(e error) { | ||||
| 	if e != nil { | ||||
| 		if strings.Contains(e.Error(), "encoding/hex: invalid byte:") { | ||||
| 			fmt.Printf("Error: Unable to parse hex, please check your input.\n") | ||||
| 		} else if strings.Contains(e.Error(), "EOF") { | ||||
| 			fmt.Printf("Error: Unable to read contents from EEPROM/file.\n") | ||||
| 		} else if strings.Contains(e.Error(), "encoding/hex: odd length hex string") { | ||||
| 			fmt.Printf("Error: Incorrect length of input. Please try again.\n") | ||||
| 		} else { | ||||
| 			fmt.Printf("Fatal Error!!! ") | ||||
| 			panic(e) | ||||
| 		} | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func eeprom_read(vl []EEPROM_Value, f *os.File, key string) string { | ||||
| 	var offs, leng int64 | ||||
| 	var vtype string | ||||
| 
 | ||||
| 	// Lookup our item | ||||
| 	for _, v := range vl { | ||||
| 		if v.name == key { | ||||
| 			offs = v.offset | ||||
| 			leng = v.length | ||||
| 			vtype = v.vtype | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Make sure we found it | ||||
| 	if (offs == 0) && (leng == 0) { | ||||
| 		fmt.Printf("Error: Invalid key %s!\n", key) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	// Seek our file | ||||
| 	_, err := f.Seek(offs, 0) | ||||
| 	check(err) | ||||
| 
 | ||||
| 	// Make var and read into it | ||||
| 	b2 := make([]byte, leng) | ||||
| 	_, err = f.Read(b2) | ||||
| 	check(err) | ||||
| 
 | ||||
| 	// Format as needed depending on type | ||||
| 	switch vtype { | ||||
| 	case "hexmac": | ||||
| 		// Mac is stored in hex, but we need to format the return | ||||
| 		macstr := net.HardwareAddr(b2[:]).String() | ||||
| 		return macstr | ||||
| 	case "hexint": | ||||
| 		// Int is stored in hex | ||||
| 		if b2[0]&0x0 == 0x0 { | ||||
| 			// We start with 0, so strip | ||||
| 			return strings.TrimPrefix(hex.EncodeToString(b2), `0`) | ||||
| 		} else { | ||||
| 			// We do not start with 0, so carry on | ||||
| 			return hex.EncodeToString(b2) | ||||
| 		} | ||||
| 	case "hextobase10": | ||||
| 		// Hex value needs to be moved to base 10 | ||||
| 		base_conversion, err := strconv.ParseInt(hex.EncodeToString(b2), 16, 64) | ||||
| 		check(err) | ||||
| 		return strconv.Itoa(int(base_conversion)) | ||||
| 	case "str": | ||||
| 		// String value | ||||
| 		return string(b2) | ||||
| 	default: | ||||
| 		// Default is to assume hex | ||||
| 		return hex.EncodeToString(b2) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func return_values(values []EEPROM_Value, file string, filter string) { | ||||
| 	// Open EEPROM for read only | ||||
| 	f, err := os.Open(file) | ||||
| 	defer f.Close() | ||||
| 	check(err) | ||||
| 
 | ||||
| 	// If select is set, select our item, else return all | ||||
| 	if len(filter) > 0 { | ||||
| 		// Read value | ||||
| 		fmt.Printf("%s\n", eeprom_read(values, f, filter)) | ||||
| 	} else { | ||||
| 		// read all | ||||
| 		for _, v := range values { | ||||
| 			fmt.Printf("%s=%s\n", v.name, eeprom_read(values, f, v.name)) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	// Start by defining our args | ||||
| 	argfile := flag.String("file", "/dev/mtd4", "The path to the EEPROM for the device") | ||||
| 	argboard := flag.Bool("board", false, "Print the board values") | ||||
| 	argsystem := flag.Bool("systeminfo", false, "Print the system info values") | ||||
| 	argtools := flag.Bool("tools", false, "Print similar values to ubnt-tools id") | ||||
| 	argfilter := flag.String("key", "", "Used to select a specific EEPROM value") | ||||
| 	flag.Parse() | ||||
| 
 | ||||
| 	// Verify we can read our eeprom file | ||||
| 	if _, err := os.Stat(*argfile); os.IsNotExist(err) { | ||||
| 		fmt.Printf("Error: Unable to access %s.\n", *argfile) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	// Is board set? | ||||
| 	if *argboard { | ||||
| 		return_values(BOARD, *argfile, *argfilter) | ||||
| 	} else if *argsystem { | ||||
| 		return_values(SYSTEM_INFO, *argfile, *argfilter) | ||||
| 	} else if *argtools { | ||||
| 		return_values(UBNT_TOOLS, *argfile, *argfilter) | ||||
| 	} else { | ||||
| 		// Tell user noting was submitted | ||||
| 		fmt.Fprintf(os.Stderr, "Error Invalid usage of %s:\n", os.Args[0]) | ||||
| 		flag.PrintDefaults() | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	// We be done | ||||
| 	os.Exit(0) | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue