From 91fe520152ec2199b59029ae991d50318085d2ac Mon Sep 17 00:00:00 2001 From: "github-action[bot]" Date: Mon, 1 Jul 2024 20:30:45 +0200 Subject: [PATCH] Update On Mon Jul 1 20:30:44 CEST 2024 --- .github/update.log | 1 + .../golang/clash/adapter/outbound/direct.go | 24 +- .../clash/adapter/outbound/wireguard.go | 160 +- .../clash/adapter/outboundgroup/relay.go | 2 + .../golang/clash/adapter/provider/parser.go | 3 + .../golang/clash/adapter/provider/provider.go | 49 +- .../golang/clash/common/utils/callback.go | 50 + .../golang/clash/component/cidr/ipcidr_set.go | 8 +- .../golang/clash/component/dialer/dialer.go | 6 +- .../golang/clash/component/iface/iface.go | 10 +- .../clash/component/process/process_linux.go | 1 - .../src/foss/golang/clash/config/config.go | 148 +- .../clash/constant/provider/interface.go | 8 +- .../src/foss/golang/clash/constant/rule.go | 1 + .../core/src/foss/golang/clash/dns/client.go | 47 +- .../core/src/foss/golang/clash/dns/dialer.go | 11 + .../core/src/foss/golang/clash/dns/doh.go | 35 +- .../core/src/foss/golang/clash/dns/doq.go | 16 +- .../core/src/foss/golang/clash/dns/policy.go | 13 +- .../src/foss/golang/clash/dns/resolver.go | 9 +- .../core/src/foss/golang/clash/dns/util.go | 132 +- .../src/foss/golang/clash/docs/config.yaml | 27 +- .../core/src/foss/golang/clash/go.mod | 43 +- .../core/src/foss/golang/clash/go.sum | 88 +- .../golang/clash/hub/executor/executor.go | 12 +- .../foss/golang/clash/hub/route/configs.go | 72 +- .../foss/golang/clash/listener/config/tun.go | 47 +- .../foss/golang/clash/listener/inbound/tun.go | 116 +- .../foss/golang/clash/listener/listener.go | 28 +- .../foss/golang/clash/listener/sing/sing.go | 6 + .../golang/clash/listener/sing_tun/dns.go | 7 + .../golang/clash/listener/sing_tun/iface.go | 70 + .../clash/listener/sing_tun/redirect_linux.go | 3 + .../clash/listener/sing_tun/redirect_stub.go | 5 + .../golang/clash/listener/sing_tun/server.go | 215 +- .../clash/listener/tproxy/tproxy_iptables.go | 4 +- .../foss/golang/clash/rules/common/base.go | 2 + .../foss/golang/clash/rules/logic/logic.go | 12 +- .../clash/rules/provider/ipcidr_strategy.go | 6 + .../clash/rules/provider/patch_android.go | 4 +- .../golang/clash/rules/provider/provider.go | 42 +- .../golang/clash/rules/provider/rule_set.go | 51 +- .../foss/golang/clash/tunnel/dns_dialer.go | 186 + .../src/foss/golang/clash/tunnel/tunnel.go | 116 +- .../core/src/foss/golang/go.mod | 41 +- .../core/src/foss/golang/go.sum | 84 +- .../core/src/main/golang/go.mod | 41 +- .../core/src/main/golang/go.sum | 84 +- clash-nyanpasu/backend/Cargo.lock | 5 +- clash-nyanpasu/backend/tauri/Cargo.toml | 1 + clash-nyanpasu/backend/tauri/src/cmds.rs | 18 +- .../backend/tauri/src/core/updater.rs | 384 -- .../tauri/src/core/updater/instance.rs | 341 ++ .../backend/tauri/src/core/updater/mod.rs | 258 ++ .../backend/tauri/src/core/updater/shared.rs | 43 + clash-nyanpasu/backend/tauri/src/main.rs | 1 + .../backend/tauri/src/utils/candy.rs | 119 +- .../backend/tauri/src/utils/downloader.rs | 3 +- .../frontend/nyanpasu/src/pages/providers.tsx | 11 +- .../materialYou/components/basePage/index.tsx | 11 +- .../components/basePage/style.scss | 25 +- clash-nyanpasu/package.json | 2 +- clash-nyanpasu/pnpm-lock.yaml | 16 +- clash-verge-rev/.github/workflows/alpha.yml | 8 +- clash-verge-rev/.github/workflows/release.yml | 6 +- .../src-tauri/src/config/config.rs | 17 + .../src-tauri/src/config/prfitem.rs | 30 +- clash-verge-rev/src-tauri/src/config/verge.rs | 5 + clash-verge-rev/src-tauri/src/core/sysopt.rs | 20 +- clash-verge-rev/src-tauri/src/enhance/mod.rs | 61 +- .../src/components/profile/profile-item.tsx | 8 +- .../src/components/profile/profile-more.tsx | 188 + .../setting/mods/sysproxy-viewer.tsx | 17 + clash-verge-rev/src/locales/en.json | 7 +- clash-verge-rev/src/locales/fa.json | 7 +- clash-verge-rev/src/locales/ru.json | 7 +- clash-verge-rev/src/locales/zh.json | 13 +- clash-verge-rev/src/pages/profiles.tsx | 39 + clash-verge-rev/src/services/types.d.ts | 1 + hysteria/app/cmd/server.go | 35 + hysteria/app/cmd/server_test.go | 7 + hysteria/app/cmd/server_test.yaml | 7 + hysteria/app/cmd/speedtest.go | 28 +- hysteria/app/go.mod | 12 +- hysteria/app/go.sum | 24 +- hysteria/core/go.mod | 8 +- hysteria/core/go.sum | 16 +- hysteria/extras/go.mod | 14 +- hysteria/extras/go.sum | 24 +- hysteria/extras/sniff/.mockery.yaml | 12 + hysteria/extras/sniff/internal/quic/LICENSE | 31 + hysteria/extras/sniff/internal/quic/README.md | 1 + hysteria/extras/sniff/internal/quic/header.go | 105 + .../sniff/internal/quic/packet_protector.go | 193 + .../internal/quic/packet_protector_test.go | 94 + .../extras/sniff/internal/quic/payload.go | 122 + hysteria/extras/sniff/internal/quic/quic.go | 59 + hysteria/extras/sniff/mock_Stream.go | 492 ++ hysteria/extras/sniff/sniff.go | 193 + hysteria/extras/sniff/sniff_test.go | 135 + hysteria/extras/transport/udphop/addr.go | 39 +- hysteria/extras/transport/udphop/addr_test.go | 132 - hysteria/extras/utils/portunion.go | 107 + hysteria/extras/utils/portunion_test.go | 92 + hysteria/go.work.sum | 4 + .../arm-trusted-firmware-mediatek/Makefile | 11 +- .../uboot-envtools/files/mediatek_filogic | 51 +- lede/package/boot/uboot-mediatek/Makefile | 327 +- .../patches/111-force-pylibfdt-build.patch | 30 + ...pport-for-Airoha-ethernet-PHY-driver.patch | 1929 -------- .../patches/412-add-ubnt-unifi-6-lr.patch | 606 +-- .../patches/421-zbtlink_zbt-wg3526-16m.patch | 314 -- .../patches/429-add-netcore-n60.patch | 433 -- .../patches/432-add-tplink-xdr608x.patch | 934 ---- .../patches/433-add-qihoo_360t7.patch | 425 -- .../434-add-xiaomi_mi-router-wr30u.patch | 461 -- .../patches/435-add-h3c_magic-nx30-pro.patch | 445 -- .../patches/437-add-cmcc_rax3000m.patch | 697 --- .../patches/438-add-jcg_q30-pro.patch | 420 -- .../patches/439-add-zyxel_ex5601-t0.patch | 431 -- .../440-add-xiaomi_mi-router-ax3000t.patch | 414 -- .../patches/441-add-jdcloud_re-cp-03.patch | 324 -- .../patches/442-add-bpi-r3-mini.patch | 779 ---- .../patches/443-add-nokia_ea0326gmp.patch | 413 -- .../patches/452-add-xiaomi-redmi-ax6s.patch | 320 -- .../patches/453-add-openwrt-one.patch | 3949 ----------------- lede/package/kernel/cryptodev-linux/Makefile | 2 +- .../0005-fix-build-for-linux-5.10.220+.patch | 11 + lede/package/system/fstools/Makefile | 11 +- ...port-extroot-for-non-MTD-rootfs_data.patch | 129 + lede/package/utils/fitblk/Makefile | 2 +- lede/target/linux/generic/config-5.15 | 1 - lede/target/linux/generic/config-6.1 | 1 - lede/target/linux/generic/config-6.6 | 667 ++- .../files/drivers/mtd/mtdsplit/Kconfig | 13 +- .../files/drivers/mtd/mtdsplit/Makefile | 2 - .../drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c | 16 +- .../files/drivers/mtd/mtdsplit/mtdsplit_fit.c | 20 +- .../drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c | 170 - .../drivers/mtd/mtdsplit/mtdsplit_seil.c | 191 - .../generic/files/drivers/mtd/nand/mtk_bmt.h | 8 +- .../files/drivers/mtd/nand/mtk_bmt_v2.c | 55 +- .../drivers/mtd/parsers/routerbootpart.c | 2 +- .../generic/files/drivers/net/phy/ar8216.c | 21 +- .../generic/files/drivers/net/phy/ar8216.h | 26 +- .../generic/files/drivers/net/phy/ar8327.c | 2 +- .../files/drivers/net/phy/b53/b53_common.c | 24 +- .../files/drivers/net/phy/b53/b53_mdio.c | 38 +- .../files/drivers/net/phy/b53/b53_mmap.c | 4 +- .../files/drivers/net/phy/b53/b53_priv.h | 8 +- .../files/drivers/net/phy/b53/b53_spi.c | 4 +- .../files/drivers/net/phy/b53/b53_srab.c | 4 +- .../generic/files/drivers/net/phy/mvswitch.c | 446 ++ .../generic/files/drivers/net/phy/mvswitch.h | 145 + .../generic/files/drivers/net/phy/psb6970.c | 17 +- .../files/drivers/net/phy/rtl8366_smi.c | 39 +- .../files/drivers/net/phy/rtl8366_smi.h | 5 +- .../generic/files/drivers/net/phy/rtl8367.c | 7 +- .../generic/files/drivers/net/phy/rtl8367b.c | 11 +- .../generic/files/drivers/net/phy/swconfig.c | 3 - .../files/drivers/net/phy/swconfig_leds.c | 9 +- .../files/drivers/platform/mikrotik/Kconfig | 7 +- .../files/drivers/platform/mikrotik/Makefile | 1 - .../drivers/platform/mikrotik/rb_hardconfig.c | 37 +- .../drivers/platform/mikrotik/rb_hardconfig.h | 32 - .../drivers/platform/mikrotik/rb_nvmem.c | 230 - .../drivers/platform/mikrotik/rb_softconfig.c | 35 +- .../drivers/platform/mikrotik/routerboot.c | 47 +- .../drivers/platform/mikrotik/routerboot.h | 8 +- ...add-uImage.FIT-subimage-block-driver.patch | 732 +++ ...ass-device-lookup-for-dev-fit-rootfs.patch | 25 + lede/target/linux/mediatek/Makefile | 4 +- .../uci-defaults/99_fwenv-store-ethaddr.sh | 1 - .../mediatek/dts/mt7986a-hf-m7986r1-emmc.dts | 86 - .../mediatek/dts/mt7986a-hf-m7986r1.dtsi | 86 + .../mt7988a-bananapi-bpi-r4-emmc.dtso | 62 + .../mediatek/mt7988a-bananapi-bpi-r4-poe.dts | 25 + .../mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso | 19 + .../mediatek/mt7988a-bananapi-bpi-r4-sd.dtso | 60 + .../mt7988a-bananapi-bpi-r4-wifi-mt7996a.dtso | 99 + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 395 ++ .../arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 8 +- .../mediatek/files/block/partitions/fit.c | 15 +- .../filogic/base-files/etc/board.d/01_leds | 3 +- .../filogic/base-files/etc/board.d/02_network | 4 +- .../etc/hotplug.d/ieee80211/11_fix_wifi_mac | 3 +- .../base-files/lib/upgrade/platform.sh | 53 +- lede/target/linux/mediatek/filogic/config-6.1 | 7 +- lede/target/linux/mediatek/filogic/config-6.6 | 1 - lede/target/linux/mediatek/filogic/target.mk | 2 +- lede/target/linux/mediatek/image/filogic.mk | 9 + lede/target/linux/mediatek/mt7629/config-5.15 | 1 + lede/target/linux/mediatek/mt7629/config-6.1 | 1 + .../041-block-fit-partition-parser.patch} | 0 .../041-block-fit-partition-parser.patch} | 0 mieru/pkg/congestion/bbr_sender.go | 210 + openwrt-packages/luci-app-store/Makefile | 2 +- .../luasrc/controller/store.lua | 4 + .../luci-app-store/root/etc/config/istore | 1 + small/hysteria/Makefile | 4 +- small/v2ray-geodata/Makefile | 4 +- .../com/v2ray/ang/util/AngConfigManager.kt | 8 +- .../main/kotlin/com/v2ray/ang/util/Utils.kt | 4 +- .../com/v2ray/ang/util/fmt/WireguardFmt.kt | 2 +- v2rayu/Podfile | 3 +- v2rayu/V2rayU.xcodeproj/project.pbxproj | 28 +- v2rayu/V2rayU/AppDelegate.swift | 5 +- v2rayu/V2rayU/AppVersion.swift | 614 +++ v2rayu/V2rayU/Assets.xcassets/Contents.json | 6 +- .../IconOn.imageset/Contents.json | 12 +- .../IconOn.imageset/icon@3x 1.png | Bin 0 -> 750 bytes .../IconOn.imageset/icon@3x.png | Bin 1465 -> 0 bytes .../Assets.xcassets/V2rayU.imageset/1024.png | Bin 0 -> 308675 bytes .../Assets.xcassets/V2rayU.imageset/128.png | Bin 0 -> 12764 bytes .../V2rayU.imageset/Contents.json | 18 + v2rayu/V2rayU/Base.lproj/PreferenceAbout.xib | 24 +- v2rayu/V2rayU/Base.lproj/ToastWindow.xib | 8 +- v2rayu/V2rayU/ConfigWindow.swift | 17 - v2rayu/V2rayU/Info.plist | 10 +- v2rayu/V2rayU/MainMenu.swift | 5 +- v2rayu/V2rayU/Ping.swift | 1 - .../V2rayU/Preference/PreferenceGeneral.swift | 1 - v2rayu/V2rayU/Preference/PreferencePac.swift | 1 - .../Preference/PreferenceSubscription.swift | 1 - v2rayu/V2rayU/Sparkle.swift | 2 +- v2rayu/V2rayU/Util.swift | 1 - v2rayu/V2rayU/V2rayLaunch.swift | 55 - v2rayu/V2rayU/V2raySubscription.swift | 1 - .../transport/internet/splithttp/dialer.go | 33 +- yass/.github/workflows/releases-rpm.yml | 6 +- yass/README.md | 4 +- yass/src/android/jni.cpp | 16 + yass/src/cli/cli.cpp | 19 +- yass/src/cli/cli_worker.cpp | 24 +- yass/src/gtk/yass.cpp | 15 + yass/src/gtk4/yass.cpp | 15 + yass/src/harmony/yass.cpp | 16 + .../extensions/YassPacketTunnelProvider.mm | 18 + yass/src/ios/main.mm | 15 + yass/src/mac/main.mm | 16 + yass/src/qt6/yass.cpp | 39 +- yass/src/server/server.cpp | 19 +- yass/src/ss_benchmark.cpp | 23 +- yass/src/ss_test.cpp | 24 +- yass/yass.spec.in | 10 +- yt-dlp/README.md | 5 + yt-dlp/yt_dlp/YoutubeDL.py | 2 + yt-dlp/yt_dlp/extractor/_extractors.py | 20 +- yt-dlp/yt_dlp/extractor/afreecatv.py | 41 +- yt-dlp/yt_dlp/extractor/digitalconcerthall.py | 61 +- yt-dlp/yt_dlp/extractor/graspop.py | 32 + yt-dlp/yt_dlp/extractor/jiocinema.py | 23 +- yt-dlp/yt_dlp/extractor/laracasts.py | 114 + yt-dlp/yt_dlp/extractor/microsoftembed.py | 258 +- .../extractor/microsoftvirtualacademy.py | 188 - yt-dlp/yt_dlp/extractor/nuum.py | 6 +- yt-dlp/yt_dlp/extractor/orf.py | 3 +- yt-dlp/yt_dlp/extractor/pokergo.py | 3 +- yt-dlp/yt_dlp/extractor/qqmusic.py | 544 ++- yt-dlp/yt_dlp/extractor/youtube.py | 5 +- 260 files changed, 9567 insertions(+), 16831 deletions(-) create mode 100644 clash-meta-android/core/src/foss/golang/clash/common/utils/callback.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/dns/dialer.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/iface.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/redirect_linux.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/redirect_stub.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/tunnel/dns_dialer.go delete mode 100644 clash-nyanpasu/backend/tauri/src/core/updater.rs create mode 100644 clash-nyanpasu/backend/tauri/src/core/updater/instance.rs create mode 100644 clash-nyanpasu/backend/tauri/src/core/updater/mod.rs create mode 100644 clash-nyanpasu/backend/tauri/src/core/updater/shared.rs create mode 100644 clash-verge-rev/src/components/profile/profile-more.tsx create mode 100644 hysteria/extras/sniff/.mockery.yaml create mode 100644 hysteria/extras/sniff/internal/quic/LICENSE create mode 100644 hysteria/extras/sniff/internal/quic/README.md create mode 100644 hysteria/extras/sniff/internal/quic/header.go create mode 100644 hysteria/extras/sniff/internal/quic/packet_protector.go create mode 100644 hysteria/extras/sniff/internal/quic/packet_protector_test.go create mode 100644 hysteria/extras/sniff/internal/quic/payload.go create mode 100644 hysteria/extras/sniff/internal/quic/quic.go create mode 100644 hysteria/extras/sniff/mock_Stream.go create mode 100644 hysteria/extras/sniff/sniff.go create mode 100644 hysteria/extras/sniff/sniff_test.go delete mode 100644 hysteria/extras/transport/udphop/addr_test.go create mode 100644 hysteria/extras/utils/portunion.go create mode 100644 hysteria/extras/utils/portunion_test.go create mode 100644 lede/package/boot/uboot-mediatek/patches/111-force-pylibfdt-build.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/160-net-phy-add-support-for-Airoha-ethernet-PHY-driver.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/421-zbtlink_zbt-wg3526-16m.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/429-add-netcore-n60.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/432-add-tplink-xdr608x.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/433-add-qihoo_360t7.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/434-add-xiaomi_mi-router-wr30u.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/435-add-h3c_magic-nx30-pro.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/437-add-cmcc_rax3000m.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/438-add-jcg_q30-pro.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/439-add-zyxel_ex5601-t0.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/440-add-xiaomi_mi-router-ax3000t.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/441-add-jdcloud_re-cp-03.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/442-add-bpi-r3-mini.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/443-add-nokia_ea0326gmp.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/452-add-xiaomi-redmi-ax6s.patch delete mode 100644 lede/package/boot/uboot-mediatek/patches/453-add-openwrt-one.patch create mode 100644 lede/package/kernel/cryptodev-linux/patches/0005-fix-build-for-linux-5.10.220+.patch create mode 100644 lede/package/system/fstools/patches/0001-fstools-support-extroot-for-non-MTD-rootfs_data.patch delete mode 100644 lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c delete mode 100644 lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seil.c create mode 100644 lede/target/linux/generic/files/drivers/net/phy/mvswitch.c create mode 100644 lede/target/linux/generic/files/drivers/net/phy/mvswitch.h delete mode 100644 lede/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.h delete mode 100644 lede/target/linux/generic/files/drivers/platform/mikrotik/rb_nvmem.c create mode 100644 lede/target/linux/generic/pending-6.1/510-block-add-uImage.FIT-subimage-block-driver.patch create mode 100644 lede/target/linux/generic/pending-6.1/511-init-bypass-device-lookup-for-dev-fit-rootfs.patch create mode 100644 lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso create mode 100644 lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-poe.dts create mode 100644 lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso create mode 100644 lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso create mode 100644 lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-wifi-mt7996a.dtso create mode 100644 lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts rename lede/target/linux/{generic/hack-5.15/410-block-fit-partition-parser.patch => mediatek/patches-5.15/041-block-fit-partition-parser.patch} (100%) rename lede/target/linux/{generic/hack-6.1/410-block-fit-partition-parser.patch => mediatek/patches-6.1/041-block-fit-partition-parser.patch} (100%) create mode 100644 mieru/pkg/congestion/bbr_sender.go create mode 100644 v2rayu/V2rayU/AppVersion.swift create mode 100644 v2rayu/V2rayU/Assets.xcassets/IconOn.imageset/icon@3x 1.png delete mode 100644 v2rayu/V2rayU/Assets.xcassets/IconOn.imageset/icon@3x.png create mode 100644 v2rayu/V2rayU/Assets.xcassets/V2rayU.imageset/1024.png create mode 100644 v2rayu/V2rayU/Assets.xcassets/V2rayU.imageset/128.png create mode 100644 v2rayu/V2rayU/Assets.xcassets/V2rayU.imageset/Contents.json create mode 100644 yt-dlp/yt_dlp/extractor/graspop.py create mode 100644 yt-dlp/yt_dlp/extractor/laracasts.py delete mode 100644 yt-dlp/yt_dlp/extractor/microsoftvirtualacademy.py diff --git a/.github/update.log b/.github/update.log index 1641f9b02f..9ffd083f42 100644 --- a/.github/update.log +++ b/.github/update.log @@ -689,3 +689,4 @@ Update On Thu Jun 27 20:29:48 CEST 2024 Update On Fri Jun 28 20:30:26 CEST 2024 Update On Sat Jun 29 20:29:36 CEST 2024 Update On Sun Jun 30 20:30:33 CEST 2024 +Update On Mon Jul 1 20:30:34 CEST 2024 diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/direct.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/direct.go index 1b01a576c4..7114045d63 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/direct.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/direct.go @@ -3,15 +3,19 @@ package outbound import ( "context" "errors" - "net/netip" + "os" + "strconv" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/loopback" "github.com/metacubex/mihomo/component/resolver" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/features" ) +var DisableLoopBackDetector, _ = strconv.ParseBool(os.Getenv("DISABLE_LOOPBACK_DETECTOR")) + type Direct struct { *Base loopBack *loopback.Detector @@ -24,8 +28,10 @@ type DirectOption struct { // DialContext implements C.ProxyAdapter func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { - if err := d.loopBack.CheckConn(metadata); err != nil { - return nil, err + if !features.CMFA && !DisableLoopBackDetector { + if err := d.loopBack.CheckConn(metadata); err != nil { + return nil, err + } } opts = append(opts, dialer.WithResolver(resolver.DefaultResolver)) c, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress(), d.Base.DialOptions(opts...)...) @@ -38,8 +44,10 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ... // ListenPacketContext implements C.ProxyAdapter func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { - if err := d.loopBack.CheckPacketConn(metadata); err != nil { - return nil, err + if !features.CMFA && !DisableLoopBackDetector { + if err := d.loopBack.CheckPacketConn(metadata); err != nil { + return nil, err + } } // net.UDPConn.WriteTo only working with *net.UDPAddr, so we need a net.UDPAddr if !metadata.Resolved() { @@ -49,13 +57,17 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, } metadata.DstIP = ip } - pc, err := dialer.NewDialer(d.Base.DialOptions(opts...)...).ListenPacket(ctx, "udp", "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort)) + pc, err := dialer.NewDialer(d.Base.DialOptions(opts...)...).ListenPacket(ctx, "udp", "", metadata.AddrPort()) if err != nil { return nil, err } return d.loopBack.NewPacketConn(newPacketConn(pc, d)), nil } +func (d *Direct) IsL3Protocol(metadata *C.Metadata) bool { + return true // tell DNSDialer don't send domain to DialContext, avoid lookback to DefaultResolver +} + func NewDirectWithOption(option DirectOption) *Direct { return &Direct{ Base: &Base{ diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/wireguard.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/wireguard.go index 976f395933..2e34dd83cd 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/wireguard.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/wireguard.go @@ -12,6 +12,7 @@ import ( "strconv" "strings" "sync" + "time" "github.com/metacubex/mihomo/common/atomic" CN "github.com/metacubex/mihomo/common/net" @@ -48,6 +49,10 @@ type WireGuard struct { connectAddr M.Socksaddr localPrefixes []netip.Prefix + serverAddrMap map[M.Socksaddr]netip.AddrPort + serverAddrTime atomic.TypedValue[time.Time] + serverAddrMutex sync.Mutex + closeCh chan struct{} // for test } @@ -67,6 +72,8 @@ type WireGuardOption struct { RemoteDnsResolve bool `proxy:"remote-dns-resolve,omitempty"` Dns []string `proxy:"dns,omitempty"` + + RefreshServerIPInterval int `proxy:"refresh-server-ip-interval,omitempty"` } type WireGuardPeerOption struct { @@ -287,6 +294,15 @@ func (w *WireGuard) resolve(ctx context.Context, address M.Socksaddr) (netip.Add } func (w *WireGuard) init(ctx context.Context) error { + err := w.init0(ctx) + if err != nil { + return err + } + w.updateServerAddr(ctx) + return nil +} + +func (w *WireGuard) init0(ctx context.Context) error { if w.initOk.Load() { return nil } @@ -301,41 +317,118 @@ func (w *WireGuard) init(ctx context.Context) error { } w.bind.ResetReservedForEndpoint() - ipcConf := "private_key=" + w.option.PrivateKey + w.serverAddrMap = make(map[M.Socksaddr]netip.AddrPort) + ipcConf, err := w.genIpcConf(ctx, false) + if err != nil { + // !!! do not set initErr here !!! + // let us can retry domain resolve in next time + return err + } + + if debug.Enabled { + log.SingLogger.Trace(fmt.Sprintf("[WG](%s) created wireguard ipc conf: \n %s", w.option.Name, ipcConf)) + } + err = w.device.IpcSet(ipcConf) + if err != nil { + w.initErr = E.Cause(err, "setup wireguard") + return w.initErr + } + w.serverAddrTime.Store(time.Now()) + + err = w.tunDevice.Start() + if err != nil { + w.initErr = err + return w.initErr + } + + w.initOk.Store(true) + return nil +} + +func (w *WireGuard) updateServerAddr(ctx context.Context) { + if w.option.RefreshServerIPInterval != 0 && time.Since(w.serverAddrTime.Load()) > time.Second*time.Duration(w.option.RefreshServerIPInterval) { + if w.serverAddrMutex.TryLock() { + defer w.serverAddrMutex.Unlock() + ipcConf, err := w.genIpcConf(ctx, true) + if err != nil { + log.Warnln("[WG](%s)UpdateServerAddr failed to generate wireguard ipc conf: %s", w.option.Name, err) + return + } + err = w.device.IpcSet(ipcConf) + if err != nil { + log.Warnln("[WG](%s)UpdateServerAddr failed to update wireguard ipc conf: %s", w.option.Name, err) + return + } + w.serverAddrTime.Store(time.Now()) + } + } +} + +func (w *WireGuard) genIpcConf(ctx context.Context, updateOnly bool) (string, error) { + ipcConf := "" + if !updateOnly { + ipcConf += "private_key=" + w.option.PrivateKey + "\n" + } if len(w.option.Peers) > 0 { for i, peer := range w.option.Peers { - destination, err := w.resolve(ctx, peer.Addr()) + peerAddr := peer.Addr() + destination, err := w.resolve(ctx, peerAddr) if err != nil { - // !!! do not set initErr here !!! - // let us can retry domain resolve in next time - return E.Cause(err, "resolve endpoint domain for peer ", i) + return "", E.Cause(err, "resolve endpoint domain for peer ", i) } - ipcConf += "\npublic_key=" + peer.PublicKey - ipcConf += "\nendpoint=" + destination.String() - if peer.PreSharedKey != "" { - ipcConf += "\npreshared_key=" + peer.PreSharedKey + if w.serverAddrMap[peerAddr] != destination { + w.serverAddrMap[peerAddr] = destination + } else if updateOnly { + continue } - for _, allowedIP := range peer.AllowedIPs { - ipcConf += "\nallowed_ip=" + allowedIP + + if len(w.option.Peers) == 1 { // must call SetConnectAddr if isConnect == true + w.bind.SetConnectAddr(destination) } + ipcConf += "public_key=" + peer.PublicKey + "\n" + if updateOnly { + ipcConf += "update_only=true\n" + } + ipcConf += "endpoint=" + destination.String() + "\n" if len(peer.Reserved) > 0 { var reserved [3]uint8 copy(reserved[:], w.option.Reserved) w.bind.SetReservedForEndpoint(destination, reserved) } + if updateOnly { + continue + } + if peer.PreSharedKey != "" { + ipcConf += "preshared_key=" + peer.PreSharedKey + "\n" + } + for _, allowedIP := range peer.AllowedIPs { + ipcConf += "allowed_ip=" + allowedIP + "\n" + } + if w.option.PersistentKeepalive != 0 { + ipcConf += fmt.Sprintf("persistent_keepalive_interval=%d\n", w.option.PersistentKeepalive) + } } } else { - ipcConf += "\npublic_key=" + w.option.PublicKey destination, err := w.resolve(ctx, w.connectAddr) if err != nil { - // !!! do not set initErr here !!! - // let us can retry domain resolve in next time - return E.Cause(err, "resolve endpoint domain") + return "", E.Cause(err, "resolve endpoint domain") + } + if w.serverAddrMap[w.connectAddr] != destination { + w.serverAddrMap[w.connectAddr] = destination + } else if updateOnly { + return "", nil + } + w.bind.SetConnectAddr(destination) // must call SetConnectAddr if isConnect == true + ipcConf += "public_key=" + w.option.PublicKey + "\n" + if updateOnly { + ipcConf += "update_only=true\n" + } + ipcConf += "endpoint=" + destination.String() + "\n" + if updateOnly { + return ipcConf, nil } - w.bind.SetConnectAddr(destination) - ipcConf += "\nendpoint=" + destination.String() if w.option.PreSharedKey != "" { - ipcConf += "\npreshared_key=" + w.option.PreSharedKey + ipcConf += "preshared_key=" + w.option.PreSharedKey + "\n" } var has4, has6 bool for _, address := range w.localPrefixes { @@ -346,34 +439,17 @@ func (w *WireGuard) init(ctx context.Context) error { } } if has4 { - ipcConf += "\nallowed_ip=0.0.0.0/0" + ipcConf += "allowed_ip=0.0.0.0/0\n" } if has6 { - ipcConf += "\nallowed_ip=::/0" + ipcConf += "allowed_ip=::/0\n" + } + + if w.option.PersistentKeepalive != 0 { + ipcConf += fmt.Sprintf("persistent_keepalive_interval=%d\n", w.option.PersistentKeepalive) } } - - if w.option.PersistentKeepalive != 0 { - ipcConf += fmt.Sprintf("\npersistent_keepalive_interval=%d", w.option.PersistentKeepalive) - } - - if debug.Enabled { - log.SingLogger.Trace(fmt.Sprintf("[WG](%s) created wireguard ipc conf: \n %s", w.option.Name, ipcConf)) - } - err := w.device.IpcSet(ipcConf) - if err != nil { - w.initErr = E.Cause(err, "setup wireguard") - return w.initErr - } - - err = w.tunDevice.Start() - if err != nil { - w.initErr = err - return w.initErr - } - - w.initOk.Store(true) - return nil + return ipcConf, nil } func closeWireGuard(w *WireGuard) { diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/relay.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/relay.go index 07fbcd9588..29aa9c6a74 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/relay.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/relay.go @@ -9,6 +9,7 @@ import ( "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/log" ) type Relay struct { @@ -149,6 +150,7 @@ func (r *Relay) Addr() string { } func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay { + log.Warnln("The group [%s] with relay type is deprecated, please using dialer-proxy instead", option.Name) return &Relay{ GroupBase: NewGroupBase(GroupBaseOption{ outbound.BaseOption{ diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go index 1094668d46..edb6b9110a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go @@ -28,7 +28,10 @@ type healthCheckSchema struct { } type OverrideSchema struct { + TFO *bool `provider:"tfo,omitempty"` + MPTcp *bool `provider:"mptcp,omitempty"` UDP *bool `provider:"udp,omitempty"` + UDPOverTCP *bool `provider:"udp-over-tcp,omitempty"` Up *string `provider:"up,omitempty"` Down *string `provider:"down,omitempty"` DialerProxy *string `provider:"dialer-proxy,omitempty"` diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go index daef017c95..694eae436f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net/http" + "reflect" "runtime" "strings" "time" @@ -373,37 +374,23 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray mapping["dialer-proxy"] = dialerProxy } - if override.UDP != nil { - mapping["udp"] = *override.UDP - } - if override.Up != nil { - mapping["up"] = *override.Up - } - if override.Down != nil { - mapping["down"] = *override.Down - } - if override.DialerProxy != nil { - mapping["dialer-proxy"] = *override.DialerProxy - } - if override.SkipCertVerify != nil { - mapping["skip-cert-verify"] = *override.SkipCertVerify - } - if override.Interface != nil { - mapping["interface-name"] = *override.Interface - } - if override.RoutingMark != nil { - mapping["routing-mark"] = *override.RoutingMark - } - if override.IPVersion != nil { - mapping["ip-version"] = *override.IPVersion - } - if override.AdditionalPrefix != nil { - name := mapping["name"].(string) - mapping["name"] = *override.AdditionalPrefix + name - } - if override.AdditionalSuffix != nil { - name := mapping["name"].(string) - mapping["name"] = name + *override.AdditionalSuffix + val := reflect.ValueOf(override) + for i := 0; i < val.NumField(); i++ { + field := val.Field(i) + if field.IsNil() { + continue + } + fieldName := strings.Split(val.Type().Field(i).Tag.Get("provider"), ",")[0] + switch fieldName { + case "additional-prefix": + name := mapping["name"].(string) + mapping["name"] = *field.Interface().(*string) + name + case "additional-suffix": + name := mapping["name"].(string) + mapping["name"] = name + *field.Interface().(*string) + default: + mapping[fieldName] = field.Elem().Interface() + } } proxy, err := adapter.ParseProxy(mapping) diff --git a/clash-meta-android/core/src/foss/golang/clash/common/utils/callback.go b/clash-meta-android/core/src/foss/golang/clash/common/utils/callback.go new file mode 100644 index 0000000000..df950d3a81 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/common/utils/callback.go @@ -0,0 +1,50 @@ +package utils + +import ( + "io" + "sync" + + list "github.com/bahlo/generic-list-go" +) + +type Callback[T any] struct { + list list.List[func(T)] + mutex sync.RWMutex +} + +func NewCallback[T any]() *Callback[T] { + return &Callback[T]{} +} + +func (c *Callback[T]) Register(item func(T)) io.Closer { + c.mutex.RLock() + defer c.mutex.RUnlock() + element := c.list.PushBack(item) + return &callbackCloser[T]{ + element: element, + callback: c, + } +} + +func (c *Callback[T]) Emit(item T) { + c.mutex.RLock() + defer c.mutex.RUnlock() + for element := c.list.Front(); element != nil; element = element.Next() { + go element.Value(item) + } +} + +type callbackCloser[T any] struct { + element *list.Element[func(T)] + callback *Callback[T] + once sync.Once +} + +func (c *callbackCloser[T]) Close() error { + c.once.Do(func() { + c.callback.mutex.Lock() + defer c.callback.mutex.Unlock() + c.callback.list.Remove(c.element) + }) + return nil +} diff --git a/clash-meta-android/core/src/foss/golang/clash/component/cidr/ipcidr_set.go b/clash-meta-android/core/src/foss/golang/clash/component/cidr/ipcidr_set.go index 0cb55e3647..521fabab13 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/cidr/ipcidr_set.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/cidr/ipcidr_set.go @@ -43,12 +43,12 @@ func (set *IpCidrSet) IsContainForString(ipString string) bool { } func (set *IpCidrSet) IsContain(ip netip.Addr) bool { - return set.toIPSet().Contains(ip.WithZone("")) + return set.ToIPSet().Contains(ip.WithZone("")) } func (set *IpCidrSet) Merge() error { var b netipx.IPSetBuilder - b.AddSet(set.toIPSet()) + b.AddSet(set.ToIPSet()) i, err := b.IPSet() if err != nil { return err @@ -57,7 +57,9 @@ func (set *IpCidrSet) Merge() error { return nil } -func (set *IpCidrSet) toIPSet() *netipx.IPSet { +// ToIPSet not safe convert to *netipx.IPSet +// be careful, must be used after Merge +func (set *IpCidrSet) ToIPSet() *netipx.IPSet { return (*netipx.IPSet)(unsafe.Pointer(set)) } diff --git a/clash-meta-android/core/src/foss/golang/clash/component/dialer/dialer.go b/clash-meta-android/core/src/foss/golang/clash/component/dialer/dialer.go index c21e638e4e..54a1aa6ac7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/dialer/dialer.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/dialer/dialer.go @@ -378,12 +378,12 @@ func (d Dialer) DialContext(ctx context.Context, network, address string) (net.C } func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { - opt := WithOption(d.Opt) + opt := d.Opt // make a copy if rAddrPort.Addr().Unmap().IsLoopback() { // avoid "The requested address is not valid in its context." - opt = WithInterface("") + WithInterface("")(&opt) } - return ListenPacket(ctx, ParseNetwork(network, rAddrPort.Addr()), address, rAddrPort, opt) + return ListenPacket(ctx, ParseNetwork(network, rAddrPort.Addr()), address, rAddrPort, WithOption(opt)) } func NewDialer(options ...Option) Dialer { diff --git a/clash-meta-android/core/src/foss/golang/clash/component/iface/iface.go b/clash-meta-android/core/src/foss/golang/clash/component/iface/iface.go index d543725a3d..272ee7377a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/iface/iface.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/iface/iface.go @@ -11,8 +11,9 @@ import ( type Interface struct { Index int + MTU int Name string - Addrs []netip.Prefix + Addresses []netip.Prefix HardwareAddr net.HardwareAddr } @@ -61,8 +62,9 @@ func Interfaces() (map[string]*Interface, error) { r[iface.Name] = &Interface{ Index: iface.Index, + MTU: iface.MTU, Name: iface.Name, - Addrs: ipNets, + Addresses: ipNets, HardwareAddr: iface.HardwareAddr, } } @@ -92,7 +94,7 @@ func IsLocalIp(ip netip.Addr) (bool, error) { return false, err } for _, iface := range ifaces { - for _, addr := range iface.Addrs { + for _, addr := range iface.Addresses { if addr.Contains(ip) { return true, nil } @@ -120,7 +122,7 @@ func (iface *Interface) PickIPv6Addr(destination netip.Addr) (netip.Prefix, erro func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr netip.Prefix) bool) (netip.Prefix, error) { var fallback netip.Prefix - for _, addr := range iface.Addrs { + for _, addr := range iface.Addresses { if !accept(addr) { continue } diff --git a/clash-meta-android/core/src/foss/golang/clash/component/process/process_linux.go b/clash-meta-android/core/src/foss/golang/clash/component/process/process_linux.go index 4667104cc2..45c89e5a5a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/process/process_linux.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/process/process_linux.go @@ -209,7 +209,6 @@ func findPackageName(uid uint32) string { }) if sharedPackage, loaded := packageManager.SharedPackageByID(uid % 100000); loaded { - fmt.Println(loaded) return sharedPackage } if packageName, loaded := packageManager.PackageByID(uid % 100000); loaded { diff --git a/clash-meta-android/core/src/foss/golang/clash/config/config.go b/clash-meta-android/core/src/foss/golang/clash/config/config.go index 74a2053e33..5676f7aae4 100644 --- a/clash-meta-android/core/src/foss/golang/clash/config/config.go +++ b/clash-meta-android/core/src/foss/golang/clash/config/config.go @@ -212,6 +212,7 @@ type RawDNS struct { IPv6Timeout uint `yaml:"ipv6-timeout" json:"ipv6-timeout"` UseHosts bool `yaml:"use-hosts" json:"use-hosts"` UseSystemHosts bool `yaml:"use-system-hosts" json:"use-system-hosts"` + RespectRules bool `yaml:"respect-rules" json:"respect-rules"` NameServer []string `yaml:"nameserver" json:"nameserver"` Fallback []string `yaml:"fallback" json:"fallback"` FallbackFilter RawFallbackFilter `yaml:"fallback-filter" json:"fallback-filter"` @@ -245,31 +246,39 @@ type RawTun struct { DNSHijack []string `yaml:"dns-hijack" json:"dns-hijack"` AutoRoute bool `yaml:"auto-route" json:"auto-route"` AutoDetectInterface bool `yaml:"auto-detect-interface"` - RedirectToTun []string `yaml:"-" json:"-"` MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` GSO bool `yaml:"gso" json:"gso,omitempty"` GSOMaxSize uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` - Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` + IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2_table_index,omitempty"` + IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2_rule_index,omitempty"` + AutoRedirect bool `yaml:"auto-redirect" json:"auto_redirect,omitempty"` + AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto_redirect_input_mark,omitempty"` + AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto_redirect_output_mark,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` + RouteAddress []netip.Prefix `yaml:"route-address" json:"route_address,omitempty"` + RouteAddressSet []string `yaml:"route-address-set" json:"route_address_set,omitempty"` + RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route_exclude_address,omitempty"` + RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route_exclude_address_set,omitempty"` + IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` + ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"` Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4_route_exclude_address,omitempty"` Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6_route_exclude_address,omitempty"` - IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` - ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` - FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` - TableIndex int `yaml:"table-index" json:"table-index"` } type RawTuicServer struct { @@ -563,13 +572,13 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } config.RuleProviders = ruleProviders - subRules, err := parseSubRules(rawCfg, proxies) + subRules, err := parseSubRules(rawCfg, proxies, ruleProviders) if err != nil { return nil, err } config.SubRules = subRules - rules, err := parseRules(rawCfg.Rule, proxies, subRules, "rules") + rules, err := parseRules(rawCfg.Rule, proxies, ruleProviders, subRules, "rules") if err != nil { return nil, err } @@ -665,7 +674,6 @@ func parseGeneral(cfg *RawConfig) (*General, error) { updater.ExternalUIURL = cfg.ExternalUIURL } - cfg.Tun.RedirectToTun = cfg.EBpf.RedirectToTun return &General{ Inbound: Inbound{ Port: cfg.Port, @@ -844,6 +852,7 @@ func parseListeners(cfg *RawConfig) (listeners map[string]C.InboundListener, err } func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]providerTypes.RuleProvider, err error) { + RP.SetTunnel(T.Tunnel) ruleProviders = map[string]providerTypes.RuleProvider{} // parse rule provider for name, mapping := range cfg.RuleProvider { @@ -853,12 +862,11 @@ func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]providerTypes. } ruleProviders[name] = rp - RP.SetRuleProvider(rp) } return } -func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules map[string][]C.Rule, err error) { +func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy, ruleProviders map[string]providerTypes.RuleProvider) (subRules map[string][]C.Rule, err error) { subRules = map[string][]C.Rule{} for name := range cfg.SubRules { subRules[name] = make([]C.Rule, 0) @@ -868,7 +876,7 @@ func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules map[str return nil, fmt.Errorf("sub-rule name is empty") } var rules []C.Rule - rules, err = parseRules(rawRules, proxies, subRules, fmt.Sprintf("sub-rules[%s]", name)) + rules, err = parseRules(rawRules, proxies, ruleProviders, subRules, fmt.Sprintf("sub-rules[%s]", name)) if err != nil { return nil, err } @@ -921,7 +929,7 @@ func verifySubRuleCircularReferences(n string, subRules map[string][]C.Rule, arr return nil } -func parseRules(rulesConfig []string, proxies map[string]C.Proxy, subRules map[string][]C.Rule, format string) ([]C.Rule, error) { +func parseRules(rulesConfig []string, proxies map[string]C.Proxy, ruleProviders map[string]providerTypes.RuleProvider, subRules map[string][]C.Rule, format string) ([]C.Rule, error) { var rules []C.Rule // parse rules @@ -970,6 +978,12 @@ func parseRules(rulesConfig []string, proxies map[string]C.Proxy, subRules map[s return nil, fmt.Errorf("%s[%d] [%s] error: %s", format, idx, line, parseErr.Error()) } + for _, name := range parsed.ProviderNames() { + if _, ok := ruleProviders[name]; !ok { + return nil, fmt.Errorf("%s[%d] [%s] error: rule set [%s] not found", format, idx, line, name) + } + } + rules = append(rules, parsed) } @@ -1039,10 +1053,20 @@ func hostWithDefaultPort(host string, defPort string) (string, error) { return net.JoinHostPort(hostname, port), nil } -func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) { +func parseNameServer(servers []string, respectRules bool, preferH3 bool) ([]dns.NameServer, error) { var nameservers []dns.NameServer for idx, server := range servers { + if strings.HasPrefix(server, "dhcp://") { + nameservers = append( + nameservers, + dns.NameServer{ + Net: "dhcp", + Addr: server[len("dhcp://"):], + }, + ) + continue + } server = parsePureDNSServer(server) u, err := url.Parse(server) if err != nil { @@ -1085,9 +1109,6 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) } } } - case "dhcp": - addr = u.Host - dnsNetType = "dhcp" // UDP from DHCP case "quic": addr, err = hostWithDefaultPort(u.Host, "853") dnsNetType = "quic" // DNS over QUIC @@ -1114,6 +1135,10 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error()) } + if respectRules && len(proxyName) == 0 { + proxyName = dns.RespectRules + } + nameservers = append( nameservers, dns.NameServer{ @@ -1130,7 +1155,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) func init() { dns.ParseNameServer = func(servers []string) ([]dns.NameServer, error) { // using by wireguard - return parseNameServer(servers, false) + return parseNameServer(servers, false, false) } } @@ -1156,7 +1181,8 @@ func parsePureDNSServer(server string) string { } } } -func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, preferH3 bool) (*orderedmap.OrderedMap[string, []dns.NameServer], error) { + +func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) (*orderedmap.OrderedMap[string, []dns.NameServer], error) { policy := orderedmap.New[string, []dns.NameServer]() updatedPolicy := orderedmap.New[string, any]() re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`) @@ -1202,7 +1228,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro if err != nil { return nil, err } - nameservers, err := parseNameServer(servers, preferH3) + nameservers, err := parseNameServer(servers, respectRules, preferH3) if err != nil { return nil, err } @@ -1296,6 +1322,10 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty") } + if cfg.RespectRules && len(cfg.ProxyServerNameserver) == 0 { + return nil, fmt.Errorf("if “respect-rules” is turned on, “proxy-server-nameserver” cannot be empty") + } + dnsCfg := &DNS{ Enable: cfg.Enable, Listen: cfg.Listen, @@ -1310,26 +1340,26 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul }, } var err error - if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer, cfg.PreferH3); err != nil { + if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer, cfg.RespectRules, cfg.PreferH3); err != nil { return nil, err } - if dnsCfg.Fallback, err = parseNameServer(cfg.Fallback, cfg.PreferH3); err != nil { + if dnsCfg.Fallback, err = parseNameServer(cfg.Fallback, cfg.RespectRules, cfg.PreferH3); err != nil { return nil, err } - if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, ruleProviders, cfg.PreferH3); err != nil { + if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil { return nil, err } - if dnsCfg.ProxyServerNameserver, err = parseNameServer(cfg.ProxyServerNameserver, cfg.PreferH3); err != nil { + if dnsCfg.ProxyServerNameserver, err = parseNameServer(cfg.ProxyServerNameserver, false, cfg.PreferH3); err != nil { return nil, err } if len(cfg.DefaultNameserver) == 0 { return nil, errors.New("default nameserver should have at least one nameserver") } - if dnsCfg.DefaultNameserver, err = parseNameServer(cfg.DefaultNameserver, cfg.PreferH3); err != nil { + if dnsCfg.DefaultNameserver, err = parseNameServer(cfg.DefaultNameserver, false, cfg.PreferH3); err != nil { return nil, err } // check default nameserver is pure ip addr @@ -1446,31 +1476,39 @@ func parseTun(rawTun RawTun, general *General) error { DNSHijack: rawTun.DNSHijack, AutoRoute: rawTun.AutoRoute, AutoDetectInterface: rawTun.AutoDetectInterface, - RedirectToTun: rawTun.RedirectToTun, - MTU: rawTun.MTU, - GSO: rawTun.GSO, - GSOMaxSize: rawTun.GSOMaxSize, - Inet4Address: []netip.Prefix{tunAddressPrefix}, - Inet6Address: rawTun.Inet6Address, - StrictRoute: rawTun.StrictRoute, + MTU: rawTun.MTU, + GSO: rawTun.GSO, + GSOMaxSize: rawTun.GSOMaxSize, + Inet4Address: []netip.Prefix{tunAddressPrefix}, + Inet6Address: rawTun.Inet6Address, + IPRoute2TableIndex: rawTun.IPRoute2TableIndex, + IPRoute2RuleIndex: rawTun.IPRoute2RuleIndex, + AutoRedirect: rawTun.AutoRedirect, + AutoRedirectInputMark: rawTun.AutoRedirectInputMark, + AutoRedirectOutputMark: rawTun.AutoRedirectOutputMark, + StrictRoute: rawTun.StrictRoute, + RouteAddress: rawTun.RouteAddress, + RouteAddressSet: rawTun.RouteAddressSet, + RouteExcludeAddress: rawTun.RouteExcludeAddress, + RouteExcludeAddressSet: rawTun.RouteExcludeAddressSet, + IncludeInterface: rawTun.IncludeInterface, + ExcludeInterface: rawTun.ExcludeInterface, + IncludeUID: rawTun.IncludeUID, + IncludeUIDRange: rawTun.IncludeUIDRange, + ExcludeUID: rawTun.ExcludeUID, + ExcludeUIDRange: rawTun.ExcludeUIDRange, + IncludeAndroidUser: rawTun.IncludeAndroidUser, + IncludePackage: rawTun.IncludePackage, + ExcludePackage: rawTun.ExcludePackage, + EndpointIndependentNat: rawTun.EndpointIndependentNat, + UDPTimeout: rawTun.UDPTimeout, + FileDescriptor: rawTun.FileDescriptor, + Inet4RouteAddress: rawTun.Inet4RouteAddress, Inet6RouteAddress: rawTun.Inet6RouteAddress, Inet4RouteExcludeAddress: rawTun.Inet4RouteExcludeAddress, Inet6RouteExcludeAddress: rawTun.Inet6RouteExcludeAddress, - IncludeInterface: rawTun.IncludeInterface, - ExcludeInterface: rawTun.ExcludeInterface, - IncludeUID: rawTun.IncludeUID, - IncludeUIDRange: rawTun.IncludeUIDRange, - ExcludeUID: rawTun.ExcludeUID, - ExcludeUIDRange: rawTun.ExcludeUIDRange, - IncludeAndroidUser: rawTun.IncludeAndroidUser, - IncludePackage: rawTun.IncludePackage, - ExcludePackage: rawTun.ExcludePackage, - EndpointIndependentNat: rawTun.EndpointIndependentNat, - UDPTimeout: rawTun.UDPTimeout, - FileDescriptor: rawTun.FileDescriptor, - TableIndex: rawTun.TableIndex, } return nil diff --git a/clash-meta-android/core/src/foss/golang/clash/constant/provider/interface.go b/clash-meta-android/core/src/foss/golang/clash/constant/provider/interface.go index bb73d1bce2..f7dfc9cc60 100644 --- a/clash-meta-android/core/src/foss/golang/clash/constant/provider/interface.go +++ b/clash-meta-android/core/src/foss/golang/clash/constant/provider/interface.go @@ -84,7 +84,7 @@ type RuleProvider interface { Match(*constant.Metadata) bool ShouldResolveIP() bool ShouldFindProcess() bool - AsRule(adaptor string) constant.Rule + Strategy() any } // Rule Behavior @@ -127,3 +127,9 @@ func (rf RuleFormat) String() string { return "Unknown" } } + +type Tunnel interface { + Providers() map[string]ProxyProvider + RuleProviders() map[string]RuleProvider + RuleUpdateCallback() *utils.Callback[RuleProvider] +} diff --git a/clash-meta-android/core/src/foss/golang/clash/constant/rule.go b/clash-meta-android/core/src/foss/golang/clash/constant/rule.go index 161c200a60..a91ee6cb07 100644 --- a/clash-meta-android/core/src/foss/golang/clash/constant/rule.go +++ b/clash-meta-android/core/src/foss/golang/clash/constant/rule.go @@ -116,4 +116,5 @@ type Rule interface { Payload() string ShouldResolveIP() bool ShouldFindProcess() bool + ProviderNames() []string } diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/client.go b/clash-meta-android/core/src/foss/golang/clash/dns/client.go index a6f0a7d492..096b96a7f5 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/client.go @@ -5,28 +5,20 @@ import ( "crypto/tls" "fmt" "net" - "net/netip" "strings" "github.com/metacubex/mihomo/component/ca" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/resolver" - C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" - "github.com/metacubex/randv2" D "github.com/miekg/dns" ) type client struct { *D.Client - r *Resolver - port string - host string - iface string - proxyAdapter C.ProxyAdapter - proxyName string - addr string + port string + host string + dialer *dnsDialer + addr string } var _ dnsClient = (*client)(nil) @@ -49,38 +41,13 @@ func (c *client) Address() string { } func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) { - var ( - ip netip.Addr - err error - ) - if c.r == nil { - // a default ip dns - if ip, err = netip.ParseAddr(c.host); err != nil { - return nil, fmt.Errorf("dns %s not a valid ip", c.host) - } - } else { - ips, err := resolver.LookupIPWithResolver(ctx, c.host, c.r) - if err != nil { - return nil, fmt.Errorf("use default dns resolve failed: %w", err) - } else if len(ips) == 0 { - return nil, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, c.host) - } - ip = ips[randv2.IntN(len(ips))] - } - network := "udp" if strings.HasPrefix(c.Client.Net, "tcp") { network = "tcp" } - var options []dialer.Option - if c.iface != "" { - options = append(options, dialer.WithInterface(c.iface)) - } - - dialHandler := getDialHandler(c.r, c.proxyAdapter, c.proxyName, options...) - addr := net.JoinHostPort(ip.String(), c.port) - conn, err := dialHandler(ctx, network, addr) + addr := net.JoinHostPort(c.host, c.port) + conn, err := c.dialer.DialContext(ctx, network, addr) if err != nil { return nil, err } @@ -115,7 +82,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) tcpClient.Net = "tcp" network = "tcp" log.Debugln("[DNS] Truncated reply from %s:%s for %s over UDP, retrying over TCP", c.host, c.port, m.Question[0].String()) - dConn.Conn, err = dialHandler(ctx, network, addr) + dConn.Conn, err = c.dialer.DialContext(ctx, network, addr) if err != nil { ch <- result{msg, err} return diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/dialer.go b/clash-meta-android/core/src/foss/golang/clash/dns/dialer.go new file mode 100644 index 0000000000..f4d9e128f8 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/dns/dialer.go @@ -0,0 +1,11 @@ +package dns + +// export functions from tunnel module + +import "github.com/metacubex/mihomo/tunnel" + +const RespectRules = tunnel.DnsRespectRules + +type dnsDialer = tunnel.DNSDialer + +var newDNSDialer = tunnel.NewDNSDialer diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/doh.go b/clash-meta-android/core/src/foss/golang/clash/dns/doh.go index 09d311b585..54b8279657 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/doh.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/doh.go @@ -62,10 +62,8 @@ type dnsOverHTTPS struct { quicConfig *quic.Config quicConfigGuard sync.Mutex url *url.URL - r *Resolver httpVersions []C.HTTPVersion - proxyAdapter C.ProxyAdapter - proxyName string + dialer *dnsDialer addr string } @@ -85,11 +83,9 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin } doh := &dnsOverHTTPS{ - url: u, - addr: u.String(), - r: r, - proxyAdapter: proxyAdapter, - proxyName: proxyName, + url: u, + addr: u.String(), + dialer: newDNSDialer(r, proxyAdapter, proxyName), quicConfig: &quic.Config{ KeepAlivePeriod: QUICKeepAlivePeriod, TokenStore: newQUICTokenStore(), @@ -388,13 +384,12 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp nextProtos = append(nextProtos, string(v)) } tlsConfig.NextProtos = nextProtos - dialContext := getDialHandler(doh.r, doh.proxyAdapter, doh.proxyName) if slices.Contains(doh.httpVersions, C.HTTPVersion3) { // First, we attempt to create an HTTP3 transport. If the probe QUIC // connection is established successfully, we'll be using HTTP3 for this // upstream. - transportH3, err := doh.createTransportH3(ctx, tlsConfig, dialContext) + transportH3, err := doh.createTransportH3(ctx, tlsConfig) if err == nil { log.Debugln("[%s] using HTTP/3 for this upstream: QUIC was faster", doh.url.String()) return transportH3, nil @@ -410,7 +405,7 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp transport := &http.Transport{ TLSClientConfig: tlsConfig, DisableCompression: true, - DialContext: dialContext, + DialContext: doh.dialer.DialContext, IdleConnTimeout: transportDefaultIdleConnTimeout, MaxConnsPerHost: dohMaxConnsPerHost, MaxIdleConns: dohMaxIdleConns, @@ -490,13 +485,12 @@ func (h *http3Transport) Close() (err error) { func (doh *dnsOverHTTPS) createTransportH3( ctx context.Context, tlsConfig *tls.Config, - dialContext dialHandler, ) (roundTripper http.RoundTripper, err error) { if !doh.supportsH3() { return nil, errors.New("HTTP3 support is not enabled") } - addr, err := doh.probeH3(ctx, tlsConfig, dialContext) + addr, err := doh.probeH3(ctx, tlsConfig) if err != nil { return nil, err } @@ -534,7 +528,7 @@ func (doh *dnsOverHTTPS) dialQuic(ctx context.Context, addr string, tlsCfg *tls. IP: net.ParseIP(ip), Port: portInt, } - conn, err := listenPacket(ctx, doh.proxyAdapter, doh.proxyName, "udp", addr, doh.r) + conn, err := doh.dialer.ListenPacket(ctx, "udp", addr) if err != nil { return nil, err } @@ -557,12 +551,11 @@ func (doh *dnsOverHTTPS) dialQuic(ctx context.Context, addr string, tlsCfg *tls. func (doh *dnsOverHTTPS) probeH3( ctx context.Context, tlsConfig *tls.Config, - dialContext dialHandler, ) (addr string, err error) { // We're using bootstrapped address instead of what's passed to the function // it does not create an actual connection, but it helps us determine // what IP is actually reachable (when there are v4/v6 addresses). - rawConn, err := dialContext(ctx, "udp", doh.url.Host) + rawConn, err := doh.dialer.DialContext(ctx, "udp", doh.url.Host) if err != nil { return "", fmt.Errorf("failed to dial: %w", err) } @@ -592,7 +585,7 @@ func (doh *dnsOverHTTPS) probeH3( chQuic := make(chan error, 1) chTLS := make(chan error, 1) go doh.probeQUIC(ctx, addr, probeTLSCfg, chQuic) - go doh.probeTLS(ctx, dialContext, probeTLSCfg, chTLS) + go doh.probeTLS(ctx, probeTLSCfg, chTLS) select { case quicErr := <-chQuic: @@ -635,10 +628,10 @@ func (doh *dnsOverHTTPS) probeQUIC(ctx context.Context, addr string, tlsConfig * // probeTLS attempts to establish a TLS connection to the specified address. We // run probeQUIC and probeTLS in parallel and see which one is faster. -func (doh *dnsOverHTTPS) probeTLS(ctx context.Context, dialContext dialHandler, tlsConfig *tls.Config, ch chan error) { +func (doh *dnsOverHTTPS) probeTLS(ctx context.Context, tlsConfig *tls.Config, ch chan error) { startTime := time.Now() - conn, err := doh.tlsDial(ctx, dialContext, "tcp", tlsConfig) + conn, err := doh.tlsDial(ctx, "tcp", tlsConfig) if err != nil { ch <- fmt.Errorf("opening TLS connection: %w", err) return @@ -694,10 +687,10 @@ func isHTTP3(client *http.Client) (ok bool) { // tlsDial is basically the same as tls.DialWithDialer, but we will call our own // dialContext function to get connection. -func (doh *dnsOverHTTPS) tlsDial(ctx context.Context, dialContext dialHandler, network string, config *tls.Config) (*tls.Conn, error) { +func (doh *dnsOverHTTPS) tlsDial(ctx context.Context, network string, config *tls.Config) (*tls.Conn, error) { // We're using bootstrapped address instead of what's passed // to the function. - rawConn, err := dialContext(ctx, network, doh.url.Host) + rawConn, err := doh.dialer.DialContext(ctx, network, doh.url.Host) if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/doq.go b/clash-meta-android/core/src/foss/golang/clash/dns/doq.go index 70b67c2a61..ad936f9575 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/doq.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/doq.go @@ -60,10 +60,8 @@ type dnsOverQUIC struct { bytesPool *sync.Pool bytesPoolGuard sync.Mutex - addr string - proxyAdapter C.ProxyAdapter - proxyName string - r *Resolver + addr string + dialer *dnsDialer } // type check @@ -72,10 +70,8 @@ var _ dnsClient = (*dnsOverQUIC)(nil) // newDoQ returns the DNS-over-QUIC Upstream. func newDoQ(resolver *Resolver, addr string, proxyAdapter C.ProxyAdapter, proxyName string) (dnsClient, error) { doq := &dnsOverQUIC{ - addr: addr, - proxyAdapter: proxyAdapter, - proxyName: proxyName, - r: resolver, + addr: addr, + dialer: newDNSDialer(resolver, proxyAdapter, proxyName), quicConfig: &quic.Config{ KeepAlivePeriod: QUICKeepAlivePeriod, TokenStore: newQUICTokenStore(), @@ -300,7 +296,7 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connectio // we're using bootstrapped address instead of what's passed to the function // it does not create an actual connection, but it helps us determine // what IP is actually reachable (when there're v4/v6 addresses). - rawConn, err := getDialHandler(doq.r, doq.proxyAdapter, doq.proxyName)(ctx, "udp", doq.addr) + rawConn, err := doq.dialer.DialContext(ctx, "udp", doq.addr) if err != nil { return nil, fmt.Errorf("failed to open a QUIC connection: %w", err) } @@ -315,7 +311,7 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connectio p, err := strconv.Atoi(port) udpAddr := net.UDPAddr{IP: net.ParseIP(ip), Port: p} - udp, err := listenPacket(ctx, doq.proxyAdapter, doq.proxyName, "udp", addr, doq.r) + udp, err := doq.dialer.ListenPacket(ctx, "udp", addr) if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/policy.go b/clash-meta-android/core/src/foss/golang/clash/dns/policy.go index a58123e3dc..fc60401b01 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/policy.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/policy.go @@ -37,14 +37,17 @@ func (p geositePolicy) Match(domain string) []dnsClient { } type domainSetPolicy struct { - domainSetProvider provider.RuleProvider - dnsClients []dnsClient + tunnel provider.Tunnel + name string + dnsClients []dnsClient } func (p domainSetPolicy) Match(domain string) []dnsClient { - metadata := &C.Metadata{Host: domain} - if ok := p.domainSetProvider.Match(metadata); ok { - return p.dnsClients + if ruleProvider, ok := p.tunnel.RuleProviders()[p.name]; ok { + metadata := &C.Metadata{Host: domain} + if ok := ruleProvider.Match(metadata); ok { + return p.dnsClients + } } return nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go b/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go index 08de69adff..28ffec6f15 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go @@ -414,7 +414,7 @@ type Config struct { Pool *fakeip.Pool Hosts *trie.DomainTrie[resolver.HostValue] Policy *orderedmap.OrderedMap[string, []NameServer] - RuleProviders map[string]provider.RuleProvider + Tunnel provider.Tunnel CacheAlgorithm string } @@ -502,11 +502,12 @@ func NewResolver(config Config) *Resolver { key := temp[1] switch prefix { case "rule-set": - if p, ok := config.RuleProviders[key]; ok { + if _, ok := config.Tunnel.RuleProviders()[key]; ok { log.Debugln("Adding rule-set policy: %s ", key) insertPolicy(domainSetPolicy{ - domainSetProvider: p, - dnsClients: cacheTransform(nameserver), + tunnel: config.Tunnel, + name: key, + dnsClients: cacheTransform(nameserver), }) continue } else { diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/util.go b/clash-meta-android/core/src/foss/golang/clash/dns/util.go index 516c63fb8d..e4ec5917cf 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/util.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/util.go @@ -7,18 +7,14 @@ import ( "fmt" "net" "net/netip" - "strconv" "strings" "time" - N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/nnip" "github.com/metacubex/mihomo/common/picker" "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/resolver" - C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" - "github.com/metacubex/mihomo/tunnel" D "github.com/miekg/dns" "github.com/samber/lo" @@ -120,6 +116,11 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { continue } + var options []dialer.Option + if s.Interface != "" { + options = append(options, dialer.WithInterface(s.Interface)) + } + host, port, _ := net.SplitHostPort(s.Addr) ret = append(ret, &client{ Client: &D.Client{ @@ -130,12 +131,9 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { UDPSize: 4096, Timeout: 5 * time.Second, }, - port: port, - host: host, - iface: s.Interface, - r: resolver, - proxyAdapter: s.ProxyAdapter, - proxyName: s.ProxyName, + port: port, + host: host, + dialer: newDNSDialer(resolver, s.ProxyAdapter, s.ProxyName, options...), }) } return ret @@ -175,120 +173,6 @@ func msgToDomain(msg *D.Msg) string { return "" } -type dialHandler func(ctx context.Context, network, addr string) (net.Conn, error) - -func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, opts ...dialer.Option) dialHandler { - return func(ctx context.Context, network, addr string) (net.Conn, error) { - if len(proxyName) == 0 && proxyAdapter == nil { - opts = append(opts, dialer.WithResolver(r)) - return dialer.DialContext(ctx, network, addr, opts...) - } else { - host, port, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - uintPort, err := strconv.ParseUint(port, 10, 16) - if err != nil { - return nil, err - } - if proxyAdapter == nil { - var ok bool - proxyAdapter, ok = tunnel.Proxies()[proxyName] - if !ok { - opts = append(opts, dialer.WithInterface(proxyName)) - } - } - - if strings.Contains(network, "tcp") { - // tcp can resolve host by remote - metadata := &C.Metadata{ - NetWork: C.TCP, - Host: host, - DstPort: uint16(uintPort), - } - if proxyAdapter != nil { - if proxyAdapter.IsL3Protocol(metadata) { // L3 proxy should resolve domain before to avoid loopback - dstIP, err := resolver.ResolveIPWithResolver(ctx, host, r) - if err != nil { - return nil, err - } - metadata.Host = "" - metadata.DstIP = dstIP - } - return proxyAdapter.DialContext(ctx, metadata, opts...) - } - opts = append(opts, dialer.WithResolver(r)) - return dialer.DialContext(ctx, network, addr, opts...) - } else { - // udp must resolve host first - dstIP, err := resolver.ResolveIPWithResolver(ctx, host, r) - if err != nil { - return nil, err - } - metadata := &C.Metadata{ - NetWork: C.UDP, - Host: "", - DstIP: dstIP, - DstPort: uint16(uintPort), - } - if proxyAdapter == nil { - return dialer.DialContext(ctx, network, addr, opts...) - } - - if !proxyAdapter.SupportUDP() { - return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter) - } - - packetConn, err := proxyAdapter.ListenPacketContext(ctx, metadata, opts...) - if err != nil { - return nil, err - } - - return N.NewBindPacketConn(packetConn, metadata.UDPAddr()), nil - } - } - } -} - -func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName string, network string, addr string, r *Resolver, opts ...dialer.Option) (net.PacketConn, error) { - host, port, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - uintPort, err := strconv.ParseUint(port, 10, 16) - if err != nil { - return nil, err - } - if proxyAdapter == nil { - var ok bool - proxyAdapter, ok = tunnel.Proxies()[proxyName] - if !ok { - opts = append(opts, dialer.WithInterface(proxyName)) - } - } - - // udp must resolve host first - dstIP, err := resolver.ResolveIPWithResolver(ctx, host, r) - if err != nil { - return nil, err - } - metadata := &C.Metadata{ - NetWork: C.UDP, - Host: "", - DstIP: dstIP, - DstPort: uint16(uintPort), - } - if proxyAdapter == nil { - return dialer.NewDialer(opts...).ListenPacket(ctx, network, "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort)) - } - - if !proxyAdapter.SupportUDP() { - return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter) - } - - return proxyAdapter.ListenPacketContext(ctx, metadata, opts...) -} - func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, cache bool, err error) { cache = true fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) diff --git a/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml b/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml index fe8501636e..9c51bc10b3 100644 --- a/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml +++ b/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml @@ -116,13 +116,25 @@ tun: # mtu: 9000 # 最大传输单元 # gso: false # 启用通用分段卸载,仅支持 Linux # gso-max-size: 65536 # 通用分段卸载包的最大大小 + auto-redirect: false # 自动配置 iptables 以重定向 TCP 连接。仅支持 Linux。带有 auto-redirect 的 auto-route 现在可以在路由器上按预期工作,无需干预。 # strict-route: true # 将所有连接路由到 tun 来防止泄漏,但你的设备将无法其他设备被访问 - inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 + route-address-set: # 将指定规则集中的目标 IP CIDR 规则添加到防火墙, 不匹配的流量将绕过路由, 仅支持 Linux,且需要 nftables,`auto-route` 和 `auto-redirect` 已启用。 + - ruleset-1 + - ruleset-2 + route-exclude-address-set: # 将指定规则集中的目标 IP CIDR 规则添加到防火墙, 匹配的流量将绕过路由, 仅支持 Linux,且需要 nftables,`auto-route` 和 `auto-redirect` 已启用。 + - ruleset-3 + - ruleset-4 + route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 - 0.0.0.0/1 - 128.0.0.0/1 - inet6-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 - "::/1" - "8000::/1" + # inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由(旧写法) + # - 0.0.0.0/1 + # - 128.0.0.0/1 + # inet6-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由(旧写法) + # - "::/1" + # - "8000::/1" # endpoint-independent-nat: false # 启用独立于端点的 NAT # include-interface: # 限制被路由的接口。默认不限制,与 `exclude-interface` 冲突 # - "lan0" @@ -209,7 +221,7 @@ tunnels: # one line config dns: cache-algorithm: arc enable: false # 关闭将使用系统 DNS - prefer-h3: true # 开启 DoH 支持 HTTP/3,将并发尝试 + prefer-h3: false # 是否开启 DoH 支持 HTTP/3,将并发尝试 listen: 0.0.0.0:53 # 开启 DNS 服务器监听 # ipv6: false # false 将返回 AAAA 的空结果 # ipv6-timeout: 300 # 单位:ms,内部双栈并发时,向上游查询 AAAA 时,等待 AAAA 的时间,默认 100ms @@ -227,6 +239,13 @@ dns: # use-hosts: true # 查询 hosts + # 配置后面的nameserver、fallback和nameserver-policy向dns服务器的连接过程是否遵守遵守rules规则 + # 如果为false(默认值)则这三部分的dns服务器在未特别指定的情况下会直连 + # 如果为true,将会按照rules的规则匹配链接方式(走代理或直连),如果有特别指定则任然以指定值为准 + # 仅当proxy-server-nameserver非空时可以开启此选项, 强烈不建议和prefer-h3一起使用 + # 此外,这三者配置中的dns服务器如果出现域名会采用default-nameserver配置项解析,也请确保正确配置default-nameserver + respect-rules: false + # 配置不使用 fake-ip 的域名 # fake-ip-filter: # - '*.lan' @@ -244,6 +263,7 @@ dns: - https://mozilla.cloudflare-dns.com/dns-query#DNS&h3=true # 指定策略组和使用 HTTP/3 - dhcp://en0 # dns from dhcp - quic://dns.adguard.com:784 # DNS over QUIC + # - '8.8.8.8#RULES' # 效果同respect-rules,但仅对该服务器生效 # - '8.8.8.8#en0' # 兼容指定 DNS 出口网卡 # 当配置 fallback 时,会查询 nameserver 中返回的 IP 是否为 CN,非必要配置 @@ -720,6 +740,7 @@ proxies: # socks5 # dialer-proxy: "ss1" # remote-dns-resolve: true # 强制 dns 远程解析,默认值为 false # dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在 remote-dns-resolve 为 true 时生效 + # refresh-server-ip-interval: 60 # 重新解析server ip的间隔,单位为秒,默认值为0即仅第一次链接时解析server域名,仅应在server域名对应的IP会发生变化时启用该选项(如家宽ddns) # 如果 peers 不为空,该段落中的 allowed-ips 不可为空;前面段落的 server,port,public-key,pre-shared-key 均会被忽略,但 private-key 会被保留且只能在顶层指定 # peers: # - server: 162.159.192.1 diff --git a/clash-meta-android/core/src/foss/golang/clash/go.mod b/clash-meta-android/core/src/foss/golang/clash/go.mod index a6664b5909..4a96d14208 100644 --- a/clash-meta-android/core/src/foss/golang/clash/go.mod +++ b/clash-meta-android/core/src/foss/golang/clash/go.mod @@ -9,50 +9,50 @@ require ( github.com/cilium/ebpf v0.12.3 github.com/coreos/go-iptables v0.7.0 github.com/dlclark/regexp2 v1.11.0 - github.com/go-chi/chi/v5 v5.0.12 + github.com/go-chi/chi/v5 v5.0.14 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.3 github.com/gobwas/ws v1.4.0 github.com/gofrs/uuid/v5 v5.2.0 - github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 - github.com/klauspost/cpuid/v2 v2.2.7 + github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 + github.com/klauspost/cpuid/v2 v2.2.8 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.45.1-0.20240607133845-b24f02b35a22 + github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e github.com/metacubex/randv2 v0.2.0 github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.2.0 - github.com/metacubex/sing-tun v0.2.7-0.20240521155100-e8316a45a414 + github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f - github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 + github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 github.com/metacubex/utls v1.6.6 - github.com/miekg/dns v1.1.59 + github.com/miekg/dns v1.1.61 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 - github.com/puzpuzpuz/xsync/v3 v3.1.0 + github.com/puzpuzpuz/xsync/v3 v3.2.0 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a - github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.3.8 + github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a + github.com/sagernet/sing v0.5.0-alpha.10 github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e github.com/samber/lo v1.39.0 - github.com/shirou/gopsutil/v3 v3.24.4 + github.com/shirou/gopsutil/v3 v3.24.5 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 github.com/wk8/go-ordered-map/v2 v2.1.8 go.uber.org/automaxprocs v1.5.3 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - golang.org/x/crypto v0.23.0 - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 - golang.org/x/net v0.25.0 + golang.org/x/crypto v0.24.0 + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 + golang.org/x/net v0.26.0 golang.org/x/sync v0.7.0 - golang.org/x/sys v0.20.0 - google.golang.org/protobuf v1.34.1 + golang.org/x/sys v0.21.0 + google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.3.0 ) @@ -92,6 +92,7 @@ require ( github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect + github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect @@ -100,14 +101,14 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect - github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect + github.com/vishvananda/netns v0.0.4 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.4.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/tools v0.22.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2 diff --git a/clash-meta-android/core/src/foss/golang/clash/go.sum b/clash-meta-android/core/src/foss/golang/clash/go.sum index c75275bce0..29a5d385de 100644 --- a/clash-meta-android/core/src/foss/golang/clash/go.sum +++ b/clash-meta-android/core/src/foss/golang/clash/go.sum @@ -44,8 +44,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= -github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= -github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.14 h1:PyEwo2Vudraa0x/Wl6eDRRW2NXBvekgfxyydcM0WGE0= +github.com/go-chi/chi/v5 v5.0.14/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= @@ -69,7 +69,6 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= @@ -78,16 +77,16 @@ github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 h1:/OuvSMGT9+xnyZ+7MZQ1zdngaCCAdPoSw8B/uurZ7pg= -github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= +github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 h1:dh8D8FksyMhD64mRMbUhZHWYJfNoNMCxfVq6eexleMw= +github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -104,30 +103,30 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec/go.mod h1:8BVmQ+3cxjqzWElafm24rb2Ae4jRI6vAXNXWqWjfrXw= -github.com/metacubex/quic-go v0.45.1-0.20240607133845-b24f02b35a22 h1:dKYoWnrB5bbCMoMQit4INUDKiDcjc0Azsm3GltYf9Pw= -github.com/metacubex/quic-go v0.45.1-0.20240607133845-b24f02b35a22/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU= +github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e h1:bLYn3GuRvWDcBDAkIv5kUYIhzHwafDVq635BuybnKqI= +github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= -github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1 h1:7hDHLTmjgtRoAp59STwPQpe5Pinwi4cWex+FB3Ohvco= -github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= +github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2 h1:N5tidgg/FRmkgPw/AjRwhLUinKDx/ODCSbvv9xqRoLM= +github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 h1:Wr4g1HCb5Z/QIFwFiVNjO2qL+dRu25+Mdn9xtAZZ+ew= github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= github.com/metacubex/sing-shadowsocks2 v0.2.0/go.mod h1:LCKF6j1P94zN8ZS+LXRK1gmYTVGB3squivBSXAFnOg8= -github.com/metacubex/sing-tun v0.2.7-0.20240521155100-e8316a45a414 h1:IPxTZgQV6fVUBS8tozLMSFPHV3imYc/NbuGfp0bLQq0= -github.com/metacubex/sing-tun v0.2.7-0.20240521155100-e8316a45a414/go.mod h1:4VsMwZH1IlgPGFK1ZbBomZ/B2MYkTgs2+gnBAr5GOIo= +github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e h1:o+zohxPRo45P35fS9u1zfdBgr+L/7S0ObGU6YjbVBIc= +github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e/go.mod h1:WwJGbCx7bQcBzuQXiDOJvZH27R0kIjKNNlISIWsL6kM= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= -github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 h1:AGyIB55UfQm/0ZH0HtQO9u3l//yjtHUpjeRjjPGfGRI= -github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo= +github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a h1:NpSGclHJUYndUwBmyIpFBSoBVg8PoVX7QQKhYg0DjM0= +github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo= github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 h1:as/aO/fM8nv4W4pOr9EETP6kV/Oaujk3fUNyQSJK61c= github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts= github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8= github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo= -github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= -github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= @@ -150,8 +149,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/puzpuzpuz/xsync/v3 v3.1.0 h1:EewKT7/LNac5SLiEblJeUu8z5eERHrmRLnMQL2d7qX4= -github.com/puzpuzpuz/xsync/v3 v3.1.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/puzpuzpuz/xsync/v3 v3.2.0 h1:9AzuUeF88YC5bK8u2vEG1Fpvu4wgpM1wfPIExfaaDxQ= +github.com/puzpuzpuz/xsync/v3 v3.2.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= @@ -159,8 +158,10 @@ github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= -github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= -github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= +github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= +github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 h1:5bCAkvDDzSMITiHFjolBwpdqYsvycdTu71FsMEFXQ14= github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= @@ -171,12 +172,11 @@ github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e h1:iGH0RMv2F github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e/go.mod h1:YbL4TKHRR6APYQv3U2RGfwLDpPYSyWz6oUlpISBEzBE= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU= -github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= -github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b/go.mod h1:X7qrxNQViEaAN9LNZOPl9PfvQtp3V3c7LTo0dvGi0fM= github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6yjG3IxDaeAj3PCoRr+IsO+bzyT+Se2m2Hk= @@ -206,8 +206,8 @@ github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -222,18 +222,18 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -252,23 +252,21 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/executor/executor.go b/clash-meta-android/core/src/foss/golang/clash/hub/executor/executor.go index 56e716326b..55c40b6d90 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/executor/executor.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/executor/executor.go @@ -97,7 +97,7 @@ func ApplyConfig(cfg *config.Config, force bool) { updateHosts(cfg.Hosts) updateGeneral(cfg.General) updateNTP(cfg.NTP) - updateDNS(cfg.DNS, cfg.RuleProviders, cfg.General.IPv6) + updateDNS(cfg.DNS, cfg.General.IPv6) updateListeners(cfg.General, cfg.Listeners, force) updateIPTables(cfg) updateTun(cfg.General) @@ -211,7 +211,7 @@ func updateNTP(c *config.NTP) { } } -func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, generalIPv6 bool) { +func updateDNS(c *config.DNS, generalIPv6 bool) { if !c.Enable { resolver.DefaultResolver = nil resolver.DefaultHostMapper = nil @@ -237,7 +237,7 @@ func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, gen Default: c.DefaultNameserver, Policy: c.NameServerPolicy, ProxyServer: c.ProxyServerNameserver, - RuleProviders: ruleProvider, + Tunnel: tunnel.Tunnel, CacheAlgorithm: c.CacheAlgorithm, } @@ -355,7 +355,7 @@ func updateTun(general *config.General) { return } listener.ReCreateTun(general.Tun, tunnel.Tunnel) - listener.ReCreateRedirToTun(general.Tun.RedirectToTun) + listener.ReCreateRedirToTun(general.EBpf.RedirectToTun) } func updateSniffer(sniffer *config.Sniffer) { @@ -507,9 +507,7 @@ func updateIPTables(cfg *config.Config) { inboundInterface = iptables.InboundInterface } - if dialer.DefaultRoutingMark.Load() == 0 { - dialer.DefaultRoutingMark.Store(2158) - } + dialer.DefaultRoutingMark.CompareAndSwap(0, 2158) err = tproxy.SetTProxyIPTables(inboundInterface, bypass, uint16(tProxyPort), DnsRedirect, dnsPort.Port()) if err != nil { diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/configs.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/configs.go index f2cf298ad3..17d858d47f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/configs.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/configs.go @@ -68,25 +68,34 @@ type tunSchema struct { GSO *bool `yaml:"gso" json:"gso,omitempty"` GSOMaxSize *uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` //Inet4Address *[]netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` + Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + IPRoute2TableIndex *int `yaml:"iproute2-table-index" json:"iproute2_table_index,omitempty"` + IPRoute2RuleIndex *int `yaml:"iproute2-rule-index" json:"iproute2_rule_index,omitempty"` + AutoRedirect *bool `yaml:"auto-redirect" json:"auto_redirect,omitempty"` + AutoRedirectInputMark *uint32 `yaml:"auto-redirect-input-mark" json:"auto_redirect_input_mark,omitempty"` + AutoRedirectOutputMark *uint32 `yaml:"auto-redirect-output-mark" json:"auto_redirect_output_mark,omitempty"` + StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` + RouteAddress *[]netip.Prefix `yaml:"route-address" json:"route_address,omitempty"` + RouteAddressSet *[]string `yaml:"route-address-set" json:"route_address_set,omitempty"` + RouteExcludeAddress *[]netip.Prefix `yaml:"route-exclude-address" json:"route_exclude_address,omitempty"` + RouteExcludeAddressSet *[]string `yaml:"route-exclude-address-set" json:"route_exclude_address_set,omitempty"` + IncludeInterface *[]string `yaml:"include-interface" json:"include-interface,omitempty"` + ExcludeInterface *[]string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` + IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` + Inet4RouteAddress *[]netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` Inet4RouteExcludeAddress *[]netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` Inet6RouteExcludeAddress *[]netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` - IncludeInterface *[]string `yaml:"include-interface" json:"include-interface,omitempty"` - ExcludeInterface *[]string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` - IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` - IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` - ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` - ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` - IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` - IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` - ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` - EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` - UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` - FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` - TableIndex *int `yaml:"table-index" json:"table-index"` } type tuicServerSchema struct { @@ -157,6 +166,36 @@ func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun { if p.Inet6Address != nil { def.Inet6Address = *p.Inet6Address } + if p.IPRoute2TableIndex != nil { + def.IPRoute2TableIndex = *p.IPRoute2TableIndex + } + if p.IPRoute2RuleIndex != nil { + def.IPRoute2RuleIndex = *p.IPRoute2RuleIndex + } + if p.AutoRedirect != nil { + def.AutoRedirect = *p.AutoRedirect + } + if p.AutoRedirectInputMark != nil { + def.AutoRedirectInputMark = *p.AutoRedirectInputMark + } + if p.AutoRedirectOutputMark != nil { + def.AutoRedirectOutputMark = *p.AutoRedirectOutputMark + } + if p.StrictRoute != nil { + def.StrictRoute = *p.StrictRoute + } + if p.RouteAddress != nil { + def.RouteAddress = *p.RouteAddress + } + if p.RouteAddressSet != nil { + def.RouteAddressSet = *p.RouteAddressSet + } + if p.RouteExcludeAddress != nil { + def.RouteExcludeAddress = *p.RouteExcludeAddress + } + if p.RouteExcludeAddressSet != nil { + def.RouteExcludeAddressSet = *p.RouteExcludeAddressSet + } if p.Inet4RouteAddress != nil { def.Inet4RouteAddress = *p.Inet4RouteAddress } @@ -205,9 +244,6 @@ func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun { if p.FileDescriptor != nil { def.FileDescriptor = *p.FileDescriptor } - if p.TableIndex != nil { - def.TableIndex = *p.TableIndex - } } return def } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/config/tun.go b/clash-meta-android/core/src/foss/golang/clash/listener/config/tun.go index 7467e4a6a7..cea22bfdc8 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/config/tun.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/config/tun.go @@ -27,27 +27,36 @@ type Tun struct { AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"` RedirectToTun []string `yaml:"-" json:"-"` - MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` - GSO bool `yaml:"gso" json:"gso,omitempty"` - GSOMaxSize uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` - Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` + MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` + GSO bool `yaml:"gso" json:"gso,omitempty"` + GSOMaxSize uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` + Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2_table_index,omitempty"` + IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2_rule_index,omitempty"` + AutoRedirect bool `yaml:"auto-redirect" json:"auto_redirect,omitempty"` + AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto_redirect_input_mark,omitempty"` + AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto_redirect_output_mark,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` + RouteAddress []netip.Prefix `yaml:"route-address" json:"route_address,omitempty"` + RouteAddressSet []string `yaml:"route-address-set" json:"route_address_set,omitempty"` + RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route_exclude_address,omitempty"` + RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route_exclude_address_set,omitempty"` + IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` + ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` - IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` - ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include-android-user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include-package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` - FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` - TableIndex int `yaml:"table-index" json:"table-index"` } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tun.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tun.go index 51747c4629..a950f80db2 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tun.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tun.go @@ -18,29 +18,38 @@ type TunOption struct { AutoRoute bool `inbound:"auto-route,omitempty"` AutoDetectInterface bool `inbound:"auto-detect-interface,omitempty"` - MTU uint32 `inbound:"mtu,omitempty"` - GSO bool `inbound:"gso,omitempty"` - GSOMaxSize uint32 `inbound:"gso-max-size,omitempty"` - Inet4Address []string `inbound:"inet4_address,omitempty"` - Inet6Address []string `inbound:"inet6_address,omitempty"` - StrictRoute bool `inbound:"strict_route,omitempty"` + MTU uint32 `inbound:"mtu,omitempty"` + GSO bool `inbound:"gso,omitempty"` + GSOMaxSize uint32 `inbound:"gso-max-size,omitempty"` + Inet4Address []string `inbound:"inet4_address,omitempty"` + Inet6Address []string `inbound:"inet6_address,omitempty"` + IPRoute2TableIndex int `inbound:"iproute2-table-index"` + IPRoute2RuleIndex int `inbound:"iproute2-rule-index"` + AutoRedirect bool `inbound:"auto-redirect"` + AutoRedirectInputMark uint32 `inbound:"auto-redirect-input-mark"` + AutoRedirectOutputMark uint32 `inbound:"auto-redirect-output-mark"` + StrictRoute bool `inbound:"strict_route,omitempty"` + RouteAddress []string `inbound:"route-address"` + RouteAddressSet []string `inbound:"route-address-set"` + RouteExcludeAddress []string `inbound:"route-exclude-address"` + RouteExcludeAddressSet []string `inbound:"route-exclude-address-set"` + IncludeInterface []string `inbound:"include-interface,omitempty"` + ExcludeInterface []string `inbound:"exclude-interface"` + IncludeUID []uint32 `inbound:"include_uid,omitempty"` + IncludeUIDRange []string `inbound:"include_uid_range,omitempty"` + ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"` + ExcludeUIDRange []string `inbound:"exclude_uid_range,omitempty"` + IncludeAndroidUser []int `inbound:"include_android_user,omitempty"` + IncludePackage []string `inbound:"include_package,omitempty"` + ExcludePackage []string `inbound:"exclude_package,omitempty"` + EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"` + UDPTimeout int64 `inbound:"udp_timeout,omitempty"` + FileDescriptor int `inbound:"file-descriptor,omitempty"` + Inet4RouteAddress []string `inbound:"inet4_route_address,omitempty"` Inet6RouteAddress []string `inbound:"inet6_route_address,omitempty"` Inet4RouteExcludeAddress []string `inbound:"inet4_route_exclude_address,omitempty"` Inet6RouteExcludeAddress []string `inbound:"inet6_route_exclude_address,omitempty"` - IncludeInterface []string `inbound:"include-interface,omitempty"` - ExcludeInterface []string `inbound:"exclude-interface" json:"exclude-interface,omitempty"` - IncludeUID []uint32 `inbound:"include_uid,omitempty"` - IncludeUIDRange []string `inbound:"include_uid_range,omitempty"` - ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"` - ExcludeUIDRange []string `inbound:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `inbound:"include_android_user,omitempty"` - IncludePackage []string `inbound:"include_package,omitempty"` - ExcludePackage []string `inbound:"exclude_package,omitempty"` - EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `inbound:"udp_timeout,omitempty"` - FileDescriptor int `inbound:"file-descriptor,omitempty"` - TableIndex int `inbound:"table-index,omitempty"` } func (o TunOption) Equal(config C.InboundConfig) bool { @@ -63,6 +72,16 @@ func NewTun(options *TunOption) (*Tun, error) { if !exist { return nil, errors.New("invalid tun stack") } + + routeAddress, err := LC.StringSliceToNetipPrefixSlice(options.RouteAddress) + if err != nil { + return nil, err + } + routeExcludeAddress, err := LC.StringSliceToNetipPrefixSlice(options.RouteExcludeAddress) + if err != nil { + return nil, err + } + inet4Address, err := LC.StringSliceToNetipPrefixSlice(options.Inet4Address) if err != nil { return nil, err @@ -91,35 +110,44 @@ func NewTun(options *TunOption) (*Tun, error) { Base: base, config: options, tun: LC.Tun{ - Enable: true, - Device: options.Device, - Stack: stack, - DNSHijack: options.DNSHijack, - AutoRoute: options.AutoRoute, - AutoDetectInterface: options.AutoDetectInterface, - MTU: options.MTU, - GSO: options.GSO, - GSOMaxSize: options.GSOMaxSize, - Inet4Address: inet4Address, - Inet6Address: inet6Address, - StrictRoute: options.StrictRoute, + Enable: true, + Device: options.Device, + Stack: stack, + DNSHijack: options.DNSHijack, + AutoRoute: options.AutoRoute, + AutoDetectInterface: options.AutoDetectInterface, + MTU: options.MTU, + GSO: options.GSO, + GSOMaxSize: options.GSOMaxSize, + Inet4Address: inet4Address, + Inet6Address: inet6Address, + IPRoute2TableIndex: options.IPRoute2TableIndex, + IPRoute2RuleIndex: options.IPRoute2RuleIndex, + AutoRedirect: options.AutoRedirect, + AutoRedirectInputMark: options.AutoRedirectInputMark, + AutoRedirectOutputMark: options.AutoRedirectOutputMark, + StrictRoute: options.StrictRoute, + RouteAddress: routeAddress, + RouteAddressSet: options.RouteAddressSet, + RouteExcludeAddress: routeExcludeAddress, + RouteExcludeAddressSet: options.RouteExcludeAddressSet, + IncludeInterface: options.IncludeInterface, + ExcludeInterface: options.ExcludeInterface, + IncludeUID: options.IncludeUID, + IncludeUIDRange: options.IncludeUIDRange, + ExcludeUID: options.ExcludeUID, + ExcludeUIDRange: options.ExcludeUIDRange, + IncludeAndroidUser: options.IncludeAndroidUser, + IncludePackage: options.IncludePackage, + ExcludePackage: options.ExcludePackage, + EndpointIndependentNat: options.EndpointIndependentNat, + UDPTimeout: options.UDPTimeout, + FileDescriptor: options.FileDescriptor, + Inet4RouteAddress: inet4RouteAddress, Inet6RouteAddress: inet6RouteAddress, Inet4RouteExcludeAddress: inet4RouteExcludeAddress, Inet6RouteExcludeAddress: inet6RouteExcludeAddress, - IncludeInterface: options.IncludeInterface, - ExcludeInterface: options.ExcludeInterface, - IncludeUID: options.IncludeUID, - IncludeUIDRange: options.IncludeUIDRange, - ExcludeUID: options.ExcludeUID, - ExcludeUIDRange: options.ExcludeUIDRange, - IncludeAndroidUser: options.IncludeAndroidUser, - IncludePackage: options.IncludePackage, - ExcludePackage: options.ExcludePackage, - EndpointIndependentNat: options.EndpointIndependentNat, - UDPTimeout: options.UDPTimeout, - FileDescriptor: options.FileDescriptor, - TableIndex: options.TableIndex, }, }, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/listener.go b/clash-meta-android/core/src/foss/golang/clash/listener/listener.go index e35061882d..76860e0d43 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/listener.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/listener.go @@ -820,11 +820,15 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { LastTunConf.MTU != tunConf.MTU || LastTunConf.GSO != tunConf.GSO || LastTunConf.GSOMaxSize != tunConf.GSOMaxSize || + LastTunConf.IPRoute2TableIndex != tunConf.IPRoute2TableIndex || + LastTunConf.IPRoute2RuleIndex != tunConf.IPRoute2RuleIndex || + LastTunConf.AutoRedirect != tunConf.AutoRedirect || + LastTunConf.AutoRedirectInputMark != tunConf.AutoRedirectInputMark || + LastTunConf.AutoRedirectOutputMark != tunConf.AutoRedirectOutputMark || LastTunConf.StrictRoute != tunConf.StrictRoute || LastTunConf.EndpointIndependentNat != tunConf.EndpointIndependentNat || LastTunConf.UDPTimeout != tunConf.UDPTimeout || - LastTunConf.FileDescriptor != tunConf.FileDescriptor || - LastTunConf.TableIndex != tunConf.TableIndex { + LastTunConf.FileDescriptor != tunConf.FileDescriptor { return true } @@ -836,6 +840,22 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { return tunConf.DNSHijack[i] < tunConf.DNSHijack[j] }) + sort.Slice(tunConf.RouteAddress, func(i, j int) bool { + return tunConf.RouteAddress[i].String() < tunConf.RouteAddress[j].String() + }) + + sort.Slice(tunConf.RouteAddressSet, func(i, j int) bool { + return tunConf.RouteAddressSet[i] < tunConf.RouteAddressSet[j] + }) + + sort.Slice(tunConf.RouteExcludeAddress, func(i, j int) bool { + return tunConf.RouteExcludeAddress[i].String() < tunConf.RouteExcludeAddress[j].String() + }) + + sort.Slice(tunConf.RouteExcludeAddressSet, func(i, j int) bool { + return tunConf.RouteExcludeAddressSet[i] < tunConf.RouteExcludeAddressSet[j] + }) + sort.Slice(tunConf.Inet4Address, func(i, j int) bool { return tunConf.Inet4Address[i].String() < tunConf.Inet4Address[j].String() }) @@ -897,6 +917,10 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { }) if !slices.Equal(tunConf.DNSHijack, LastTunConf.DNSHijack) || + !slices.Equal(tunConf.RouteAddress, LastTunConf.RouteAddress) || + !slices.Equal(tunConf.RouteAddressSet, LastTunConf.RouteAddressSet) || + !slices.Equal(tunConf.RouteExcludeAddress, LastTunConf.RouteExcludeAddress) || + !slices.Equal(tunConf.RouteExcludeAddressSet, LastTunConf.RouteExcludeAddressSet) || !slices.Equal(tunConf.Inet4Address, LastTunConf.Inet4Address) || !slices.Equal(tunConf.Inet6Address, LastTunConf.Inet6Address) || !slices.Equal(tunConf.Inet4RouteAddress, LastTunConf.Inet4RouteAddress) || diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing/sing.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing/sing.go index 4e31faeb78..10390e7326 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing/sing.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing/sing.go @@ -198,6 +198,12 @@ func (h *ListenerHandler) NewError(ctx context.Context, err error) { log.Warnln("%s listener get error: %+v", h.Type.String(), err) } +func (h *ListenerHandler) TypeMutation(typ C.Type) *ListenerHandler { + handler := *h + handler.Type = typ + return &handler +} + func ShouldIgnorePacketError(err error) bool { // ignore simple error if E.IsTimeout(err) || E.IsClosed(err) || E.IsCanceled(err) { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/dns.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/dns.go index 42926732f4..505f16acc9 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/dns.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/dns.go @@ -8,6 +8,7 @@ import ( "time" "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/sing" "github.com/metacubex/mihomo/log" @@ -124,3 +125,9 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } return h.ListenerHandler.NewPacketConnection(ctx, conn, metadata) } + +func (h *ListenerHandler) TypeMutation(typ C.Type) *ListenerHandler { + handle := *h + handle.ListenerHandler = h.ListenerHandler.TypeMutation(typ) + return &handle +} diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/iface.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/iface.go new file mode 100644 index 0000000000..cc14207824 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/iface.go @@ -0,0 +1,70 @@ +package sing_tun + +import ( + "errors" + "net/netip" + + "github.com/metacubex/mihomo/component/iface" + + "github.com/sagernet/sing/common/control" +) + +type defaultInterfaceFinder struct{} + +var DefaultInterfaceFinder control.InterfaceFinder = (*defaultInterfaceFinder)(nil) + +func (f *defaultInterfaceFinder) Interfaces() []control.Interface { + ifaces, err := iface.Interfaces() + if err != nil { + return nil + } + interfaces := make([]control.Interface, 0, len(ifaces)) + for _, _interface := range ifaces { + interfaces = append(interfaces, control.Interface(*_interface)) + } + + return interfaces +} + +var errNoSuchInterface = errors.New("no such network interface") + +func (f *defaultInterfaceFinder) InterfaceIndexByName(name string) (int, error) { + ifaces, err := iface.Interfaces() + if err != nil { + return 0, err + } + for _, netInterface := range ifaces { + if netInterface.Name == name { + return netInterface.Index, nil + } + } + return 0, errNoSuchInterface +} + +func (f *defaultInterfaceFinder) InterfaceNameByIndex(index int) (string, error) { + ifaces, err := iface.Interfaces() + if err != nil { + return "", err + } + for _, netInterface := range ifaces { + if netInterface.Index == index { + return netInterface.Name, nil + } + } + return "", errNoSuchInterface +} + +func (f *defaultInterfaceFinder) InterfaceByAddr(addr netip.Addr) (*control.Interface, error) { + ifaces, err := iface.Interfaces() + if err != nil { + return nil, err + } + for _, netInterface := range ifaces { + for _, prefix := range netInterface.Addresses { + if prefix.Contains(addr) { + return (*control.Interface)(netInterface), nil + } + } + } + return nil, errNoSuchInterface +} diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/redirect_linux.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/redirect_linux.go new file mode 100644 index 0000000000..6ef6fc968a --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/redirect_linux.go @@ -0,0 +1,3 @@ +package sing_tun + +const supportRedirect = true diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/redirect_stub.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/redirect_stub.go new file mode 100644 index 0000000000..d711af3c70 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/redirect_stub.go @@ -0,0 +1,5 @@ +//go:build !linux + +package sing_tun + +const supportRedirect = false diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go index a5edb77f63..e8c2ad286b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go @@ -3,27 +3,33 @@ package sing_tun import ( "context" "fmt" + "io" "net" "net/netip" + "os" "runtime" "strconv" "strings" + "sync" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/iface" "github.com/metacubex/mihomo/component/resolver" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing" "github.com/metacubex/mihomo/log" tun "github.com/metacubex/sing-tun" "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/control" E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" "github.com/sagernet/sing/common/ranges" + + "go4.org/netipx" + "golang.org/x/exp/maps" "golang.org/x/exp/slices" ) @@ -43,10 +49,21 @@ type Listener struct { networkUpdateMonitor tun.NetworkUpdateMonitor defaultInterfaceMonitor tun.DefaultInterfaceMonitor packageManager tun.PackageManager + autoRedirect tun.AutoRedirect + autoRedirectOutputMark int32 + + ruleUpdateCallbackCloser io.Closer + ruleUpdateMutex sync.Mutex + routeAddressMap map[string]*netipx.IPSet + routeExcludeAddressMap map[string]*netipx.IPSet + routeAddressSet []*netipx.IPSet + routeExcludeAddressSet []*netipx.IPSet dnsServerIp []string } +var emptyAddressSet = []*netipx.IPSet{{}} + func CalculateInterfaceName(name string) (tunName string) { if runtime.GOOS == "darwin" { tunName = "utun" @@ -110,14 +127,45 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis inbound.WithSpecialRules(""), } } + ctx := context.TODO() + rpTunnel := tunnel.(provider.Tunnel) if options.GSOMaxSize == 0 { options.GSOMaxSize = 65536 } + if !supportRedirect { + options.AutoRedirect = false + } tunName := options.Device if tunName == "" || !checkTunName(tunName) { tunName = CalculateInterfaceName(InterfaceName) options.Device = tunName } + routeAddress := options.RouteAddress + if len(options.Inet4RouteAddress) > 0 { + routeAddress = append(routeAddress, options.Inet4RouteAddress...) + } + if len(options.Inet6RouteAddress) > 0 { + routeAddress = append(routeAddress, options.Inet6RouteAddress...) + } + inet4RouteAddress := common.Filter(routeAddress, func(it netip.Prefix) bool { + return it.Addr().Is4() + }) + inet6RouteAddress := common.Filter(routeAddress, func(it netip.Prefix) bool { + return it.Addr().Is6() + }) + routeExcludeAddress := options.RouteExcludeAddress + if len(options.Inet4RouteExcludeAddress) > 0 { + routeExcludeAddress = append(routeExcludeAddress, options.Inet4RouteExcludeAddress...) + } + if len(options.Inet6RouteExcludeAddress) > 0 { + routeExcludeAddress = append(routeExcludeAddress, options.Inet6RouteExcludeAddress...) + } + inet4RouteExcludeAddress := common.Filter(routeExcludeAddress, func(it netip.Prefix) bool { + return it.Addr().Is4() + }) + inet6RouteExcludeAddress := common.Filter(routeExcludeAddress, func(it netip.Prefix) bool { + return it.Addr().Is6() + }) tunMTU := options.MTU if tunMTU == 0 { tunMTU = 9000 @@ -128,9 +176,21 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis } else { udpTimeout = int64(sing.UDPTimeout.Seconds()) } - tableIndex := options.TableIndex + tableIndex := options.IPRoute2TableIndex if tableIndex == 0 { - tableIndex = 2022 + tableIndex = tun.DefaultIPRoute2TableIndex + } + ruleIndex := options.IPRoute2RuleIndex + if ruleIndex == 0 { + ruleIndex = tun.DefaultIPRoute2RuleIndex + } + inputMark := options.AutoRedirectInputMark + if inputMark == 0 { + inputMark = tun.DefaultAutoRedirectInputMark + } + outputMark := options.AutoRedirectOutputMark + if outputMark == 0 { + outputMark = tun.DefaultAutoRedirectOutputMark } includeUID := uidToRange(options.IncludeUID) if len(options.IncludeUIDRange) > 0 { @@ -202,6 +262,8 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis } }() + interfaceFinder := DefaultInterfaceFinder + networkUpdateMonitor, err := tun.NewNetworkUpdateMonitor(log.SingLogger) if err != nil { err = E.Cause(err, "create NetworkUpdateMonitor") @@ -236,11 +298,15 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis Inet4Address: options.Inet4Address, Inet6Address: options.Inet6Address, AutoRoute: options.AutoRoute, + IPRoute2TableIndex: tableIndex, + IPRoute2RuleIndex: ruleIndex, + AutoRedirectInputMark: inputMark, + AutoRedirectOutputMark: outputMark, StrictRoute: options.StrictRoute, - Inet4RouteAddress: options.Inet4RouteAddress, - Inet6RouteAddress: options.Inet6RouteAddress, - Inet4RouteExcludeAddress: options.Inet4RouteExcludeAddress, - Inet6RouteExcludeAddress: options.Inet6RouteExcludeAddress, + Inet4RouteAddress: inet4RouteAddress, + Inet6RouteAddress: inet6RouteAddress, + Inet4RouteExcludeAddress: inet4RouteExcludeAddress, + Inet6RouteExcludeAddress: inet6RouteExcludeAddress, IncludeInterface: options.IncludeInterface, ExcludeInterface: options.ExcludeInterface, IncludeUID: includeUID, @@ -250,7 +316,56 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis ExcludePackage: options.ExcludePackage, FileDescriptor: options.FileDescriptor, InterfaceMonitor: defaultInterfaceMonitor, - TableIndex: tableIndex, + } + + if options.AutoRedirect { + l.routeAddressMap = make(map[string]*netipx.IPSet) + l.routeExcludeAddressMap = make(map[string]*netipx.IPSet) + + if !options.AutoRoute { + return nil, E.New("`auto-route` is required by `auto-redirect`") + } + disableNFTables, dErr := strconv.ParseBool(os.Getenv("DISABLE_NFTABLES")) + l.autoRedirect, err = tun.NewAutoRedirect(tun.AutoRedirectOptions{ + TunOptions: &tunOptions, + Context: ctx, + Handler: handler.TypeMutation(C.REDIR), + Logger: log.SingLogger, + NetworkMonitor: networkUpdateMonitor, + InterfaceFinder: interfaceFinder, + TableName: "mihomo", + DisableNFTables: dErr == nil && disableNFTables, + RouteAddressSet: &l.routeAddressSet, + RouteExcludeAddressSet: &l.routeExcludeAddressSet, + }) + if err != nil { + err = E.Cause(err, "initialize auto redirect") + return + } + + var markMode bool + for _, routeAddressSet := range options.RouteAddressSet { + rp, loaded := rpTunnel.RuleProviders()[routeAddressSet] + if !loaded { + err = E.New("parse route-address-set: rule-set not found: ", routeAddressSet) + return + } + l.updateRule(rp, false, false) + markMode = true + } + for _, routeExcludeAddressSet := range options.RouteExcludeAddressSet { + rp, loaded := rpTunnel.RuleProviders()[routeExcludeAddressSet] + if !loaded { + err = E.New("parse route-exclude_address-set: rule-set not found: ", routeExcludeAddressSet) + return + } + l.updateRule(rp, true, false) + markMode = true + } + if markMode { + tunOptions.AutoRedirectMarkMode = true + } + } err = l.buildAndroidRules(&tunOptions) @@ -269,14 +384,14 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis resolver.AddSystemDnsBlacklist(dnsServerIp...) stackOptions := tun.StackOptions{ - Context: context.TODO(), + Context: ctx, Tun: tunIf, TunOptions: tunOptions, EndpointIndependentNat: options.EndpointIndependentNat, UDPTimeout: udpTimeout, Handler: handler, Logger: log.SingLogger, - InterfaceFinder: control.DefaultInterfaceFinder(), + InterfaceFinder: interfaceFinder, EnforceBindInterface: EnforceBindInterface, } @@ -299,13 +414,80 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis } l.tunStack = tunStack + if l.autoRedirect != nil { + if len(l.options.RouteAddressSet) > 0 && len(l.routeAddressSet) == 0 { + l.routeAddressSet = emptyAddressSet // without this we can't call UpdateRouteAddressSet after Start + } + if len(l.options.RouteExcludeAddressSet) > 0 && len(l.routeExcludeAddressSet) == 0 { + l.routeExcludeAddressSet = emptyAddressSet // without this we can't call UpdateRouteAddressSet after Start + } + err = l.autoRedirect.Start() + if err != nil { + err = E.Cause(err, "auto redirect") + return + } + if tunOptions.AutoRedirectMarkMode { + l.autoRedirectOutputMark = int32(outputMark) + dialer.DefaultRoutingMark.Store(l.autoRedirectOutputMark) + l.autoRedirect.UpdateRouteAddressSet() + l.ruleUpdateCallbackCloser = rpTunnel.RuleUpdateCallback().Register(l.ruleUpdateCallback) + } + } + //l.openAndroidHotspot(tunOptions) - l.addrStr = fmt.Sprintf("%s(%s,%s), mtu: %d, auto route: %v, ip stack: %s", - tunName, tunOptions.Inet4Address, tunOptions.Inet6Address, tunMTU, options.AutoRoute, options.Stack) + l.addrStr = fmt.Sprintf("%s(%s,%s), mtu: %d, auto route: %v, auto redir: %v, ip stack: %s", + tunName, tunOptions.Inet4Address, tunOptions.Inet6Address, tunMTU, options.AutoRoute, options.AutoRedirect, options.Stack) return } +func (l *Listener) ruleUpdateCallback(ruleProvider provider.RuleProvider) { + name := ruleProvider.Name() + if slices.Contains(l.options.RouteAddressSet, name) { + l.updateRule(ruleProvider, false, true) + return + } + if slices.Contains(l.options.RouteExcludeAddressSet, name) { + l.updateRule(ruleProvider, true, true) + return + } +} + +type toIpCidr interface { + ToIpCidr() *netipx.IPSet +} + +func (l *Listener) updateRule(ruleProvider provider.RuleProvider, exclude bool, update bool) { + l.ruleUpdateMutex.Lock() + defer l.ruleUpdateMutex.Unlock() + name := ruleProvider.Name() + switch rp := ruleProvider.Strategy().(type) { + case toIpCidr: + if !exclude { + ipCidr := rp.ToIpCidr() + if ipCidr != nil { + l.routeAddressMap[name] = ipCidr + } else { + delete(l.routeAddressMap, name) + } + l.routeAddressSet = maps.Values(l.routeAddressMap) + } else { + ipCidr := rp.ToIpCidr() + if ipCidr != nil { + l.routeExcludeAddressMap[name] = ipCidr + } else { + delete(l.routeExcludeAddressMap, name) + } + l.routeExcludeAddressSet = maps.Values(l.routeExcludeAddressMap) + } + default: + return + } + if update && l.autoRedirect != nil { + l.autoRedirect.UpdateRouteAddressSet() + } +} + func (l *Listener) FlushDefaultInterface() { if l.options.AutoDetectInterface { for _, destination := range []netip.Addr{netip.IPv4Unspecified(), netip.IPv6Unspecified(), netip.MustParseAddr("1.1.1.1")} { @@ -347,11 +529,11 @@ func parseRange(uidRanges []ranges.Range[uint32], rangeList []string) ([]ranges. } var start, end uint64 var err error - start, err = strconv.ParseUint(uidRange[:subIndex], 10, 32) + start, err = strconv.ParseUint(uidRange[:subIndex], 0, 32) if err != nil { return nil, E.Cause(err, "parse range start") } - end, err = strconv.ParseUint(uidRange[subIndex+1:], 10, 32) + end, err = strconv.ParseUint(uidRange[subIndex+1:], 0, 32) if err != nil { return nil, E.Cause(err, "parse range end") } @@ -363,9 +545,14 @@ func parseRange(uidRanges []ranges.Range[uint32], rangeList []string) ([]ranges. func (l *Listener) Close() error { l.closed = true resolver.RemoveSystemDnsBlacklist(l.dnsServerIp...) + if l.autoRedirectOutputMark != 0 { + dialer.DefaultRoutingMark.CompareAndSwap(l.autoRedirectOutputMark, 0) + } return common.Close( + l.ruleUpdateCallbackCloser, l.tunStack, l.tunIf, + l.autoRedirect, l.defaultInterfaceMonitor, l.networkUpdateMonitor, l.packageManager, diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/tproxy/tproxy_iptables.go b/clash-meta-android/core/src/foss/golang/clash/listener/tproxy/tproxy_iptables.go index 6c6e2cc81f..bc26b125fd 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/tproxy/tproxy_iptables.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/tproxy/tproxy_iptables.go @@ -119,9 +119,7 @@ func CleanupTProxyIPTables() { log.Warnln("Cleanup tproxy linux iptables") - if int(dialer.DefaultRoutingMark.Load()) == 2158 { - dialer.DefaultRoutingMark.Store(0) - } + dialer.DefaultRoutingMark.CompareAndSwap(2158, 0) if _, err := cmd.ExecCmd("iptables -t mangle -L mihomo_divert"); err != nil { return diff --git a/clash-meta-android/core/src/foss/golang/clash/rules/common/base.go b/clash-meta-android/core/src/foss/golang/clash/rules/common/base.go index d912107c2e..670df1d969 100644 --- a/clash-meta-android/core/src/foss/golang/clash/rules/common/base.go +++ b/clash-meta-android/core/src/foss/golang/clash/rules/common/base.go @@ -20,6 +20,8 @@ func (b *Base) ShouldResolveIP() bool { return false } +func (b *Base) ProviderNames() []string { return nil } + func HasNoResolve(params []string) bool { for _, p := range params { if p == noResolve { diff --git a/clash-meta-android/core/src/foss/golang/clash/rules/logic/logic.go b/clash-meta-android/core/src/foss/golang/clash/rules/logic/logic.go index af8c31a4bf..8c79cab537 100644 --- a/clash-meta-android/core/src/foss/golang/clash/rules/logic/logic.go +++ b/clash-meta-android/core/src/foss/golang/clash/rules/logic/logic.go @@ -2,12 +2,13 @@ package logic import ( "fmt" - list "github.com/bahlo/generic-list-go" "regexp" "strings" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/rules/common" + + list "github.com/bahlo/generic-list-go" ) type Logic struct { @@ -243,7 +244,7 @@ func matchSubRules(metadata *C.Metadata, name string, subRules map[string][]C.Ru for _, rule := range subRules[name] { if m, a := rule.Match(metadata); m { if rule.RuleType() == C.SubRules { - matchSubRules(metadata, rule.Adapter(), subRules) + return matchSubRules(metadata, rule.Adapter(), subRules) } else { return m, a } @@ -298,3 +299,10 @@ func (logic *Logic) ShouldResolveIP() bool { func (logic *Logic) ShouldFindProcess() bool { return logic.needProcess } + +func (logic *Logic) ProviderNames() (names []string) { + for _, rule := range logic.rules { + names = append(names, rule.ProviderNames()...) + } + return +} diff --git a/clash-meta-android/core/src/foss/golang/clash/rules/provider/ipcidr_strategy.go b/clash-meta-android/core/src/foss/golang/clash/rules/provider/ipcidr_strategy.go index c93facd95e..d0545c7cc2 100644 --- a/clash-meta-android/core/src/foss/golang/clash/rules/provider/ipcidr_strategy.go +++ b/clash-meta-android/core/src/foss/golang/clash/rules/provider/ipcidr_strategy.go @@ -4,6 +4,8 @@ import ( "github.com/metacubex/mihomo/component/cidr" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" + + "go4.org/netipx" ) type ipcidrStrategy struct { @@ -52,6 +54,10 @@ func (i *ipcidrStrategy) FinishInsert() { i.cidrSet.Merge() } +func (i *ipcidrStrategy) ToIpCidr() *netipx.IPSet { + return i.cidrSet.ToIPSet() +} + func NewIPCidrStrategy() *ipcidrStrategy { return &ipcidrStrategy{} } diff --git a/clash-meta-android/core/src/foss/golang/clash/rules/provider/patch_android.go b/clash-meta-android/core/src/foss/golang/clash/rules/provider/patch_android.go index 2bd5ffc874..7ef1df1b59 100644 --- a/clash-meta-android/core/src/foss/golang/clash/rules/provider/patch_android.go +++ b/clash-meta-android/core/src/foss/golang/clash/rules/provider/patch_android.go @@ -12,8 +12,8 @@ type UpdatableProvider interface { UpdatedAt() time.Time } -func (f *ruleSetProvider) UpdatedAt() time.Time { - return f.Fetcher.UpdatedAt +func (rp *ruleSetProvider) UpdatedAt() time.Time { + return rp.Fetcher.UpdatedAt } func (rp *ruleSetProvider) Close() error { diff --git a/clash-meta-android/core/src/foss/golang/clash/rules/provider/provider.go b/clash-meta-android/core/src/foss/golang/clash/rules/provider/provider.go index adc2e44a29..6c03c6e5f3 100644 --- a/clash-meta-android/core/src/foss/golang/clash/rules/provider/provider.go +++ b/clash-meta-android/core/src/foss/golang/clash/rules/provider/provider.go @@ -4,23 +4,26 @@ import ( "bytes" "encoding/json" "errors" - "gopkg.in/yaml.v3" "runtime" "strings" "time" + "gopkg.in/yaml.v3" + "github.com/metacubex/mihomo/common/pool" "github.com/metacubex/mihomo/component/resource" C "github.com/metacubex/mihomo/constant" P "github.com/metacubex/mihomo/constant/provider" ) -var ( - ruleProviders = map[string]P.RuleProvider{} -) +var tunnel P.Tunnel + +func SetTunnel(t P.Tunnel) { + tunnel = t +} type ruleSetProvider struct { - *resource.Fetcher[any] + *resource.Fetcher[ruleStrategy] behavior P.RuleBehavior format P.RuleFormat strategy ruleStrategy @@ -49,16 +52,6 @@ type ruleStrategy interface { FinishInsert() } -func RuleProviders() map[string]P.RuleProvider { - return ruleProviders -} - -func SetRuleProvider(ruleProvider P.RuleProvider) { - if ruleProvider != nil { - ruleProviders[(ruleProvider).Name()] = ruleProvider - } -} - func (rp *ruleSetProvider) Type() P.ProviderType { return P.Rule } @@ -99,8 +92,8 @@ func (rp *ruleSetProvider) ShouldFindProcess() bool { return rp.strategy.ShouldFindProcess() } -func (rp *ruleSetProvider) AsRule(adaptor string) C.Rule { - panic("implement me") +func (rp *ruleSetProvider) Strategy() any { + return rp.strategy } func (rp *ruleSetProvider) MarshalJSON() ([]byte, error) { @@ -123,13 +116,15 @@ func NewRuleSetProvider(name string, behavior P.RuleBehavior, format P.RuleForma format: format, } - onUpdate := func(elm interface{}) { - strategy := elm.(ruleStrategy) + onUpdate := func(strategy ruleStrategy) { rp.strategy = strategy + tunnel.RuleUpdateCallback().Emit(rp) } rp.strategy = newStrategy(behavior, parse) - rp.Fetcher = resource.NewFetcher(name, interval, vehicle, func(bytes []byte) (any, error) { return rulesParse(bytes, newStrategy(behavior, parse), format) }, onUpdate) + rp.Fetcher = resource.NewFetcher(name, interval, vehicle, func(bytes []byte) (ruleStrategy, error) { + return rulesParse(bytes, newStrategy(behavior, parse), format) + }, onUpdate) wrapper := &RuleSetProvider{ rp, @@ -158,7 +153,7 @@ func newStrategy(behavior P.RuleBehavior, parse func(tp, payload, target string, var ErrNoPayload = errors.New("file must have a `payload` field") -func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (any, error) { +func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (ruleStrategy, error) { strategy.Reset() schema := &RulePayload{} @@ -176,15 +171,14 @@ func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (any, er line = buf[s : i+1] s = i + 1 } else { - s = len(buf) // stop loop in next step - if firstLineLength == 0 { // no head or only one line body + s = len(buf) // stop loop in next step + if firstLineLength == 0 && format == P.YamlRule { // no head or only one line body return nil, ErrNoPayload } } var str string switch format { case P.TextRule: - firstLineLength = -1 // don't return ErrNoPayload when read last line str = string(line) str = strings.TrimSpace(str) if len(str) == 0 { diff --git a/clash-meta-android/core/src/foss/golang/clash/rules/provider/rule_set.go b/clash-meta-android/core/src/foss/golang/clash/rules/provider/rule_set.go index 1d94018868..d85db80558 100644 --- a/clash-meta-android/core/src/foss/golang/clash/rules/provider/rule_set.go +++ b/clash-meta-android/core/src/foss/golang/clash/rules/provider/rule_set.go @@ -1,7 +1,6 @@ package provider import ( - "fmt" C "github.com/metacubex/mihomo/constant" P "github.com/metacubex/mihomo/constant/provider" "github.com/metacubex/mihomo/rules/common" @@ -11,13 +10,18 @@ type RuleSet struct { *common.Base ruleProviderName string adapter string - ruleProvider P.RuleProvider noResolveIP bool shouldFindProcess bool } func (rs *RuleSet) ShouldFindProcess() bool { - return rs.shouldFindProcess || rs.getProviders().ShouldFindProcess() + if rs.shouldFindProcess { + return true + } + if provider, ok := rs.getProvider(); ok { + return provider.ShouldFindProcess() + } + return false } func (rs *RuleSet) RuleType() C.RuleType { @@ -25,7 +29,10 @@ func (rs *RuleSet) RuleType() C.RuleType { } func (rs *RuleSet) Match(metadata *C.Metadata) (bool, string) { - return rs.getProviders().Match(metadata), rs.adapter + if provider, ok := rs.getProvider(); ok { + return provider.Match(metadata), rs.adapter + } + return false, "" } func (rs *RuleSet) Adapter() string { @@ -33,31 +40,37 @@ func (rs *RuleSet) Adapter() string { } func (rs *RuleSet) Payload() string { - return rs.getProviders().Name() + if provider, ok := rs.getProvider(); ok { + return provider.Name() + } + return "" } func (rs *RuleSet) ShouldResolveIP() bool { - return !rs.noResolveIP && rs.getProviders().ShouldResolveIP() -} -func (rs *RuleSet) getProviders() P.RuleProvider { - if rs.ruleProvider == nil { - rp := RuleProviders()[rs.ruleProviderName] - rs.ruleProvider = rp + if rs.noResolveIP { + return false } + if provider, ok := rs.getProvider(); ok { + return provider.ShouldResolveIP() + } + return false +} - return rs.ruleProvider +func (rs *RuleSet) ProviderNames() []string { + return []string{rs.ruleProviderName} +} + +func (rs *RuleSet) getProvider() (P.RuleProvider, bool) { + pp, ok := tunnel.RuleProviders()[rs.ruleProviderName] + return pp, ok } func NewRuleSet(ruleProviderName string, adapter string, noResolveIP bool) (*RuleSet, error) { - rp, ok := RuleProviders()[ruleProviderName] - if !ok { - return nil, fmt.Errorf("rule set %s not found", ruleProviderName) - } - return &RuleSet{ + rs := &RuleSet{ Base: &common.Base{}, ruleProviderName: ruleProviderName, adapter: adapter, - ruleProvider: rp, noResolveIP: noResolveIP, - }, nil + } + return rs, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/tunnel/dns_dialer.go b/clash-meta-android/core/src/foss/golang/clash/tunnel/dns_dialer.go new file mode 100644 index 0000000000..1839869b4a --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/tunnel/dns_dialer.go @@ -0,0 +1,186 @@ +package tunnel + +// WARNING: all function in this file should only be using in dns module + +import ( + "context" + "fmt" + "net" + "strings" + + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/tunnel/statistic" +) + +const DnsRespectRules = "RULES" + +type DNSDialer struct { + r resolver.Resolver + proxyAdapter C.ProxyAdapter + proxyName string + opts []dialer.Option +} + +func NewDNSDialer(r resolver.Resolver, proxyAdapter C.ProxyAdapter, proxyName string, opts ...dialer.Option) *DNSDialer { + return &DNSDialer{r: r, proxyAdapter: proxyAdapter, proxyName: proxyName, opts: opts} +} + +func (d *DNSDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + r := d.r + proxyName := d.proxyName + proxyAdapter := d.proxyAdapter + opts := d.opts + var rule C.Rule + metadata := &C.Metadata{ + NetWork: C.TCP, + Type: C.INNER, + } + err := metadata.SetRemoteAddress(addr) // tcp can resolve host by remote + if err != nil { + return nil, err + } + if !strings.Contains(network, "tcp") { + metadata.NetWork = C.UDP + if !metadata.Resolved() { + // udp must resolve host first + dstIP, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r) + if err != nil { + return nil, err + } + metadata.DstIP = dstIP + } + } + + if proxyAdapter == nil && len(proxyName) != 0 { + if proxyName == DnsRespectRules { + if !metadata.Resolved() { + // resolve here before resolveMetadata to avoid its inner resolver.ResolveIP + dstIP, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r) + if err != nil { + return nil, err + } + metadata.DstIP = dstIP + } + proxyAdapter, rule, err = resolveMetadata(metadata) + if err != nil { + return nil, err + } + } else { + var ok bool + proxyAdapter, ok = Proxies()[proxyName] + if !ok { + opts = append(opts, dialer.WithInterface(proxyName)) + } + } + } + + if metadata.NetWork == C.TCP { + if proxyAdapter == nil { + opts = append(opts, dialer.WithResolver(r)) + return dialer.DialContext(ctx, network, addr, opts...) + } + + if proxyAdapter.IsL3Protocol(metadata) { // L3 proxy should resolve domain before to avoid loopback + if !metadata.Resolved() { + dstIP, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r) + if err != nil { + return nil, err + } + metadata.DstIP = dstIP + } + metadata.Host = "" // clear host to avoid double resolve in proxy + } + + conn, err := proxyAdapter.DialContext(ctx, metadata, opts...) + if err != nil { + logMetadataErr(metadata, rule, proxyAdapter, err) + return nil, err + } + logMetadata(metadata, rule, conn) + + conn = statistic.NewTCPTracker(conn, statistic.DefaultManager, metadata, rule, 0, 0, false) + + return conn, nil + } else { + if proxyAdapter == nil { + return dialer.DialContext(ctx, network, metadata.AddrPort().String(), opts...) + } + + if !proxyAdapter.SupportUDP() { + return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter) + } + + packetConn, err := proxyAdapter.ListenPacketContext(ctx, metadata, opts...) + if err != nil { + logMetadataErr(metadata, rule, proxyAdapter, err) + return nil, err + } + logMetadata(metadata, rule, packetConn) + + packetConn = statistic.NewUDPTracker(packetConn, statistic.DefaultManager, metadata, rule, 0, 0, false) + + return N.NewBindPacketConn(packetConn, metadata.UDPAddr()), nil + } + +} + +func (d *DNSDialer) ListenPacket(ctx context.Context, network, addr string) (net.PacketConn, error) { + r := d.r + proxyAdapter := d.proxyAdapter + proxyName := d.proxyName + opts := d.opts + metadata := &C.Metadata{ + NetWork: C.UDP, + Type: C.INNER, + } + err := metadata.SetRemoteAddress(addr) + if err != nil { + return nil, err + } + if !metadata.Resolved() { + // udp must resolve host first + dstIP, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r) + if err != nil { + return nil, err + } + metadata.DstIP = dstIP + } + + var rule C.Rule + if proxyAdapter == nil { + if proxyName == DnsRespectRules { + proxyAdapter, rule, err = resolveMetadata(metadata) + if err != nil { + return nil, err + } + } else { + var ok bool + proxyAdapter, ok = Proxies()[proxyName] + if !ok { + opts = append(opts, dialer.WithInterface(proxyName)) + } + } + } + + if proxyAdapter == nil { + return dialer.NewDialer(opts...).ListenPacket(ctx, network, "", metadata.AddrPort()) + } + + if !proxyAdapter.SupportUDP() { + return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter) + } + + packetConn, err := proxyAdapter.ListenPacketContext(ctx, metadata, opts...) + if err != nil { + logMetadataErr(metadata, rule, proxyAdapter, err) + return nil, err + } + logMetadata(metadata, rule, packetConn) + + packetConn = statistic.NewUDPTracker(packetConn, statistic.DefaultManager, metadata, rule, 0, 0, false) + + return packetConn, nil +} diff --git a/clash-meta-android/core/src/foss/golang/clash/tunnel/tunnel.go b/clash-meta-android/core/src/foss/golang/clash/tunnel/tunnel.go index 608ab2c5bd..1a6f104dc9 100644 --- a/clash-meta-android/core/src/foss/golang/clash/tunnel/tunnel.go +++ b/clash-meta-android/core/src/foss/golang/clash/tunnel/tunnel.go @@ -8,10 +8,12 @@ import ( "net/netip" "path/filepath" "runtime" + "strings" "sync" "time" N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/loopback" "github.com/metacubex/mihomo/component/nat" P "github.com/metacubex/mihomo/component/process" @@ -49,11 +51,15 @@ var ( findProcessMode P.FindProcessMode fakeIPRange netip.Prefix + + ruleUpdateCallback = utils.NewCallback[provider.RuleProvider]() ) type tunnel struct{} -var Tunnel C.Tunnel = tunnel{} +var Tunnel = tunnel{} +var _ C.Tunnel = Tunnel +var _ provider.Tunnel = Tunnel func (t tunnel) HandleTCPConn(conn net.Conn, metadata *C.Metadata) { connCtx := icontext.NewConnContext(conn, metadata) @@ -72,6 +78,18 @@ func (t tunnel) NatTable() C.NatTable { return natTable } +func (t tunnel) Providers() map[string]provider.ProxyProvider { + return providers +} + +func (t tunnel) RuleProviders() map[string]provider.RuleProvider { + return ruleProviders +} + +func (t tunnel) RuleUpdateCallback() *utils.Callback[provider.RuleProvider] { + return ruleUpdateCallback +} + func OnSuspend() { status.Store(Suspend) } @@ -386,43 +404,18 @@ func handleUDPConn(packet C.PacketAdapter) { rawPc, err := retry(ctx, func(ctx context.Context) (C.PacketConn, error) { return proxy.ListenPacketContext(ctx, metadata.Pure()) }, func(err error) { - if rule == nil { - log.Warnln( - "[UDP] dial %s %s --> %s error: %s", - proxy.Name(), - metadata.SourceDetail(), - metadata.RemoteAddress(), - err.Error(), - ) - } else { - log.Warnln("[UDP] dial %s (match %s/%s) %s --> %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.SourceDetail(), metadata.RemoteAddress(), err.Error()) - } + logMetadataErr(metadata, rule, proxy, err) }) if err != nil { return } + logMetadata(metadata, rule, rawPc) pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true) - switch true { - case metadata.SpecialProxy != "": - log.Infoln("[UDP] %s --> %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), metadata.SpecialProxy) - case rule != nil: - if rule.Payload() != "" { - log.Infoln("[UDP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload()), rawPc.Chains().String()) - if rawPc.Chains().Last() == "REJECT-DROP" { - pc.Close() - return - } - } else { - log.Infoln("[UDP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), rule.Payload(), rawPc.Chains().String()) - } - case mode == Global: - log.Infoln("[UDP] %s --> %s using GLOBAL", metadata.SourceDetail(), metadata.RemoteAddress()) - case mode == Direct: - log.Infoln("[UDP] %s --> %s using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress()) - default: - log.Infoln("[UDP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress()) + if rawPc.Chains().Last() == "REJECT-DROP" { + pc.Close() + return } oAddrPort := metadata.AddrPort() @@ -539,48 +532,18 @@ func handleTCPConn(connCtx C.ConnContext) { } return }, func(err error) { - if rule == nil { - log.Warnln( - "[TCP] dial %s %s --> %s error: %s", - proxy.Name(), - metadata.SourceDetail(), - metadata.RemoteAddress(), - err.Error(), - ) - } else { - log.Warnln("[TCP] dial %s (match %s/%s) %s --> %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.SourceDetail(), metadata.RemoteAddress(), err.Error()) - } + logMetadataErr(metadata, rule, proxy, err) }) if err != nil { return } + logMetadata(metadata, rule, remoteConn) remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule, 0, int64(peekLen), true) defer func(remoteConn C.Conn) { _ = remoteConn.Close() }(remoteConn) - switch true { - case metadata.SpecialProxy != "": - log.Infoln("[TCP] %s --> %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), metadata.SpecialProxy) - case rule != nil: - if rule.Payload() != "" { - log.Infoln("[TCP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload()), remoteConn.Chains().String()) - } else { - log.Infoln("[TCP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), rule.RuleType().String(), remoteConn.Chains().String()) - } - case mode == Global: - log.Infoln("[TCP] %s --> %s using GLOBAL", metadata.SourceDetail(), metadata.RemoteAddress()) - case mode == Direct: - log.Infoln("[TCP] %s --> %s using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress()) - default: - log.Infoln( - "[TCP] %s --> %s doesn't match any rule using DIRECT", - metadata.SourceDetail(), - metadata.RemoteAddress(), - ) - } - _ = conn.SetReadDeadline(time.Now()) // stop unfinished peek peekMutex.Lock() defer peekMutex.Unlock() @@ -588,6 +551,33 @@ func handleTCPConn(connCtx C.ConnContext) { handleSocket(conn, remoteConn) } +func logMetadataErr(metadata *C.Metadata, rule C.Rule, proxy C.ProxyAdapter, err error) { + if rule == nil { + log.Warnln("[%s] dial %s %s --> %s error: %s", strings.ToUpper(metadata.NetWork.String()), proxy.Name(), metadata.SourceDetail(), metadata.RemoteAddress(), err.Error()) + } else { + log.Warnln("[%s] dial %s (match %s/%s) %s --> %s error: %s", strings.ToUpper(metadata.NetWork.String()), proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.SourceDetail(), metadata.RemoteAddress(), err.Error()) + } +} + +func logMetadata(metadata *C.Metadata, rule C.Rule, remoteConn C.Connection) { + switch { + case metadata.SpecialProxy != "": + log.Infoln("[%s] %s --> %s using %s", strings.ToUpper(metadata.NetWork.String()), metadata.SourceDetail(), metadata.RemoteAddress(), metadata.SpecialProxy) + case rule != nil: + if rule.Payload() != "" { + log.Infoln("[%s] %s --> %s match %s using %s", strings.ToUpper(metadata.NetWork.String()), metadata.SourceDetail(), metadata.RemoteAddress(), fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload()), remoteConn.Chains().String()) + } else { + log.Infoln("[%s] %s --> %s match %s using %s", strings.ToUpper(metadata.NetWork.String()), metadata.SourceDetail(), metadata.RemoteAddress(), rule.RuleType().String(), remoteConn.Chains().String()) + } + case mode == Global: + log.Infoln("[%s] %s --> %s using GLOBAL", strings.ToUpper(metadata.NetWork.String()), metadata.SourceDetail(), metadata.RemoteAddress()) + case mode == Direct: + log.Infoln("[%s] %s --> %s using DIRECT", strings.ToUpper(metadata.NetWork.String()), metadata.SourceDetail(), metadata.RemoteAddress()) + default: + log.Infoln("[%s] %s --> %s doesn't match any rule using %s", strings.ToUpper(metadata.NetWork.String()), metadata.SourceDetail(), metadata.RemoteAddress(), remoteConn.Chains().Last()) + } +} + func shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool { return rule.ShouldResolveIP() && metadata.Host != "" && !metadata.DstIP.IsValid() } diff --git a/clash-meta-android/core/src/foss/golang/go.mod b/clash-meta-android/core/src/foss/golang/go.mod index 7694c1dba9..8e8d0e9788 100644 --- a/clash-meta-android/core/src/foss/golang/go.mod +++ b/clash-meta-android/core/src/foss/golang/go.mod @@ -35,10 +35,10 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 // indirect + github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.17.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -47,17 +47,17 @@ require ( github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec // indirect github.com/metacubex/mihomo v1.7.0 // indirect - github.com/metacubex/quic-go v0.45.1-0.20240607133845-b24f02b35a22 // indirect + github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e // indirect github.com/metacubex/randv2 v0.2.0 // indirect github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 // indirect github.com/metacubex/sing-shadowsocks v0.2.6 // indirect github.com/metacubex/sing-shadowsocks2 v0.2.0 // indirect - github.com/metacubex/sing-tun v0.2.7-0.20240521155100-e8316a45a414 // indirect + github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e // indirect github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f // indirect - github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 // indirect + github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a // indirect github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 // indirect github.com/metacubex/utls v1.6.6 // indirect - github.com/miekg/dns v1.1.59 // indirect + github.com/miekg/dns v1.1.61 // indirect github.com/mroth/weightedrand/v2 v2.1.0 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect @@ -65,18 +65,19 @@ require ( github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/puzpuzpuz/xsync/v3 v3.1.0 // indirect + github.com/puzpuzpuz/xsync/v3 v3.2.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect - github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/sing v0.3.8 // indirect + github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect + github.com/sagernet/nftables v0.3.0-beta.4 // indirect + github.com/sagernet/sing v0.5.0-alpha.10 // indirect github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e // indirect github.com/samber/lo v1.39.0 // indirect - github.com/shirou/gopsutil/v3 v3.24.4 // indirect + github.com/shirou/gopsutil/v3 v3.24.5 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect @@ -85,28 +86,28 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect - github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect + github.com/vishvananda/netns v0.0.4 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.4.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.0 // indirect - google.golang.org/protobuf v1.34.1 // indirect + golang.org/x/tools v0.22.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2 replace cfa => ../../main/golang diff --git a/clash-meta-android/core/src/foss/golang/go.sum b/clash-meta-android/core/src/foss/golang/go.sum index 1cfaefffc9..206a150909 100644 --- a/clash-meta-android/core/src/foss/golang/go.sum +++ b/clash-meta-android/core/src/foss/golang/go.sum @@ -63,7 +63,6 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= @@ -72,16 +71,16 @@ github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 h1:/OuvSMGT9+xnyZ+7MZQ1zdngaCCAdPoSw8B/uurZ7pg= -github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= +github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 h1:dh8D8FksyMhD64mRMbUhZHWYJfNoNMCxfVq6eexleMw= +github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -98,30 +97,30 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec/go.mod h1:8BVmQ+3cxjqzWElafm24rb2Ae4jRI6vAXNXWqWjfrXw= -github.com/metacubex/quic-go v0.45.1-0.20240607133845-b24f02b35a22 h1:dKYoWnrB5bbCMoMQit4INUDKiDcjc0Azsm3GltYf9Pw= -github.com/metacubex/quic-go v0.45.1-0.20240607133845-b24f02b35a22/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU= +github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e h1:bLYn3GuRvWDcBDAkIv5kUYIhzHwafDVq635BuybnKqI= +github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= -github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1 h1:7hDHLTmjgtRoAp59STwPQpe5Pinwi4cWex+FB3Ohvco= -github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= +github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2 h1:N5tidgg/FRmkgPw/AjRwhLUinKDx/ODCSbvv9xqRoLM= +github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 h1:Wr4g1HCb5Z/QIFwFiVNjO2qL+dRu25+Mdn9xtAZZ+ew= github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= github.com/metacubex/sing-shadowsocks2 v0.2.0/go.mod h1:LCKF6j1P94zN8ZS+LXRK1gmYTVGB3squivBSXAFnOg8= -github.com/metacubex/sing-tun v0.2.7-0.20240521155100-e8316a45a414 h1:IPxTZgQV6fVUBS8tozLMSFPHV3imYc/NbuGfp0bLQq0= -github.com/metacubex/sing-tun v0.2.7-0.20240521155100-e8316a45a414/go.mod h1:4VsMwZH1IlgPGFK1ZbBomZ/B2MYkTgs2+gnBAr5GOIo= +github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e h1:o+zohxPRo45P35fS9u1zfdBgr+L/7S0ObGU6YjbVBIc= +github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e/go.mod h1:WwJGbCx7bQcBzuQXiDOJvZH27R0kIjKNNlISIWsL6kM= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= -github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 h1:AGyIB55UfQm/0ZH0HtQO9u3l//yjtHUpjeRjjPGfGRI= -github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo= +github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a h1:NpSGclHJUYndUwBmyIpFBSoBVg8PoVX7QQKhYg0DjM0= +github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo= github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 h1:as/aO/fM8nv4W4pOr9EETP6kV/Oaujk3fUNyQSJK61c= github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts= github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8= github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo= -github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= -github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= @@ -143,8 +142,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/puzpuzpuz/xsync/v3 v3.1.0 h1:EewKT7/LNac5SLiEblJeUu8z5eERHrmRLnMQL2d7qX4= -github.com/puzpuzpuz/xsync/v3 v3.1.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/puzpuzpuz/xsync/v3 v3.2.0 h1:9AzuUeF88YC5bK8u2vEG1Fpvu4wgpM1wfPIExfaaDxQ= +github.com/puzpuzpuz/xsync/v3 v3.2.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= @@ -152,8 +151,10 @@ github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= -github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= -github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= +github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= +github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 h1:5bCAkvDDzSMITiHFjolBwpdqYsvycdTu71FsMEFXQ14= github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= @@ -164,12 +165,11 @@ github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e h1:iGH0RMv2F github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e/go.mod h1:YbL4TKHRR6APYQv3U2RGfwLDpPYSyWz6oUlpISBEzBE= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU= -github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= -github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b/go.mod h1:X7qrxNQViEaAN9LNZOPl9PfvQtp3V3c7LTo0dvGi0fM= github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6yjG3IxDaeAj3PCoRr+IsO+bzyT+Se2m2Hk= @@ -199,8 +199,8 @@ github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -213,18 +213,18 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -243,23 +243,21 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/clash-meta-android/core/src/main/golang/go.mod b/clash-meta-android/core/src/main/golang/go.mod index 57c23c4e00..d2676f4ff5 100644 --- a/clash-meta-android/core/src/main/golang/go.mod +++ b/clash-meta-android/core/src/main/golang/go.mod @@ -6,7 +6,7 @@ require ( github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 github.com/dlclark/regexp2 v1.11.0 github.com/metacubex/mihomo v1.7.0 - github.com/miekg/dns v1.1.59 + github.com/miekg/dns v1.1.61 github.com/oschwald/maxminddb-golang v1.12.0 golang.org/x/sync v0.7.0 gopkg.in/yaml.v2 v2.4.0 @@ -14,7 +14,7 @@ require ( replace github.com/metacubex/mihomo => ../../foss/golang/clash -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2 require ( github.com/3andne/restls-client-go v0.1.6 // indirect @@ -43,10 +43,10 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 // indirect + github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.17.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -54,14 +54,14 @@ require ( github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec // indirect - github.com/metacubex/quic-go v0.45.1-0.20240607133845-b24f02b35a22 // indirect + github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e // indirect github.com/metacubex/randv2 v0.2.0 // indirect github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 // indirect github.com/metacubex/sing-shadowsocks v0.2.6 // indirect github.com/metacubex/sing-shadowsocks2 v0.2.0 // indirect - github.com/metacubex/sing-tun v0.2.7-0.20240521155100-e8316a45a414 // indirect + github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e // indirect github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f // indirect - github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 // indirect + github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a // indirect github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 // indirect github.com/metacubex/utls v1.6.6 // indirect github.com/mroth/weightedrand/v2 v2.1.0 // indirect @@ -70,18 +70,19 @@ require ( github.com/openacid/low v0.1.21 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/puzpuzpuz/xsync/v3 v3.1.0 // indirect + github.com/puzpuzpuz/xsync/v3 v3.2.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect - github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/sing v0.3.8 // indirect + github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect + github.com/sagernet/nftables v0.3.0-beta.4 // indirect + github.com/sagernet/sing v0.5.0-alpha.10 // indirect github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e // indirect github.com/samber/lo v1.39.0 // indirect - github.com/shirou/gopsutil/v3 v3.24.4 // indirect + github.com/shirou/gopsutil/v3 v3.24.5 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect @@ -90,21 +91,21 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect - github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect + github.com/vishvananda/netns v0.0.4 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.4.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.0 // indirect - google.golang.org/protobuf v1.34.1 // indirect + golang.org/x/tools v0.22.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/clash-meta-android/core/src/main/golang/go.sum b/clash-meta-android/core/src/main/golang/go.sum index 1cfaefffc9..206a150909 100644 --- a/clash-meta-android/core/src/main/golang/go.sum +++ b/clash-meta-android/core/src/main/golang/go.sum @@ -63,7 +63,6 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= @@ -72,16 +71,16 @@ github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 h1:/OuvSMGT9+xnyZ+7MZQ1zdngaCCAdPoSw8B/uurZ7pg= -github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= +github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 h1:dh8D8FksyMhD64mRMbUhZHWYJfNoNMCxfVq6eexleMw= +github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -98,30 +97,30 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec/go.mod h1:8BVmQ+3cxjqzWElafm24rb2Ae4jRI6vAXNXWqWjfrXw= -github.com/metacubex/quic-go v0.45.1-0.20240607133845-b24f02b35a22 h1:dKYoWnrB5bbCMoMQit4INUDKiDcjc0Azsm3GltYf9Pw= -github.com/metacubex/quic-go v0.45.1-0.20240607133845-b24f02b35a22/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU= +github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e h1:bLYn3GuRvWDcBDAkIv5kUYIhzHwafDVq635BuybnKqI= +github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= -github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1 h1:7hDHLTmjgtRoAp59STwPQpe5Pinwi4cWex+FB3Ohvco= -github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= +github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2 h1:N5tidgg/FRmkgPw/AjRwhLUinKDx/ODCSbvv9xqRoLM= +github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 h1:Wr4g1HCb5Z/QIFwFiVNjO2qL+dRu25+Mdn9xtAZZ+ew= github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= github.com/metacubex/sing-shadowsocks2 v0.2.0/go.mod h1:LCKF6j1P94zN8ZS+LXRK1gmYTVGB3squivBSXAFnOg8= -github.com/metacubex/sing-tun v0.2.7-0.20240521155100-e8316a45a414 h1:IPxTZgQV6fVUBS8tozLMSFPHV3imYc/NbuGfp0bLQq0= -github.com/metacubex/sing-tun v0.2.7-0.20240521155100-e8316a45a414/go.mod h1:4VsMwZH1IlgPGFK1ZbBomZ/B2MYkTgs2+gnBAr5GOIo= +github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e h1:o+zohxPRo45P35fS9u1zfdBgr+L/7S0ObGU6YjbVBIc= +github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e/go.mod h1:WwJGbCx7bQcBzuQXiDOJvZH27R0kIjKNNlISIWsL6kM= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= -github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 h1:AGyIB55UfQm/0ZH0HtQO9u3l//yjtHUpjeRjjPGfGRI= -github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo= +github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a h1:NpSGclHJUYndUwBmyIpFBSoBVg8PoVX7QQKhYg0DjM0= +github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo= github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 h1:as/aO/fM8nv4W4pOr9EETP6kV/Oaujk3fUNyQSJK61c= github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts= github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8= github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo= -github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= -github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= @@ -143,8 +142,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/puzpuzpuz/xsync/v3 v3.1.0 h1:EewKT7/LNac5SLiEblJeUu8z5eERHrmRLnMQL2d7qX4= -github.com/puzpuzpuz/xsync/v3 v3.1.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/puzpuzpuz/xsync/v3 v3.2.0 h1:9AzuUeF88YC5bK8u2vEG1Fpvu4wgpM1wfPIExfaaDxQ= +github.com/puzpuzpuz/xsync/v3 v3.2.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= @@ -152,8 +151,10 @@ github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= -github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= -github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= +github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= +github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 h1:5bCAkvDDzSMITiHFjolBwpdqYsvycdTu71FsMEFXQ14= github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= @@ -164,12 +165,11 @@ github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e h1:iGH0RMv2F github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e/go.mod h1:YbL4TKHRR6APYQv3U2RGfwLDpPYSyWz6oUlpISBEzBE= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU= -github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= -github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b/go.mod h1:X7qrxNQViEaAN9LNZOPl9PfvQtp3V3c7LTo0dvGi0fM= github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6yjG3IxDaeAj3PCoRr+IsO+bzyT+Se2m2Hk= @@ -199,8 +199,8 @@ github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -213,18 +213,18 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -243,23 +243,21 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock index 07c0c560f9..9e67132eae 100644 --- a/clash-nyanpasu/backend/Cargo.lock +++ b/clash-nyanpasu/backend/Cargo.lock @@ -895,6 +895,7 @@ dependencies = [ "parking_lot", "percent-encoding", "port_scanner", + "rand 0.8.5", "redb", "reqwest", "rfd", @@ -5177,9 +5178,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.118" +version = "1.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" +checksum = "e8eddb61f0697cc3989c5d64b452f5488e2b8a60fd7d5076a3045076ffef8cb0" dependencies = [ "indexmap 2.2.6", "itoa 1.0.11", diff --git a/clash-nyanpasu/backend/tauri/Cargo.toml b/clash-nyanpasu/backend/tauri/Cargo.toml index b8001a51d3..f752c5fede 100644 --- a/clash-nyanpasu/backend/tauri/Cargo.toml +++ b/clash-nyanpasu/backend/tauri/Cargo.toml @@ -99,6 +99,7 @@ derive_builder = "0.20" test-log = { version = "0.2.16", features = ["trace"] } md-5 = "0.10.6" hex = "0.4" +rand = "0.8" [target.'cfg(windows)'.dependencies] deelevate = "0.2.0" diff --git a/clash-nyanpasu/backend/tauri/src/cmds.rs b/clash-nyanpasu/backend/tauri/src/cmds.rs index 44114562b3..19d9ab5a9d 100644 --- a/clash-nyanpasu/backend/tauri/src/cmds.rs +++ b/clash-nyanpasu/backend/tauri/src/cmds.rs @@ -266,7 +266,7 @@ pub fn save_window_size_state() -> CmdResult<()> { #[tauri::command] pub async fn fetch_latest_core_versions() -> CmdResult { - let mut updater = updater::Updater::global().write().await; // It is intended to block here + let mut updater = updater::UpdaterManager::global().write().await; // It is intended to block here wrap_err!(updater.fetch_latest().await)?; Ok(updater.get_latest_versions()) } @@ -305,16 +305,26 @@ pub async fn collect_logs() -> CmdResult { } #[tauri::command] -pub async fn update_core(core_type: nyanpasu::ClashCore) -> CmdResult { +pub async fn update_core(core_type: nyanpasu::ClashCore) -> CmdResult { wrap_err!( - updater::Updater::global() - .read() + updater::UpdaterManager::global() + .write() .await .update_core(&core_type) .await ) } +#[tauri::command] +pub async fn inspect_updater(updater_id: usize) -> CmdResult { + let updater = wrap_err!(updater::UpdaterManager::global() + .read() + .await + .inspect_updater(updater_id) + .ok_or(anyhow::anyhow!("updater is not exist")))?; + Ok(updater) +} + #[tauri::command] pub async fn clash_api_get_proxy_delay( name: String, diff --git a/clash-nyanpasu/backend/tauri/src/core/updater.rs b/clash-nyanpasu/backend/tauri/src/core/updater.rs deleted file mode 100644 index f739ed1d7c..0000000000 --- a/clash-nyanpasu/backend/tauri/src/core/updater.rs +++ /dev/null @@ -1,384 +0,0 @@ -use std::{collections::HashMap, io::Cursor, path::Path, sync::OnceLock}; - -use super::CoreManager; -use crate::config::nyanpasu::ClashCore; -use anyhow::{anyhow, Result}; -use gunzip::Decompressor; -use log::{debug, warn}; -use runas::Command as RunasCommand; -use serde::{Deserialize, Serialize}; -#[cfg(target_family = "unix")] -use std::os::unix::fs::PermissionsExt; -use tempfile::{tempdir, TempDir}; -use tokio::{join, sync::RwLock, task::spawn_blocking}; -use zip::ZipArchive; - -pub struct Updater { - manifest_version: ManifestVersion, - mirror: String, -} - -impl Default for Updater { - fn default() -> Self { - Self { - manifest_version: ManifestVersion::default(), - mirror: "https://mirror.ghproxy.com/github.com".to_string(), - } - } -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub struct ManifestVersion { - manifest_version: u64, - latest: ManifestVersionLatest, - arch_template: ArchTemplate, - updated_at: String, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub struct ManifestVersionLatest { - mihomo: String, - mihomo_alpha: String, - clash_rs: String, - clash_premium: String, -} - -#[derive(Deserialize, Serialize, Default, Clone, Debug)] -pub struct ArchTemplate { - mihomo: HashMap, - mihomo_alpha: HashMap, - clash_rs: HashMap, - clash_premium: HashMap, -} - -impl Default for ManifestVersion { - fn default() -> Self { - Self { - manifest_version: 0, - latest: ManifestVersionLatest::default(), - arch_template: ArchTemplate::default(), - updated_at: "".to_string(), - } - } -} - -impl Default for ManifestVersionLatest { - fn default() -> Self { - Self { - mihomo: "".to_string(), - mihomo_alpha: "".to_string(), - clash_rs: "".to_string(), - clash_premium: "".to_string(), - } - } -} - -fn get_arch() -> Result<&'static str> { - let env = { - let arch = std::env::consts::ARCH; - let os = std::env::consts::OS; - (arch, os) - }; - - match env { - ("x86_64", "macos") => Ok("darwin-x64"), - ("x86_64", "linux") => Ok("linux-amd64"), - ("x86_64", "windows") => Ok("windows-x86_64"), - ("aarch64", "macos") => Ok("darwin-arm64"), - ("aarch64", "linux") => Ok("linux-aarch64"), - // ("aarch64", "windows") => Ok("windows-arm64"), - _ => anyhow::bail!("unsupported platform"), - } -} - -impl Updater { - pub fn new() -> Self { - Self::default() - } - - pub fn global() -> &'static RwLock { - static INSTANCE: OnceLock> = OnceLock::new(); - INSTANCE.get_or_init(|| RwLock::new(Updater::new())) - } - - pub fn get_latest_versions(&self) -> ManifestVersionLatest { - self.manifest_version.latest.clone() - } - - pub async fn fetch_latest(&mut self) -> Result<()> { - let latest = get_latest_version_manifest(self.mirror.as_str()); - let mihomo_alpha_version = self.get_mihomo_alpha_version(); - let (latest, mihomo_alpha_version) = join!(latest, mihomo_alpha_version); - log::debug!("latest version: {:?}", latest); - self.manifest_version = latest?; - log::debug!("mihomo alpha version: {:?}", mihomo_alpha_version); - self.manifest_version.latest.mihomo_alpha = mihomo_alpha_version?; - Ok(()) - } - - async fn get_mihomo_alpha_version(&self) -> Result { - let client = crate::utils::candy::get_reqwest_client()?; - let url = format!( - "{}/{}", - self.mirror.as_str(), - "MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt" - ); - let res = client.get(url).send().await?; - let status_code = res.status(); - if !status_code.is_success() { - anyhow::bail!( - "failed to get mihomo alpha version: response status is {}, expected 200", - status_code - ); - } - Ok(res.text().await?.trim().to_string()) - } - - pub async fn update_core(&self, core_type: &ClashCore) -> Result<()> { - let current_core = crate::config::Config::verge() - .latest() - .clash_core - .clone() - .unwrap_or_default(); - let tmp_dir = tempdir()?; - // 1. download core - debug!("downloading core"); - let artifact = self.download_core(core_type, &tmp_dir).await?; - // 2. decompress core - debug!("decompressing core"); - let core_type_ref = core_type.clone(); - let tmp_dir_path = tmp_dir.path().to_owned(); - let artifact_ref = artifact.clone(); - spawn_blocking(move || { - decompress_and_set_permission(&core_type_ref, &tmp_dir_path, &artifact_ref) - }) - .await??; - // 3. if core is used, close it - if current_core == *core_type { - tokio::task::spawn_blocking(move || CoreManager::global().stop_core()).await??; - } - // 4. replace core - #[cfg(target_os = "windows")] - let target_core = format!("{}.exe", core_type); - #[cfg(not(target_os = "windows"))] - let target_core = core_type.clone().to_string(); - let core_dir = tauri::utils::platform::current_exe()?; - let core_dir = core_dir.parent().ok_or(anyhow!("failed to get core dir"))?; - let target_core = core_dir.join(target_core); - debug!("copying core to {:?}", target_core); - let tmp_core_path = tmp_dir.path().join(core_type.clone().to_string()); - match std::fs::copy(tmp_core_path.clone(), target_core.clone()) { - Ok(_) => {} - Err(err) => { - warn!( - "failed to copy core: {}, trying to use elevated permission to copy and override core", - err - ); - let mut target_core_str = target_core.to_str().unwrap().to_string(); - if target_core_str.starts_with("\\\\?\\") { - target_core_str = target_core_str[4..].to_string(); - } - debug!("tmp core path: {:?}", tmp_core_path); - debug!("target core path: {:?}", target_core_str); - // 防止 UAC 弹窗堵塞主线程 - let status_code = tokio::task::spawn_blocking(move || { - #[cfg(target_os = "windows")] - { - RunasCommand::new("cmd") - .args(&[ - "/C", - "copy", - "/Y", - tmp_core_path.to_str().unwrap(), - &target_core_str, - ]) - .status() - } - #[cfg(not(target_os = "windows"))] - { - RunasCommand::new("cp") - .args(&["-f", tmp_core_path.to_str().unwrap(), &target_core_str]) - .status() - } - }) - .await??; - if !status_code.success() { - anyhow::bail!("failed to copy core: {}", status_code); - } - } - }; - - // 5. if core is used before, restart it - if current_core == *core_type { - CoreManager::global().run_core().await?; - } - Ok(()) - } - - async fn download_core(&self, core_type: &ClashCore, tmp_dir: &TempDir) -> Result { - let arch = get_arch()?; - debug!("download core: {} in arch {}", core_type, arch); - let version_manifest = &self.manifest_version; - let (artifact, core_type_meta) = match core_type { - ClashCore::ClashPremium => ( - version_manifest - .arch_template - .clash_premium - .get(arch) - .ok_or(anyhow!("invalid arch"))? - .clone() - .replace("{}", &version_manifest.latest.clash_premium), - CoreTypeMeta::ClashPremium(version_manifest.latest.clash_premium.clone()), - ), - ClashCore::Mihomo => ( - version_manifest - .arch_template - .mihomo - .get(arch) - .ok_or(anyhow!("invalid arch"))? - .clone() - .replace("{}", &version_manifest.latest.mihomo), - CoreTypeMeta::Mihomo(version_manifest.latest.mihomo.clone()), - ), - ClashCore::MihomoAlpha => ( - version_manifest - .arch_template - .mihomo_alpha - .get(arch) - .ok_or(anyhow!("invalid arch"))? - .clone() - .replace("{}", &version_manifest.latest.mihomo_alpha), - CoreTypeMeta::MihomoAlpha, - ), - ClashCore::ClashRs => ( - version_manifest - .arch_template - .clash_rs - .get(arch) - .ok_or(anyhow!("invalid arch"))? - .clone() - .replace("{}", &version_manifest.latest.clash_rs), - CoreTypeMeta::ClashRs(version_manifest.latest.clash_rs.clone()), - ), - }; - debug!("artifact: {}", artifact); - let url = format!( - "{}/{}", - &self.mirror, - get_download_path(core_type_meta, artifact.clone()) - ); - debug!("url: {}", url); - let file_path = tmp_dir.path().join(&artifact); - debug!("file path: {:?}", file_path); - let mut dst = std::fs::File::create(&file_path)?; - - let client = crate::utils::candy::get_reqwest_client()?; - let res = client.get(url).send().await?; - let status_code = res.status(); - if !status_code.is_success() { - anyhow::bail!( - "failed to download core: response status is {}, expected 200", - status_code - ); - } - let mut buff = Cursor::new(res.bytes().await?); - std::io::copy(&mut buff, &mut dst)?; - Ok(artifact) - } -} - -fn decompress_and_set_permission( - core_type: &ClashCore, - tmp_path: &Path, - fname: &str, -) -> Result<()> { - let mut buff = Vec::::new(); - let path = tmp_path.join(fname); - debug!("decompressing file: {:?}", path); - let mut tmp_file = std::fs::File::open(path)?; - debug!("file size: {}", tmp_file.metadata()?.len()); - match fname { - fname if fname.ends_with(".gz") => { - debug!("decompressing gz file"); - let mut decompressor = Decompressor::new(tmp_file, true); - std::io::copy(&mut decompressor, &mut buff)?; - } - fname if fname.ends_with(".zip") => { - debug!("decompressing zip file"); - let mut archive = ZipArchive::new(tmp_file)?; - let len = archive.len(); - for i in 0..len { - let mut file = archive.by_index(i)?; - let file_name = file.name(); - debug!("Filename: {}", file.name()); - // TODO: 在 enum 做点魔法 - if file_name.contains("mihomo") || file_name.contains("clash") { - debug!("extract file: {}", file_name); - debug!("extract file size: {}", file.size()); - std::io::copy(&mut file, &mut buff)?; - break; - } - if i == len - 1 { - anyhow::bail!("failed to find core file in a zip archive"); - } - } - } - _ => { - debug!("directly copying file"); - std::io::copy(&mut tmp_file, &mut buff)?; - } - }; - let tmp_core = tmp_path.join(core_type.clone().to_string()); - debug!("writing core to {:?} ({} bytes)", tmp_core, buff.len()); - let mut core_file = std::fs::File::create(&tmp_core)?; - std::io::copy(&mut buff.as_slice(), &mut core_file)?; - #[cfg(target_family = "unix")] - { - std::fs::set_permissions(&tmp_core, std::fs::Permissions::from_mode(0o755))?; - } - Ok(()) -} - -pub async fn get_latest_version_manifest(mirror: &str) -> Result { - let url = format!( - "{}/LibNyanpasu/clash-nyanpasu/raw/main/manifest/version.json", - mirror - ); - log::debug!("{}", url); - let client = crate::utils::candy::get_reqwest_client()?; - let res = client.get(url).send().await?; - let status_code = res.status(); - if !status_code.is_success() { - anyhow::bail!( - "failed to get latest version manifest: response status is {}, expected 200", - status_code - ); - } - Ok(res.json::().await?) -} - -enum CoreTypeMeta { - ClashPremium(String), - Mihomo(String), - MihomoAlpha, - ClashRs(String), -} - -fn get_download_path(core_type: CoreTypeMeta, artifact: String) -> String { - match core_type { - CoreTypeMeta::Mihomo(tag) => { - format!("MetaCubeX/mihomo/releases/download/{}/{}", tag, artifact) - } - CoreTypeMeta::MihomoAlpha => format!( - "MetaCubeX/mihomo/releases/download/Prerelease-Alpha/{}", - artifact - ), - CoreTypeMeta::ClashRs(tag) => { - format!("Watfaq/clash-rs/releases/download/{}/{}", tag, artifact) - } - CoreTypeMeta::ClashPremium(tag) => format!( - "zhongfly/Clash-premium-backup/releases/download/{}/{}", - tag, artifact - ), - } -} diff --git a/clash-nyanpasu/backend/tauri/src/core/updater/instance.rs b/clash-nyanpasu/backend/tauri/src/core/updater/instance.rs new file mode 100644 index 0000000000..d39225aa8a --- /dev/null +++ b/clash-nyanpasu/backend/tauri/src/core/updater/instance.rs @@ -0,0 +1,341 @@ +use super::shared::{self, CoreTypeMeta}; +use crate::{ + config::nyanpasu::ClashCore, + core::CoreManager, + utils::downloader::{DownloadStatus, Downloader, DownloaderBuilder, DownloaderState}, +}; +use anyhow::anyhow; +use runas::Command as RunasCommand; +use serde::Serialize; +#[cfg(target_family = "unix")] +use std::os::unix::fs::PermissionsExt; +use std::sync::Arc; +use tempfile::TempDir; +use tokio::sync::Mutex; + +#[derive(Debug, Clone, Serialize, Default)] +pub enum UpdaterState { + #[default] + Idle, + Downloading, + Decompressing, + Replacing, + Restarting, + Done, + Failed(String), +} + +type DownloaderWithDynCallback = Downloader>; + +pub(super) struct Updater { + id: usize, + temp_dir: TempDir, + core_type: ClashCore, + artifact: String, + inner: parking_lot::RwLock, + rx: Mutex>, + downloader: Arc, +} + +struct UpdaterInner { + state: UpdaterState, +} + +#[derive(Debug, Serialize)] +pub struct UpdaterSummary { + pub id: usize, + pub state: UpdaterState, + pub downloader: DownloadStatus, +} + +pub(super) struct UpdaterBuilder { + client: Option, + core_type: Option, + mirror: Option, + artifact: Option, + tag: Option, +} + +impl UpdaterBuilder { + pub fn new() -> Self { + Self { + client: None, + core_type: None, + mirror: None, + artifact: None, + tag: None, + } + } + + pub fn set_client(mut self, client: reqwest::Client) -> Self { + self.client = Some(client); + self + } + + pub fn set_core_type(mut self, core_type: ClashCore) -> Self { + self.core_type = Some(core_type); + self + } + + pub fn set_artifact(mut self, artifact: String) -> Self { + self.artifact = Some(artifact); + self + } + + pub fn set_tag(mut self, tag: CoreTypeMeta) -> Self { + self.tag = Some(tag); + self + } + + pub fn set_mirror(mut self, mirror: String) -> Self { + self.mirror = Some(mirror); + self + } + + pub async fn build(self) -> anyhow::Result { + let client = self.client.ok_or(anyhow::anyhow!("client is required"))?; + let core_type = self + .core_type + .ok_or(anyhow::anyhow!("core_type is required"))?; + let artifact = self + .artifact + .ok_or(anyhow::anyhow!("artifact is required"))?; + let tag = self.tag.ok_or(anyhow::anyhow!("tag is required"))?; + let mirror = self.mirror.ok_or(anyhow::anyhow!("mirror is required"))?; + + let temp_dir = TempDir::new()?; + let inner = UpdaterInner { + state: UpdaterState::Idle, + }; + + // setup downloader + let download_path = shared::get_download_path(tag, &artifact); + let mut download_url = url::Url::parse("https://github.com")?; + download_url.set_path(&download_path); + let download_url = crate::utils::candy::parse_gh_url(&mirror, download_url.as_str())?; + let file = tokio::fs::File::create(temp_dir.path().join(&artifact)).await?; + let (tx, rx) = tokio::sync::mpsc::channel::(1); + let callback: Box = Box::new(move |state| { + let tx = tx.clone(); + tokio::spawn(async move { + if let Err(e) = tx.send(state).await { + tracing::warn!("failed to send downloader state: {}", e); + } + }); + }); + let downloader = Arc::new( + DownloaderBuilder::new() + .set_client(client) + .set_url(download_url)? + .set_file(file) + .set_event_callback(callback) + .build()?, + ); + Ok(Updater { + id: rand::random(), + temp_dir, + core_type, + inner: parking_lot::RwLock::new(inner), + artifact, + rx: Mutex::new(rx), + downloader, + }) + } +} + +impl Updater { + fn dispatch_state(&self, state: UpdaterState) { + let mut inner = self.inner.write(); + inner.state = state; + } + + async fn decompress_and_set_premission(&self) -> anyhow::Result<()> { + self.dispatch_state(UpdaterState::Decompressing); + let path = self.temp_dir.path().join(&self.artifact); + tracing::debug!("decompressing file: {:?}", path); + let mut tmp_file = std::fs::File::open(path)?; + tracing::debug!("file size: {}", tmp_file.metadata()?.len()); + let artifact = self.artifact.clone(); + let buff = tokio::task::spawn_blocking(move || { + let mut buff = Vec::::new(); + match artifact { + fname if fname.ends_with(".gz") => { + tracing::debug!("decompressing gz file"); + let mut decompressor = gunzip::Decompressor::new(tmp_file, true); + std::io::copy(&mut decompressor, &mut buff)?; + } + fname if fname.ends_with(".zip") => { + tracing::debug!("decompressing zip file"); + let mut archive = zip::ZipArchive::new(tmp_file)?; + let len = archive.len(); + for i in 0..len { + let mut file = archive.by_index(i)?; + let file_name = file.name(); + tracing::debug!("Filename: {}", file.name()); + // TODO: 在 enum 做点魔法 + if file_name.contains("mihomo") || file_name.contains("clash") { + tracing::debug!("extract file: {}", file_name); + tracing::debug!("extract file size: {}", file.size()); + std::io::copy(&mut file, &mut buff)?; + break; + } + if i == len - 1 { + anyhow::bail!("failed to find core file in a zip archive"); + } + } + } + _ => { + tracing::debug!("directly copying file"); + std::io::copy(&mut tmp_file, &mut buff)?; + } + }; + Ok::<_, anyhow::Error>(buff) + }) + .await??; + let tmp_core = self.temp_dir.path().join(self.core_type.to_string()); + tracing::debug!("writing core to {:?} ({} bytes)", tmp_core, buff.len()); + let mut core_file = tokio::fs::File::create(&tmp_core).await?; + tokio::io::copy(&mut buff.as_slice(), &mut core_file).await?; + #[cfg(target_family = "unix")] + { + std::fs::set_permissions(&tmp_core, std::fs::Permissions::from_mode(0o755))?; + } + Ok(()) + } + + async fn replace_core(&self) -> anyhow::Result<()> { + self.dispatch_state(UpdaterState::Replacing); + let current_core = crate::config::Config::verge() + .latest() + .clash_core + .clone() + .unwrap_or_default(); + if current_core == self.core_type { + tokio::task::spawn_blocking(move || CoreManager::global().stop_core()).await??; + return Ok(()); + } + #[cfg(target_os = "windows")] + let target_core = format!("{}.exe", self.core_type); + #[cfg(not(target_os = "windows"))] + let target_core = self.core_type.clone().to_string(); + let core_dir = tauri::utils::platform::current_exe()?; + let core_dir = core_dir.parent().ok_or(anyhow!("failed to get core dir"))?; + let target_core = core_dir.join(target_core); + tracing::debug!("copying core to {:?}", target_core); + let tmp_core_path = self.temp_dir.path().join(&self.artifact); + match tokio::fs::copy(tmp_core_path.clone(), target_core.clone()).await { + Ok(_) => {} + Err(err) => { + tracing::warn!( + "failed to copy core: {}, trying to use elevated permission to copy and override core", + err + ); + let mut target_core_str = target_core.to_str().unwrap().to_string(); + if target_core_str.starts_with("\\\\?\\") { + target_core_str = target_core_str[4..].to_string(); + } + tracing::debug!("tmp core path: {:?}", tmp_core_path); + tracing::debug!("target core path: {:?}", target_core_str); + // 防止 UAC 弹窗堵塞主线程 + let status_code = tokio::task::spawn_blocking(move || { + #[cfg(target_os = "windows")] + { + RunasCommand::new("cmd") + .args(&[ + "/C", + "copy", + "/Y", + tmp_core_path.to_str().unwrap(), + &target_core_str, + ]) + .status() + } + #[cfg(not(target_os = "windows"))] + { + RunasCommand::new("cp") + .args(&["-f", tmp_core_path.to_str().unwrap(), &target_core_str]) + .status() + } + }) + .await??; + if !status_code.success() { + anyhow::bail!("failed to copy core: {}", status_code); + } + } + }; + + if current_core == self.core_type { + self.dispatch_state(UpdaterState::Restarting); + CoreManager::global().run_core().await?; + } + + Ok(()) + } + + pub async fn start(&self) { + { + let mut inner = self.inner.write(); + if !matches!(inner.state, UpdaterState::Idle) { + return; + } + inner.state = UpdaterState::Downloading; + } + let downloader = self.downloader.clone(); + tokio::spawn(async move { + if let Err(e) = downloader.start().await { + tracing::error!("failed to start downloader: {}", e); + } + }); + let mut rx = self.rx.lock().await; + loop { + match rx.recv().await { + Some(state) => match state { + DownloaderState::Downloading => { + tracing::debug!("start to download core."); + self.dispatch_state(UpdaterState::Downloading); + } + DownloaderState::Finished => { + tracing::debug!("download finished and start to incoming update logic"); + if let Err(e) = self.decompress_and_set_premission().await { + tracing::error!("failed to decompress and set permission: {}", e); + self.dispatch_state(UpdaterState::Failed(e.to_string())); + return; + } + if let Err(e) = self.replace_core().await { + tracing::error!("failed to replace core: {}", e); + self.dispatch_state(UpdaterState::Failed(e.to_string())); + return; + } + self.dispatch_state(UpdaterState::Done); + break; + } + DownloaderState::Failed(e) => { + tracing::error!("download failed: {}", e); + self.dispatch_state(UpdaterState::Failed(e)); + break; + } + _ => { + tracing::debug!("downloader enter state: {:?}", state); + } + }, + None => { + tracing::error!("downloader channel closed"); + } + } + } + } + + pub fn get_report(&self) -> UpdaterSummary { + UpdaterSummary { + id: self.id, + state: self.inner.read().state.clone(), + downloader: self.downloader.get_current_status(), + } + } + + pub fn get_updater_id(&self) -> usize { + self.id + } +} + +unsafe impl Send for Updater {} diff --git a/clash-nyanpasu/backend/tauri/src/core/updater/mod.rs b/clash-nyanpasu/backend/tauri/src/core/updater/mod.rs new file mode 100644 index 0000000000..30e2ca2dd3 --- /dev/null +++ b/clash-nyanpasu/backend/tauri/src/core/updater/mod.rs @@ -0,0 +1,258 @@ +use std::{ + collections::HashMap, + sync::{Arc, OnceLock}, +}; + +use crate::{config::nyanpasu::ClashCore, utils::candy::ReqwestSpeedTestExt}; +use anyhow::{anyhow, Result}; +use dashmap::DashMap; +use serde::{Deserialize, Serialize}; +use shared::{get_arch, CoreTypeMeta}; +use tokio::{join, sync::RwLock}; + +mod instance; +mod shared; + +pub use instance::UpdaterSummary; + +pub struct UpdaterManager { + manifest_version: ManifestVersion, + client: reqwest::Client, + mirror: Arc>>, + instances: Arc>>, +} + +impl Default for UpdaterManager { + fn default() -> Self { + Self { + manifest_version: ManifestVersion::default(), + client: crate::utils::candy::get_reqwest_client().unwrap(), + mirror: Arc::new(parking_lot::RwLock::new(None)), + instances: Arc::new(DashMap::new()), + } + } +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct ManifestVersion { + manifest_version: u64, + latest: ManifestVersionLatest, + arch_template: ArchTemplate, + updated_at: String, +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct ManifestVersionLatest { + mihomo: String, + mihomo_alpha: String, + clash_rs: String, + clash_premium: String, +} + +#[derive(Deserialize, Serialize, Default, Clone, Debug)] +pub struct ArchTemplate { + mihomo: HashMap, + mihomo_alpha: HashMap, + clash_rs: HashMap, + clash_premium: HashMap, +} + +impl Default for ManifestVersion { + fn default() -> Self { + Self { + manifest_version: 0, + latest: ManifestVersionLatest::default(), + arch_template: ArchTemplate::default(), + updated_at: "".to_string(), + } + } +} + +impl Default for ManifestVersionLatest { + fn default() -> Self { + Self { + mihomo: "".to_string(), + mihomo_alpha: "".to_string(), + clash_rs: "".to_string(), + clash_premium: "".to_string(), + } + } +} + +impl ManifestVersion { + pub(self) fn get_matches(&self, core_type: &ClashCore) -> Option<(String, CoreTypeMeta)> { + let arch = get_arch().ok()?; + match core_type { + ClashCore::ClashPremium => Some(( + self.arch_template + .clash_premium + .get(arch)? + .clone() + .replace("{}", &self.latest.clash_premium), + CoreTypeMeta::ClashPremium(self.latest.clash_premium.clone()), + )), + ClashCore::Mihomo => Some(( + self.arch_template + .mihomo + .get(arch)? + .clone() + .replace("{}", &self.latest.mihomo), + CoreTypeMeta::Mihomo(self.latest.mihomo.clone()), + )), + ClashCore::MihomoAlpha => Some(( + self.arch_template + .mihomo_alpha + .get(arch)? + .clone() + .replace("{}", &self.latest.mihomo_alpha), + CoreTypeMeta::MihomoAlpha, + )), + ClashCore::ClashRs => Some(( + self.arch_template + .clash_rs + .get(arch)? + .clone() + .replace("{}", &self.latest.clash_rs), + CoreTypeMeta::ClashRs(self.latest.clash_rs.clone()), + )), + } + } +} + +impl UpdaterManager { + pub fn new() -> Self { + Self::default() + } + + pub fn global() -> &'static RwLock { + static INSTANCE: OnceLock> = OnceLock::new(); + INSTANCE.get_or_init(|| RwLock::new(UpdaterManager::new())) + } + + pub fn get_latest_versions(&self) -> ManifestVersionLatest { + self.manifest_version.latest.clone() + } + + pub fn get_mirror(&self) -> Option { + self.mirror.read().clone().map(|(mirror, _)| mirror) + } + + async fn get_latest_version_manifest(&self, mirror: &str) -> Result { + let url = format!( + "{}/LibNyanpasu/clash-nyanpasu/raw/main/manifest/version.json", + mirror + ); + log::debug!("{}", url); + let res = self.client.get(url).send().await?; + let status_code = res.status(); + if !status_code.is_success() { + anyhow::bail!( + "failed to get latest version manifest: response status is {}, expected 200", + status_code + ); + } + Ok(res.json::().await?) + } + + pub async fn fetch_latest(&mut self) -> Result<()> { + self.mirror_speed_test().await?; + let mirror = self.get_mirror().unwrap(); + let latest = self.get_latest_version_manifest(&mirror); + let mihomo_alpha_version = self.get_mihomo_alpha_version(); + let (latest, mihomo_alpha_version) = join!(latest, mihomo_alpha_version); + log::debug!("latest version: {:?}", latest); + self.manifest_version = latest?; + log::debug!("mihomo alpha version: {:?}", mihomo_alpha_version); + self.manifest_version.latest.mihomo_alpha = mihomo_alpha_version?; + Ok(()) + } + + // TODO: add user-spec mirror support + pub async fn mirror_speed_test(&self) -> Result<()> { + { + let mirror = self.mirror.read(); + if let Some((_, timestamp)) = mirror.as_ref() { + if chrono::Utc::now().timestamp() - (*timestamp as i64) < 3600 { + return Ok(()); + } + } + } + let mirrors = crate::utils::candy::INTERNAL_MIRRORS; + let path = "https://github.com/LibNyanpasu/clash-nyanpasu/raw/main/manifest/version.json"; + let client = crate::utils::candy::get_reqwest_client()?; + let results = client.mirror_speed_test(mirrors, path).await?; + let (fastest_mirror, speed) = results.first().ok_or(anyhow!("no mirrors found"))?; + if speed - 1.0 < 0.0001 { + anyhow::bail!("all mirrors are too slow"); + } + tracing::debug!("fastest mirror: {}, speed: {}", fastest_mirror, speed); + { + let mut mirror = self.mirror.write(); + *mirror = Some(( + fastest_mirror.to_string(), + chrono::Utc::now().timestamp() as u64, + )); + } + Ok(()) + } + + async fn get_mihomo_alpha_version(&self) -> Result { + self.mirror_speed_test().await?; + let mirror = self.get_mirror().unwrap(); + let url = crate::utils::candy::parse_gh_url( + &mirror, + "MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt", + )?; + let res = self.client.get(url).send().await?; + let status_code = res.status(); + if !status_code.is_success() { + anyhow::bail!( + "failed to get mihomo alpha version: response status is {}, expected 200", + status_code + ); + } + Ok(res.text().await?.trim().to_string()) + } + + pub async fn update_core(&mut self, core_type: &ClashCore) -> Result { + self.mirror_speed_test().await?; + let (artifact, tag) = self + .manifest_version + .get_matches(core_type) + .ok_or(anyhow!("no matches found for core type: {:?}", core_type))?; + let mirror = self.get_mirror().unwrap(); + let updater = Arc::new( + instance::UpdaterBuilder::new() + .set_client(self.client.clone()) + .set_core_type(core_type.clone()) + .set_mirror(mirror) + .set_artifact(artifact) + .set_tag(tag) + .build() + .await?, + ); + let updater_ref = updater.clone(); + let updater_id = updater.get_updater_id(); + self.instances.insert(updater_id, updater); + tokio::spawn(async move { + updater_ref.start().await; + }); + Ok(updater_id) + } + + pub fn inspect_updater(&self, updater_id: usize) -> Option { + let updater = self.instances.get(&updater_id)?; + let report = updater.get_report(); + if matches!( + report.state, + instance::UpdaterState::Done | instance::UpdaterState::Failed(_) + ) { + let map = self.instances.clone(); + tokio::spawn(async move { + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + map.remove(&updater_id); + }); + } + Some(report) + } +} diff --git a/clash-nyanpasu/backend/tauri/src/core/updater/shared.rs b/clash-nyanpasu/backend/tauri/src/core/updater/shared.rs new file mode 100644 index 0000000000..1c7b556030 --- /dev/null +++ b/clash-nyanpasu/backend/tauri/src/core/updater/shared.rs @@ -0,0 +1,43 @@ +pub(super) fn get_arch() -> anyhow::Result<&'static str> { + let env = { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + (arch, os) + }; + + match env { + ("x86_64", "macos") => Ok("darwin-x64"), + ("x86_64", "linux") => Ok("linux-amd64"), + ("x86_64", "windows") => Ok("windows-x86_64"), + ("aarch64", "macos") => Ok("darwin-arm64"), + ("aarch64", "linux") => Ok("linux-aarch64"), + // ("aarch64", "windows") => Ok("windows-arm64"), + _ => anyhow::bail!("unsupported platform"), + } +} + +pub(super) enum CoreTypeMeta { + ClashPremium(String), + Mihomo(String), + MihomoAlpha, + ClashRs(String), +} + +pub(super) fn get_download_path(core_type: CoreTypeMeta, artifact: &str) -> String { + match core_type { + CoreTypeMeta::Mihomo(tag) => { + format!("MetaCubeX/mihomo/releases/download/{}/{}", tag, artifact) + } + CoreTypeMeta::MihomoAlpha => format!( + "MetaCubeX/mihomo/releases/download/Prerelease-Alpha/{}", + artifact + ), + CoreTypeMeta::ClashRs(tag) => { + format!("Watfaq/clash-rs/releases/download/{}/{}", tag, artifact) + } + CoreTypeMeta::ClashPremium(tag) => format!( + "zhongfly/Clash-premium-backup/releases/download/{}/{}", + tag, artifact + ), + } +} diff --git a/clash-nyanpasu/backend/tauri/src/main.rs b/clash-nyanpasu/backend/tauri/src/main.rs index 0c6856c361..ddbfc2e161 100644 --- a/clash-nyanpasu/backend/tauri/src/main.rs +++ b/clash-nyanpasu/backend/tauri/src/main.rs @@ -142,6 +142,7 @@ fn main() -> std::io::Result<()> { // updater cmds::fetch_latest_core_versions, cmds::update_core, + cmds::inspect_updater, cmds::get_core_version, // utils cmds::collect_logs, diff --git a/clash-nyanpasu/backend/tauri/src/utils/candy.rs b/clash-nyanpasu/backend/tauri/src/utils/candy.rs index 83dcf0ce04..2ec2adefd8 100644 --- a/clash-nyanpasu/backend/tauri/src/utils/candy.rs +++ b/clash-nyanpasu/backend/tauri/src/utils/candy.rs @@ -58,59 +58,68 @@ pub fn parse_gh_url(mirror: &str, path: &str) -> Result { } } -pub async fn mirror_speed_test<'a>( - mirrors: &'a [&'a str], - path: &'a str, -) -> Result> { - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(3)) - .user_agent( - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0", - ) - .build()?; +#[async_trait::async_trait] +pub trait ReqwestSpeedTestExt { + async fn mirror_speed_test<'a>( + &self, + mirrors: &'a [&'a str], + path: &'a str, + ) -> Result>; +} - let results = futures::future::join_all(mirrors.iter().map(|&mirror| { - let client = &client; - async move { - let start = tokio::time::Instant::now(); - // if mirror is github.com, we should use it directly - let url = parse_gh_url(mirror, path)?; - tracing::debug!("Testing {}", url.as_str()); - let _ = client.get(url.as_str()).send().await; // warm up - let result = client - .get(url) - .send() - .await - .and_then(|response| response.error_for_status()); - match result { - Ok(response) => { - let content_length = response.content_length().unwrap_or(0) as f64; - // should read all the response body to get the correct speed - match response.bytes().await { - Ok(_) => { - let elapsed = start.elapsed().as_secs_f64(); - let speed = content_length / elapsed; - Ok((mirror, speed)) - } - Err(e) => { - tracing::warn!("test mirror {} failed: {}", mirror, e); - Ok((mirror, 0.0)) +#[async_trait::async_trait] +impl ReqwestSpeedTestExt for reqwest::Client { + async fn mirror_speed_test<'a>( + &self, + mirrors: &'a [&'a str], + path: &'a str, + ) -> Result> { + let results = futures::future::join_all(mirrors.iter().map(|&mirror| { + let client = self; + async move { + let start = tokio::time::Instant::now(); + // if mirror is github.com, we should use it directly + let url = parse_gh_url(mirror, path)?; + tracing::debug!("Testing {}", url.as_str()); + let _ = + tokio::time::timeout(Duration::from_secs(3), client.get(url.as_str()).send()) + .await; // warm up + let result: Result = + tokio::time::timeout(Duration::from_secs(3), client.get(url).send()) + .await + .map_err(anyhow::Error::msg) + .and_then(|v| v.map_err(anyhow::Error::msg)) + .and_then(|v| v.error_for_status().map_err(anyhow::Error::msg)); + match result { + Ok(response) => { + let content_length = response.content_length().unwrap_or(0) as f64; + // should read all the response body to get the correct speed + match response.bytes().await { + Ok(_) => { + let elapsed = start.elapsed().as_secs_f64(); + let speed = content_length / elapsed; + Ok((mirror, speed)) + } + Err(e) => { + tracing::warn!("test mirror {} failed: {}", mirror, e); + Ok((mirror, 0.0)) + } } } - } - Err(e) => { - tracing::warn!("test mirror {} failed: {}", mirror, e); - Ok((mirror, 0.0)) + Err(e) => { + tracing::warn!("test mirror {} failed: {}", mirror, e); + Ok((mirror, 0.0)) + } } } - } - })) - .await; - let collected_result: Result, anyhow::Error> = results.into_iter().collect(); - let mut results = collected_result?; - results.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); + })) + .await; + let collected_result: Result, anyhow::Error> = results.into_iter().collect(); + let mut results = collected_result?; + results.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); - Ok(results) + Ok(results) + } } mod test { @@ -119,12 +128,16 @@ mod test { #[tokio::test] async fn test_mirror_speed_test() { - let results = mirror_speed_test( - INTERNAL_MIRRORS, - "https://raw.githubusercontent.com/simonw/github-large-file-test/master/1.5mb.txt", - ) - .await - .unwrap(); + let client = reqwest::Client::builder().user_agent( + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" + ).build().unwrap(); + let results = client + .mirror_speed_test( + INTERNAL_MIRRORS, + "https://raw.githubusercontent.com/simonw/github-large-file-test/master/1.5mb.txt", + ) + .await + .unwrap(); println!("{:?}", results); assert_eq!(results.len(), 5); } diff --git a/clash-nyanpasu/backend/tauri/src/utils/downloader.rs b/clash-nyanpasu/backend/tauri/src/utils/downloader.rs index 3511769386..d2f6c95f43 100644 --- a/clash-nyanpasu/backend/tauri/src/utils/downloader.rs +++ b/clash-nyanpasu/backend/tauri/src/utils/downloader.rs @@ -149,6 +149,7 @@ pub struct DownloadStatus { } #[derive(Debug, Serialize)] +#[allow(private_interfaces)] pub struct ChunkStatus { pub state: ChunkThreadState, pub start: usize, @@ -425,7 +426,7 @@ impl Downloader { Ok(()) } - async fn start(&self) -> Result<(), DownloaderError> { + pub async fn start(&self) -> Result<(), DownloaderError> { let result = self.download().await; match result { Ok(_) => Ok(()), diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/providers.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/providers.tsx index f69298d8af..2c4d3f7eb4 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/providers.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/providers.tsx @@ -29,7 +29,14 @@ export default function ProvidersPage() { {Object.entries(getProxiesProviders.data).map( ([name, provider]) => ( - + ), @@ -49,7 +56,7 @@ export default function ProvidersPage() { {getRulesProviders.data && ( {Object.entries(getRulesProviders.data).map(([name, provider]) => ( - + ))} diff --git a/clash-nyanpasu/frontend/ui/materialYou/components/basePage/index.tsx b/clash-nyanpasu/frontend/ui/materialYou/components/basePage/index.tsx index f9f3da00d9..6488bc08c8 100644 --- a/clash-nyanpasu/frontend/ui/materialYou/components/basePage/index.tsx +++ b/clash-nyanpasu/frontend/ui/materialYou/components/basePage/index.tsx @@ -54,14 +54,9 @@ export const BasePage: FC = ({
-
-
- {children} -
-
+
+
{children}
+
diff --git a/clash-nyanpasu/frontend/ui/materialYou/components/basePage/style.scss b/clash-nyanpasu/frontend/ui/materialYou/components/basePage/style.scss index b5d0e8fa1a..ef1130c268 100644 --- a/clash-nyanpasu/frontend/ui/materialYou/components/basePage/style.scss +++ b/clash-nyanpasu/frontend/ui/materialYou/components/basePage/style.scss @@ -16,31 +16,28 @@ } .MDYBasePage-container { + position: relative; + box-sizing: border-box; + flex: 1 1 100%; + width: 100%; height: 100%; - overflow: hidden; + overflow: auto; + background-color: var(--background-color); border-radius: var(--border-radius); + scrollbar-gutter: stable; - > section { - position: relative; - box-sizing: border-box; - flex: 1 1 100%; - width: 100%; - height: 100%; - overflow: auto; - background-color: var(--background-color); - scrollbar-gutter: stable; - - .MDYBasePage-content { + .MDYBasePage-content { + > section { padding: 28px; margin: 0 auto; } } &.no-padding { - > section { + .MDYBasePage-content { overflow: visible; - .MDYBasePage-content { + > section { padding: 0; } } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index 57dc9eb2d8..7ee461e859 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -87,7 +87,7 @@ "eslint-plugin-import": "2.29.1", "eslint-plugin-n": "16.6.2", "eslint-plugin-prettier": "5.1.3", - "eslint-plugin-promise": "6.2.0", + "eslint-plugin-promise": "6.4.0", "eslint-plugin-react": "7.34.3", "lint-staged": "15.2.7", "npm-run-all2": "6.2.0", diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index eab1ae2878..cdc149864b 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -60,7 +60,7 @@ importers: version: 9.1.0(eslint@8.57.0) eslint-config-standard: specifier: 17.1.0 - version: 17.1.0(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.2.0(eslint@8.57.0))(eslint@8.57.0) + version: 17.1.0(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.4.0(eslint@8.57.0))(eslint@8.57.0) eslint-import-resolver-alias: specifier: 1.1.2 version: 1.1.2(eslint-plugin-import@2.29.1(eslint@8.57.0)) @@ -77,8 +77,8 @@ importers: specifier: 5.1.3 version: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.2) eslint-plugin-promise: - specifier: 6.2.0 - version: 6.2.0(eslint@8.57.0) + specifier: 6.4.0 + version: 6.4.0(eslint@8.57.0) eslint-plugin-react: specifier: 7.34.3 version: 7.34.3(eslint@8.57.0) @@ -3201,8 +3201,8 @@ packages: eslint-config-prettier: optional: true - eslint-plugin-promise@6.2.0: - resolution: {integrity: sha512-QmAqwizauvnKOlifxyDj2ObfULpHQawlg/zQdgEixur9vl0CvZGv/LCJV2rtj3210QCoeGBzVMfMXqGAOr/4fA==} + eslint-plugin-promise@6.4.0: + resolution: {integrity: sha512-/KWWRaD3fGkVCZsdR0RU53PSthFmoHVhZl+y9+6DqeDLSikLdlUVpVEAmI6iCRR5QyOjBYBqHZV/bdv4DJ4Gtw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -8687,12 +8687,12 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.2.0(eslint@8.57.0))(eslint@8.57.0): + eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.4.0(eslint@8.57.0))(eslint@8.57.0): dependencies: eslint: 8.57.0 eslint-plugin-import: 2.29.1(eslint@8.57.0) eslint-plugin-n: 16.6.2(eslint@8.57.0) - eslint-plugin-promise: 6.2.0(eslint@8.57.0) + eslint-plugin-promise: 6.4.0(eslint@8.57.0) eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(eslint@8.57.0)): dependencies: @@ -8775,7 +8775,7 @@ snapshots: optionalDependencies: eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-plugin-promise@6.2.0(eslint@8.57.0): + eslint-plugin-promise@6.4.0(eslint@8.57.0): dependencies: eslint: 8.57.0 diff --git a/clash-verge-rev/.github/workflows/alpha.yml b/clash-verge-rev/.github/workflows/alpha.yml index b799e0e467..8cc9050ddd 100644 --- a/clash-verge-rev/.github/workflows/alpha.yml +++ b/clash-verge-rev/.github/workflows/alpha.yml @@ -171,9 +171,15 @@ jobs: uses: Swatinem/rust-cache@v2 with: workspaces: src-tauri + cache-all-crates: true + cache-on-failure: true - name: Install Tauri CLI - run: cargo install --git https://github.com/tauri-apps/tauri --branch 1.x tauri-cli + uses: baptiste0928/cargo-install@v3 + with: + crate: tauri-cli + git: https://github.com/tauri-apps/tauri + branch: 1.x # `branch` and `commit` are also supported - name: Install Node uses: actions/setup-node@v4 diff --git a/clash-verge-rev/.github/workflows/release.yml b/clash-verge-rev/.github/workflows/release.yml index 8f9ac8e0f7..619b17b359 100644 --- a/clash-verge-rev/.github/workflows/release.yml +++ b/clash-verge-rev/.github/workflows/release.yml @@ -161,7 +161,11 @@ jobs: workspaces: src-tauri - name: Install Tauri CLI - run: cargo install --git https://github.com/tauri-apps/tauri --branch 1.x tauri-cli + uses: baptiste0928/cargo-install@v3 + with: + crate: tauri-cli + git: https://github.com/tauri-apps/tauri + branch: 1.x # `branch` and `commit` are also supported - name: Install Node uses: actions/setup-node@v4 diff --git a/clash-verge-rev/src-tauri/src/config/config.rs b/clash-verge-rev/src-tauri/src/config/config.rs index 8664596419..bc074b2c38 100644 --- a/clash-verge-rev/src-tauri/src/config/config.rs +++ b/clash-verge-rev/src-tauri/src/config/config.rs @@ -1,5 +1,6 @@ use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge}; use crate::{ + config::PrfItem, enhance, utils::{dirs, help}, }; @@ -47,6 +48,22 @@ impl Config { /// 初始化订阅 pub async fn init_config() -> Result<()> { + if Self::profiles() + .data() + .get_item(&"Merge".to_string()) + .is_err() + { + let merge_item = PrfItem::from_merge(Some("Merge".to_string()))?; + Self::profiles().data().append_item(merge_item.clone())?; + } + if Self::profiles() + .data() + .get_item(&"Script".to_string()) + .is_err() + { + let script_item = PrfItem::from_script(Some("Script".to_string()))?; + Self::profiles().data().append_item(script_item.clone())?; + } crate::log_err!(Self::generate().await); if let Err(err) = Self::generate_file(ConfigType::Run) { log::error!(target: "app", "{err}"); diff --git a/clash-verge-rev/src-tauri/src/config/prfitem.rs b/clash-verge-rev/src-tauri/src/config/prfitem.rs index 32d846f77f..b5cfcf84b3 100644 --- a/clash-verge-rev/src-tauri/src/config/prfitem.rs +++ b/clash-verge-rev/src-tauri/src/config/prfitem.rs @@ -175,12 +175,12 @@ impl PrfItem { let mut groups = opt_ref.and_then(|o| o.groups.clone()); if merge.is_none() { - let merge_item = PrfItem::from_merge()?; + let merge_item = PrfItem::from_merge(None)?; Config::profiles().data().append_item(merge_item.clone())?; merge = merge_item.uid; } if script.is_none() { - let script_item = PrfItem::from_script()?; + let script_item = PrfItem::from_script(None)?; Config::profiles().data().append_item(script_item.clone())?; script = script_item.uid; } @@ -248,12 +248,12 @@ impl PrfItem { let mut builder = reqwest::ClientBuilder::new().use_rustls_tls().no_proxy(); if merge.is_none() { - let merge_item = PrfItem::from_merge()?; + let merge_item = PrfItem::from_merge(None)?; Config::profiles().data().append_item(merge_item.clone())?; merge = merge_item.uid; } if script.is_none() { - let script_item = PrfItem::from_script()?; + let script_item = PrfItem::from_script(None)?; Config::profiles().data().append_item(script_item.clone())?; script = script_item.uid; } @@ -426,12 +426,15 @@ impl PrfItem { /// ## Merge type (enhance) /// create the enhanced item by using `merge` rule - pub fn from_merge() -> Result { - let uid = help::get_uid("m"); - let file = format!("{uid}.yaml"); + pub fn from_merge(uid: Option) -> Result { + let mut id = help::get_uid("m"); + if let Some(uid) = uid { + id = uid; + } + let file = format!("{id}.yaml"); Ok(PrfItem { - uid: Some(uid), + uid: Some(id), itype: Some("merge".into()), name: None, desc: None, @@ -448,12 +451,15 @@ impl PrfItem { /// ## Script type (enhance) /// create the enhanced item by using javascript quick.js - pub fn from_script() -> Result { - let uid = help::get_uid("s"); - let file = format!("{uid}.js"); // js ext + pub fn from_script(uid: Option) -> Result { + let mut id = help::get_uid("s"); + if let Some(uid) = uid { + id = uid; + } + let file = format!("{id}.js"); // js ext Ok(PrfItem { - uid: Some(uid), + uid: Some(id), itype: Some("script".into()), name: None, desc: None, diff --git a/clash-verge-rev/src-tauri/src/config/verge.rs b/clash-verge-rev/src-tauri/src/config/verge.rs index be454c5de4..a7f8827c8e 100644 --- a/clash-verge-rev/src-tauri/src/config/verge.rs +++ b/clash-verge-rev/src-tauri/src/config/verge.rs @@ -75,6 +75,9 @@ pub struct IVerge { /// enable proxy guard pub enable_proxy_guard: Option, + /// always use default bypass + pub use_default_bypass: Option, + /// set system proxy bypass pub system_proxy_bypass: Option, @@ -235,6 +238,7 @@ impl IVerge { verge_port: Some(7899), verge_http_enabled: Some(true), enable_proxy_guard: Some(false), + use_default_bypass: Some(true), proxy_guard_duration: Some(30), auto_close_connection: Some(true), auto_check_update: Some(true), @@ -297,6 +301,7 @@ impl IVerge { patch!(verge_http_enabled); patch!(enable_system_proxy); patch!(enable_proxy_guard); + patch!(use_default_bypass); patch!(system_proxy_bypass); patch!(proxy_guard_duration); patch!(proxy_auto_config); diff --git a/clash-verge-rev/src-tauri/src/core/sysopt.rs b/clash-verge-rev/src-tauri/src/core/sysopt.rs index a5a6a80608..35ed33a81c 100644 --- a/clash-verge-rev/src-tauri/src/core/sysopt.rs +++ b/clash-verge-rev/src-tauri/src/core/sysopt.rs @@ -42,8 +42,8 @@ static DEFAULT_BYPASS: &str = "127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,localhost,*.local,*.crashlytics.com,"; fn get_bypass() -> String { - let bypass = DEFAULT_BYPASS.to_string(); - + // let bypass = DEFAULT_BYPASS.to_string(); + let use_default = Config::verge().latest().use_default_bypass.unwrap_or(true); let res = { let verge = Config::verge(); let verge = verge.latest(); @@ -55,15 +55,23 @@ fn get_bypass() -> String { }; #[cfg(target_os = "windows")] let bypass = if custom_bypass.is_empty() { - bypass + DEFAULT_BYPASS.to_string() } else { - format!("{};{}", bypass, custom_bypass) + if use_default { + format!("{};{}", DEFAULT_BYPASS, custom_bypass) + } else { + custom_bypass + } }; #[cfg(not(target_os = "windows"))] let bypass = if custom_bypass.is_empty() { - bypass + DEFAULT_BYPASS.to_string() } else { - format!("{},{}", bypass, custom_bypass) + if use_default { + format!("{},{}", DEFAULT_BYPASS, custom_bypass) + } else { + custom_bypass + } }; bypass diff --git a/clash-verge-rev/src-tauri/src/enhance/mod.rs b/clash-verge-rev/src-tauri/src/enhance/mod.rs index 9af9ebddc2..0ea77f5d2e 100644 --- a/clash-verge-rev/src-tauri/src/enhance/mod.rs +++ b/clash-verge-rev/src-tauri/src/enhance/mod.rs @@ -50,7 +50,16 @@ pub async fn enhance() -> (Mapping, Vec, HashMap) { }; // 从profiles里拿东西 - let (mut config, merge_item, script_item, rules_item, proxies_item, groups_item) = { + let ( + mut config, + merge_item, + script_item, + rules_item, + proxies_item, + groups_item, + global_merge, + global_script, + ) = { let profiles = Config::profiles(); let profiles = profiles.latest(); @@ -96,7 +105,34 @@ pub async fn enhance() -> (Mapping, Vec, HashMap) { data: ChainType::Groups(SeqMap::default()), }); - (current, merge, script, rules, proxies, groups) + let global_merge = profiles + .get_item(&"Merge".to_string()) + .ok() + .and_then(>::from) + .unwrap_or_else(|| ChainItem { + uid: "Merge".into(), + data: ChainType::Merge(Mapping::new()), + }); + + let global_script = profiles + .get_item(&"Script".to_string()) + .ok() + .and_then(>::from) + .unwrap_or_else(|| ChainItem { + uid: "Script".into(), + data: ChainType::Script(tmpl::ITEM_SCRIPT.into()), + }); + + ( + current, + merge, + script, + rules, + proxies, + groups, + global_merge, + global_script, + ) }; let mut result_map = HashMap::new(); // 保存脚本日志 @@ -136,6 +172,27 @@ pub async fn enhance() -> (Mapping, Vec, HashMap) { result_map.insert(script_item.uid, logs); } + // 全局Merge和Script + if let ChainType::Merge(merge) = global_merge.data { + exists_keys.extend(use_keys(&merge)); + config = use_merge(merge, config.to_owned()); + } + + if let ChainType::Script(script) = global_script.data { + let mut logs = vec![]; + + match use_script(script, config.to_owned()) { + Ok((res_config, res_logs)) => { + exists_keys.extend(use_keys(&res_config)); + config = res_config; + logs.extend(res_logs); + } + Err(err) => logs.push(("exception".into(), err.to_string())), + } + + result_map.insert(global_script.uid, logs); + } + // 合并默认的config for (key, value) in clash_config.into_iter() { if key.as_str() == Some("tun") { diff --git a/clash-verge-rev/src/components/profile/profile-item.tsx b/clash-verge-rev/src/components/profile/profile-item.tsx index 38868e5924..7feaab2e86 100644 --- a/clash-verge-rev/src/components/profile/profile-item.tsx +++ b/clash-verge-rev/src/components/profile/profile-item.tsx @@ -226,12 +226,12 @@ export const ProfileItem = (props: Props) => { disabled: option?.groups === null, }, { - label: "Edit Merge", + label: "Extend Config", handler: onEditMerge, disabled: option?.merge === null, }, { - label: "Edit Script", + label: "Extend Script", handler: onEditScript, disabled: option?.script === null, }, @@ -267,12 +267,12 @@ export const ProfileItem = (props: Props) => { disabled: option?.groups === null, }, { - label: "Edit Merge", + label: "Extend Config", handler: onEditMerge, disabled: option?.merge === null, }, { - label: "Edit Script", + label: "Extend Script", handler: onEditScript, disabled: option?.script === null, }, diff --git a/clash-verge-rev/src/components/profile/profile-more.tsx b/clash-verge-rev/src/components/profile/profile-more.tsx new file mode 100644 index 0000000000..25e543ed7d --- /dev/null +++ b/clash-verge-rev/src/components/profile/profile-more.tsx @@ -0,0 +1,188 @@ +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useLockFn } from "ahooks"; +import { + Box, + Badge, + Chip, + Typography, + MenuItem, + Menu, + IconButton, +} from "@mui/material"; +import { FeaturedPlayListRounded } from "@mui/icons-material"; +import { viewProfile } from "@/services/cmds"; +import { Notice } from "@/components/base"; +import { EditorViewer } from "@/components/profile/editor-viewer"; +import { ProfileBox } from "./profile-box"; +import { LogViewer } from "./log-viewer"; + +interface Props { + logInfo?: [string, string][]; + id: "Merge" | "Script"; + onChange?: (prev?: string, curr?: string) => void; +} + +// profile enhanced item +export const ProfileMore = (props: Props) => { + const { id, logInfo = [], onChange } = props; + + const { t, i18n } = useTranslation(); + const [anchorEl, setAnchorEl] = useState(null); + const [position, setPosition] = useState({ left: 0, top: 0 }); + const [fileOpen, setFileOpen] = useState(false); + const [logOpen, setLogOpen] = useState(false); + + const onEditFile = () => { + setAnchorEl(null); + setFileOpen(true); + }; + + const onOpenFile = useLockFn(async () => { + setAnchorEl(null); + try { + await viewProfile(id); + } catch (err: any) { + Notice.error(err?.message || err.toString()); + } + }); + + const fnWrapper = (fn: () => void) => () => { + setAnchorEl(null); + return fn(); + }; + + const hasError = !!logInfo.find((e) => e[0] === "exception"); + + const itemMenu = [ + { label: "Edit File", handler: onEditFile }, + { label: "Open File", handler: onOpenFile }, + ]; + + const boxStyle = { + height: 26, + display: "flex", + alignItems: "center", + justifyContent: "space-between", + lineHeight: 1, + }; + + return ( + <> + { + const { clientX, clientY } = event; + setPosition({ top: clientY, left: clientX }); + setAnchorEl(event.currentTarget); + event.preventDefault(); + }} + > + + + {t(`Global ${id}`)} + + + + + + + {id === "Script" && + (hasError ? ( + + setLogOpen(true)} + > + + + + ) : ( + setLogOpen(true)} + > + + + ))} + + + + setAnchorEl(null)} + anchorPosition={position} + anchorReference="anchorPosition" + transitionDuration={225} + MenuListProps={{ sx: { py: 0.5 } }} + onContextMenu={(e) => { + setAnchorEl(null); + e.preventDefault(); + }} + > + {itemMenu + .filter((item: any) => item.show !== false) + .map((item) => ( + { + return { + color: + item.label === "Delete" + ? theme.palette.error.main + : undefined, + }; + }, + ]} + dense + > + {t(item.label)} + + ))} + + + setFileOpen(false)} + /> + + setLogOpen(false)} + /> + + ); +}; diff --git a/clash-verge-rev/src/components/setting/mods/sysproxy-viewer.tsx b/clash-verge-rev/src/components/setting/mods/sysproxy-viewer.tsx index d5da90fb3a..8981477b1b 100644 --- a/clash-verge-rev/src/components/setting/mods/sysproxy-viewer.tsx +++ b/clash-verge-rev/src/components/setting/mods/sysproxy-viewer.tsx @@ -49,6 +49,7 @@ export const SysproxyViewer = forwardRef((props, ref) => { proxy_auto_config, pac_file_content, enable_proxy_guard, + use_default_bypass, system_proxy_bypass, proxy_guard_duration, } = verge ?? {}; @@ -57,6 +58,7 @@ export const SysproxyViewer = forwardRef((props, ref) => { guard: enable_proxy_guard, bypass: system_proxy_bypass, duration: proxy_guard_duration ?? 10, + use_default: use_default_bypass ?? true, pac: proxy_auto_config, pac_content: pac_file_content ?? DEFAULT_PAC, }); @@ -68,6 +70,7 @@ export const SysproxyViewer = forwardRef((props, ref) => { guard: enable_proxy_guard, bypass: system_proxy_bypass, duration: proxy_guard_duration ?? 10, + use_default: use_default_bypass ?? true, pac: proxy_auto_config, pac_content: pac_file_content ?? DEFAULT_PAC, }); @@ -97,6 +100,9 @@ export const SysproxyViewer = forwardRef((props, ref) => { if (value.pac !== proxy_auto_config) { patch.proxy_auto_config = value.pac; } + if (value.use_default !== use_default_bypass) { + patch.use_default_bypass = value.use_default; + } if (value.pac_content !== pac_file_content) { patch.pac_file_content = value.pac_content; } @@ -197,6 +203,17 @@ export const SysproxyViewer = forwardRef((props, ref) => { }} /> + {!value.pac && ( + + + setValue((v) => ({ ...v, use_default: e }))} + /> + + )} {!value.pac && ( <> diff --git a/clash-verge-rev/src/locales/en.json b/clash-verge-rev/src/locales/en.json index 38d8b8386d..1d5094e442 100644 --- a/clash-verge-rev/src/locales/en.json +++ b/clash-verge-rev/src/locales/en.json @@ -60,8 +60,10 @@ "Add Append Rule": "Add Append Rule", "Delete Rule": "Delete Rule", "Edit Groups": "Edit Proxy Groups", - "Edit Merge": "Edit Merge", - "Edit Script": "Edit Script", + "Extend Config": "Extend Config", + "Extend Script": "Extend Script", + "Global Merge": "Global Extend Config", + "Global Script": "Global Extend Script", "Type": "Type", "Name": "Name", "Descriptions": "Descriptions", @@ -151,6 +153,7 @@ "Proxy Guard": "Proxy Guard", "Proxy Guard Info": "Enable to prevent other software from modifying the operating system's proxy settings", "Guard Duration": "Guard Duration", + "Always use Default Bypass": "Always use Default Bypass", "Proxy Bypass": "Proxy Bypass Settings: ", "Bypass": "Bypass: ", "Use PAC Mode": "Use PAC Mode", diff --git a/clash-verge-rev/src/locales/fa.json b/clash-verge-rev/src/locales/fa.json index c9bea1f911..3f85e28bcd 100644 --- a/clash-verge-rev/src/locales/fa.json +++ b/clash-verge-rev/src/locales/fa.json @@ -50,8 +50,10 @@ "Expire Time": "زمان انقضا", "Create Profile": "ایجاد پروفایل", "Edit Profile": "ویرایش پروفایل", - "Edit Merge": "ادغام ویرایش", - "Edit Script": "ویرایش اسکریپت", + "Extend Config": "توسعه پیکربندی", + "Extend Script": "ادغام اسکریپت", + "Global Merge": "تنظیمات گسترده‌ی سراسری", + "Global Script": "اسکریپت گسترش سراسری", "Type": "نوع", "Name": "نام", "Descriptions": "توضیحات", @@ -141,6 +143,7 @@ "Proxy Guard": "محافظ پراکسی", "Proxy Guard Info": "امکان جلوگیری از نرم‌افزارهای دیگر از تغییر تنظیمات پروکسی سیستم عامل را فعال کنید", "Guard Duration": "مدت محافظت", + "Always use Default Bypass": "همیشه از دور زدن پیش‌فرض استفاده کنید", "Proxy Bypass": "دور زدن پراکسی: ", "Bypass": "دور زدن: ", "Use PAC Mode": "استفاده از حالت PAC", diff --git a/clash-verge-rev/src/locales/ru.json b/clash-verge-rev/src/locales/ru.json index dee452cd5b..95a604210e 100644 --- a/clash-verge-rev/src/locales/ru.json +++ b/clash-verge-rev/src/locales/ru.json @@ -50,8 +50,10 @@ "Expire Time": "Время окончания", "Create Profile": "Создать профиль", "Edit Profile": "Изменить профиль", - "Edit Merge": "Изменить Merge.", - "Edit Script": "Изменить Script", + "Extend Config": "Изменить Merge.", + "Extend Script": "Изменить Script", + "Global Merge": "Глобальный расширенный Настройки", + "Global Script": "Глобальный расширенный скрипт", "Type": "Тип", "Name": "Название", "Descriptions": "Описания", @@ -141,6 +143,7 @@ "Proxy Guard": "Защита прокси", "Proxy Guard Info": "Включите эту функцию чтобы предотвратить изменение настроек прокси-сервера операционной системы другим программным обеспечением", "Guard Duration": "Период защиты", + "Always use Default Bypass": "Всегда использовать стандартное обходное решение", "Proxy Bypass": "Игнорирование прокси: ", "Bypass": "Игнорирование: ", "Use PAC Mode": "Используйте режим PAC", diff --git a/clash-verge-rev/src/locales/zh.json b/clash-verge-rev/src/locales/zh.json index 24042d76a9..ddd9b3c40e 100644 --- a/clash-verge-rev/src/locales/zh.json +++ b/clash-verge-rev/src/locales/zh.json @@ -50,8 +50,8 @@ "Expire Time": "到期时间", "Create Profile": "新建配置", "Edit Profile": "编辑配置", - "Edit Proxies": "添加/删除 节点", - "Edit Rules": "添加/删除 规则", + "Edit Proxies": "编辑节点", + "Edit Rules": "编辑规则", "Rule Type": "规则类型", "Rule Content": "规则内容", "Proxy Policy": "代理策略", @@ -59,9 +59,11 @@ "Add Prepend Rule": "添加前置规则", "Add Append Rule": "添加后置规则", "Delete Rule": "删除规则", - "Edit Groups": "添加/删除 代理组", - "Edit Merge": "微调配置 (yaml)", - "Edit Script": "微调配置 (js)", + "Edit Groups": "编辑代理组", + "Extend Config": "扩展配置", + "Extend Script": "扩展脚本", + "Global Merge": "全局扩展配置", + "Global Script": "全局扩展脚本", "Type": "类型", "Name": "名称", "Descriptions": "描述", @@ -151,6 +153,7 @@ "Proxy Guard": "系统代理守卫", "Proxy Guard Info": "开启以防止其他软件修改操作系统的代理设置", "Guard Duration": "代理守卫间隔", + "Always use Default Bypass": "始终使用默认绕过", "Proxy Bypass": "代理绕过设置:", "Bypass": "当前绕过:", "Use PAC Mode": "使用PAC模式", diff --git a/clash-verge-rev/src/pages/profiles.tsx b/clash-verge-rev/src/pages/profiles.tsx index 9c641e6404..dedfbee9b4 100644 --- a/clash-verge-rev/src/pages/profiles.tsx +++ b/clash-verge-rev/src/pages/profiles.tsx @@ -41,6 +41,7 @@ import { ProfileViewer, ProfileViewerRef, } from "@/components/profile/profile-viewer"; +import { ProfileMore } from "@/components/profile/profile-more"; import { ProfileItem } from "@/components/profile/profile-item"; import { useProfiles } from "@/hooks/use-profiles"; import { ConfigViewer } from "@/components/setting/mods/config-viewer"; @@ -49,6 +50,7 @@ import { BaseStyledTextField } from "@/components/base/base-styled-text-field"; import { listen } from "@tauri-apps/api/event"; import { readTextFile } from "@tauri-apps/api/fs"; import { readText } from "@tauri-apps/api/clipboard"; +import { EditorViewer } from "@/components/profile/editor-viewer"; const ProfilePage = () => { const { t } = useTranslation(); @@ -244,6 +246,12 @@ const ProfilePage = () => { if (text) setUrl(text); }; + const mode = useThemeMode(); + const islight = mode === "light" ? true : false; + const dividercolor = islight + ? "rgba(0, 0, 0, 0.06)" + : "rgba(255, 255, 255, 0.06)"; + return ( { + + + + + { + if (prev !== curr) { + await onEnhance(); + } + }} + /> + + + { + if (prev !== curr) { + await onEnhance(); + } + }} + /> + + + + mutateProfiles()} /> diff --git a/clash-verge-rev/src/services/types.d.ts b/clash-verge-rev/src/services/types.d.ts index b5fe361519..35a3f3c5cf 100644 --- a/clash-verge-rev/src/services/types.d.ts +++ b/clash-verge-rev/src/services/types.d.ts @@ -239,6 +239,7 @@ interface IVergeConfig { verge_socks_enabled?: boolean; verge_http_enabled?: boolean; enable_proxy_guard?: boolean; + use_default_bypass?: boolean; proxy_guard_duration?: number; system_proxy_bypass?: string; web_ui_list?: string[]; diff --git a/hysteria/app/cmd/server.go b/hysteria/app/cmd/server.go index d2c9f4cf73..b45fb15135 100644 --- a/hysteria/app/cmd/server.go +++ b/hysteria/app/cmd/server.go @@ -34,7 +34,9 @@ import ( "github.com/apernet/hysteria/extras/v2/masq" "github.com/apernet/hysteria/extras/v2/obfs" "github.com/apernet/hysteria/extras/v2/outbounds" + "github.com/apernet/hysteria/extras/v2/sniff" "github.com/apernet/hysteria/extras/v2/trafficlogger" + eUtils "github.com/apernet/hysteria/extras/v2/utils" ) const ( @@ -64,6 +66,7 @@ type serverConfig struct { UDPIdleTimeout time.Duration `mapstructure:"udpIdleTimeout"` Auth serverConfigAuth `mapstructure:"auth"` Resolver serverConfigResolver `mapstructure:"resolver"` + Sniff serverConfigSniff `mapstructure:"sniff"` ACL serverConfigACL `mapstructure:"acl"` Outbounds []serverConfigOutboundEntry `mapstructure:"outbounds"` TrafficStats serverConfigTrafficStats `mapstructure:"trafficStats"` @@ -179,6 +182,14 @@ type serverConfigResolver struct { HTTPS serverConfigResolverHTTPS `mapstructure:"https"` } +type serverConfigSniff struct { + Enable bool `mapstructure:"enable"` + Timeout time.Duration `mapstructure:"timeout"` + RewriteDomain bool `mapstructure:"rewriteDomain"` + TCPPorts string `mapstructure:"tcpPorts"` + UDPPorts string `mapstructure:"udpPorts"` +} + type serverConfigACL struct { File string `mapstructure:"file"` Inline []string `mapstructure:"inline"` @@ -541,6 +552,29 @@ func serverConfigOutboundHTTPToOutbound(c serverConfigOutboundHTTP) (outbounds.P return outbounds.NewHTTPOutbound(c.URL, c.Insecure) } +func (c *serverConfig) fillRequestHook(hyConfig *server.Config) error { + if c.Sniff.Enable { + s := &sniff.Sniffer{ + Timeout: c.Sniff.Timeout, + RewriteDomain: c.Sniff.RewriteDomain, + } + if c.Sniff.TCPPorts != "" { + s.TCPPorts = eUtils.ParsePortUnion(c.Sniff.TCPPorts) + if s.TCPPorts == nil { + return configError{Field: "sniff.tcpPorts", Err: errors.New("invalid port union")} + } + } + if c.Sniff.UDPPorts != "" { + s.UDPPorts = eUtils.ParsePortUnion(c.Sniff.UDPPorts) + if s.UDPPorts == nil { + return configError{Field: "sniff.udpPorts", Err: errors.New("invalid port union")} + } + } + hyConfig.RequestHook = s + } + return nil +} + func (c *serverConfig) fillOutboundConfig(hyConfig *server.Config) error { // Resolver, ACL, actual outbound are all implemented through the Outbound interface. // Depending on the config, we build a chain like this: @@ -821,6 +855,7 @@ func (c *serverConfig) Config() (*server.Config, error) { c.fillConn, c.fillTLSConfig, c.fillQUICConfig, + c.fillRequestHook, c.fillOutboundConfig, c.fillBandwidthConfig, c.fillIgnoreClientBandwidth, diff --git a/hysteria/app/cmd/server_test.go b/hysteria/app/cmd/server_test.go index d81a61a095..bb2d12a82c 100644 --- a/hysteria/app/cmd/server_test.go +++ b/hysteria/app/cmd/server_test.go @@ -111,6 +111,13 @@ func TestServerConfig(t *testing.T) { Insecure: true, }, }, + Sniff: serverConfigSniff{ + Enable: true, + Timeout: 1 * time.Second, + RewriteDomain: true, + TCPPorts: "80,443,1000-2000", + UDPPorts: "443", + }, ACL: serverConfigACL{ File: "chnroute.txt", Inline: []string{ diff --git a/hysteria/app/cmd/server_test.yaml b/hysteria/app/cmd/server_test.yaml index 86a2dcf2ae..ff0bf52068 100644 --- a/hysteria/app/cmd/server_test.yaml +++ b/hysteria/app/cmd/server_test.yaml @@ -83,6 +83,13 @@ resolver: sni: real.stuff.net insecure: true +sniff: + enable: true + timeout: 1s + rewriteDomain: true + tcpPorts: 80,443,1000-2000 + udpPorts: 443 + acl: file: chnroute.txt inline: diff --git a/hysteria/app/cmd/speedtest.go b/hysteria/app/cmd/speedtest.go index 12d3a83718..f5c37fb81a 100644 --- a/hysteria/app/cmd/speedtest.go +++ b/hysteria/app/cmd/speedtest.go @@ -3,6 +3,9 @@ package cmd import ( "errors" "fmt" + "os" + "os/signal" + "syscall" "time" "github.com/spf13/cobra" @@ -68,11 +71,26 @@ func runSpeedtest(cmd *cobra.Command, args []string) { zap.Bool("udpEnabled", info.UDPEnabled), zap.Uint64("tx", info.Tx)) - if !skipDownload { - runDownloadTest(c) - } - if !skipUpload { - runUploadTest(c) + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM) + defer signal.Stop(signalChan) + + runChan := make(chan struct{}, 1) + go func() { + if !skipDownload { + runDownloadTest(c) + } + if !skipUpload { + runUploadTest(c) + } + runChan <- struct{}{} + }() + + select { + case <-signalChan: + logger.Info("received signal, shutting down gracefully") + case <-runChan: + logger.Info("speed test complete") } } diff --git a/hysteria/app/go.mod b/hysteria/app/go.mod index bfc20b08b9..dfbea428ec 100644 --- a/hysteria/app/go.mod +++ b/hysteria/app/go.mod @@ -23,12 +23,14 @@ require ( github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301 go.uber.org/zap v1.24.0 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 - golang.org/x/sys v0.20.0 + golang.org/x/sys v0.21.0 ) require ( + github.com/andybalholm/brotli v1.1.0 // indirect github.com/apernet/quic-go v0.44.1-0.20240520215222-bb2e53664023 // indirect github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 // indirect + github.com/cloudflare/circl v1.3.9 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -40,6 +42,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.1.1 // indirect github.com/libdns/libdns v0.2.2 // indirect github.com/magiconair/properties v1.8.7 // indirect @@ -51,6 +54,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect + github.com/refraction-networking/utls v1.6.6 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect github.com/spf13/afero v1.9.3 // indirect @@ -66,13 +70,13 @@ require ( go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.23.0 // indirect + golang.org/x/crypto v0.24.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/hysteria/app/go.sum b/hysteria/app/go.sum index 550394f702..e1b80a594d 100644 --- a/hysteria/app/go.sum +++ b/hysteria/app/go.sum @@ -38,6 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f h1:uVh0qpEslrWjgzx9vOcyCqsOY3c9kofDZ1n+qaw35ZY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f/go.mod h1:xkkq9D4ygcldQQhKS/w9CadiCKwCngU7K9E3DaKahpM= github.com/apernet/quic-go v0.44.1-0.20240520215222-bb2e53664023 h1:UTrvVPt+GfeOeli9/3gvpCDz2Jd5UEn3YotfP0u/pok= @@ -55,6 +57,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE= +github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -164,6 +168,8 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0= github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -222,6 +228,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/refraction-networking/utls v1.6.6 h1:igFsYBUJPYM8Rno9xUuDoM5GQrVEqY4llzEXOkL43Ig= +github.com/refraction-networking/utls v1.6.6/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= @@ -306,8 +314,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -455,8 +463,8 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -468,8 +476,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -526,8 +534,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/hysteria/core/go.mod b/hysteria/core/go.mod index 66a89380b4..f35cc548a7 100644 --- a/hysteria/core/go.mod +++ b/hysteria/core/go.mod @@ -22,12 +22,12 @@ require ( github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/stretchr/objx v0.5.2 // indirect go.uber.org/mock v0.4.0 // indirect - golang.org/x/crypto v0.23.0 // indirect + golang.org/x/crypto v0.24.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.25.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/hysteria/core/go.sum b/hysteria/core/go.sum index a8e10c4b4e..1a133cbe60 100644 --- a/hysteria/core/go.sum +++ b/hysteria/core/go.sum @@ -47,8 +47,8 @@ go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= @@ -58,14 +58,14 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/hysteria/extras/go.mod b/hysteria/extras/go.mod index 58304186fd..2d9fae7ec5 100644 --- a/hysteria/extras/go.mod +++ b/hysteria/extras/go.mod @@ -4,21 +4,25 @@ go 1.21 require ( github.com/apernet/hysteria/core/v2 v2.0.0-00010101000000-000000000000 + github.com/apernet/quic-go v0.44.1-0.20240520215222-bb2e53664023 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/hashicorp/golang-lru/v2 v2.0.5 github.com/miekg/dns v1.1.59 + github.com/refraction-networking/utls v1.6.6 github.com/stretchr/testify v1.9.0 github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301 - golang.org/x/crypto v0.23.0 + golang.org/x/crypto v0.24.0 golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 ) require ( - github.com/apernet/quic-go v0.44.1-0.20240520215222-bb2e53664023 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/cloudflare/circl v1.3.9 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/kr/text v0.2.0 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect @@ -30,9 +34,9 @@ require ( golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/hysteria/extras/go.sum b/hysteria/extras/go.sum index 5d931d7793..74dceb5690 100644 --- a/hysteria/extras/go.sum +++ b/hysteria/extras/go.sum @@ -1,3 +1,5 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apernet/quic-go v0.44.1-0.20240520215222-bb2e53664023 h1:UTrvVPt+GfeOeli9/3gvpCDz2Jd5UEn3YotfP0u/pok= github.com/apernet/quic-go v0.44.1-0.20240520215222-bb2e53664023/go.mod h1:UkcG7+34BM+bbH2RFVKtHQp3mR7h8yJHx4z95lZ7sx4= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= @@ -5,6 +7,8 @@ github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE= +github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -22,6 +26,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -39,6 +45,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/refraction-networking/utls v1.6.6 h1:igFsYBUJPYM8Rno9xUuDoM5GQrVEqY4llzEXOkL43Ig= +github.com/refraction-networking/utls v1.6.6/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -58,8 +66,8 @@ go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -84,8 +92,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -93,16 +101,16 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/hysteria/extras/sniff/.mockery.yaml b/hysteria/extras/sniff/.mockery.yaml new file mode 100644 index 0000000000..c866d1da1c --- /dev/null +++ b/hysteria/extras/sniff/.mockery.yaml @@ -0,0 +1,12 @@ +with-expecter: true +dir: . +outpkg: sniff +packages: + github.com/apernet/quic-go: + interfaces: + Stream: + config: + mockname: mockStream + replace-type: # internal package alias dirty fix + - github.com/apernet/quic-go/internal/protocol=github.com/apernet/quic-go + - github.com/apernet/quic-go/internal/qerr=github.com/apernet/quic-go diff --git a/hysteria/extras/sniff/internal/quic/LICENSE b/hysteria/extras/sniff/internal/quic/LICENSE new file mode 100644 index 0000000000..43970c4103 --- /dev/null +++ b/hysteria/extras/sniff/internal/quic/LICENSE @@ -0,0 +1,31 @@ +Author:: Cuong Manh Le +Copyright:: Copyright (c) 2023, Cuong Manh Le +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the @organization@ nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LE MANH CUONG +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/hysteria/extras/sniff/internal/quic/README.md b/hysteria/extras/sniff/internal/quic/README.md new file mode 100644 index 0000000000..8f3a5e2a66 --- /dev/null +++ b/hysteria/extras/sniff/internal/quic/README.md @@ -0,0 +1 @@ +The code here is from https://github.com/cuonglm/quicsni with various modifications. \ No newline at end of file diff --git a/hysteria/extras/sniff/internal/quic/header.go b/hysteria/extras/sniff/internal/quic/header.go new file mode 100644 index 0000000000..c1a5e7c4c8 --- /dev/null +++ b/hysteria/extras/sniff/internal/quic/header.go @@ -0,0 +1,105 @@ +package quic + +import ( + "bytes" + "encoding/binary" + "errors" + "io" + + "github.com/apernet/quic-go/quicvarint" +) + +// The Header represents a QUIC header. +type Header struct { + Type uint8 + Version uint32 + SrcConnectionID []byte + DestConnectionID []byte + Length int64 + Token []byte +} + +// ParseInitialHeader parses the initial packet of a QUIC connection, +// return the initial header and number of bytes read so far. +func ParseInitialHeader(data []byte) (*Header, int64, error) { + br := bytes.NewReader(data) + hdr, err := parseLongHeader(br) + if err != nil { + return nil, 0, err + } + n := int64(len(data) - br.Len()) + return hdr, n, nil +} + +func parseLongHeader(b *bytes.Reader) (*Header, error) { + typeByte, err := b.ReadByte() + if err != nil { + return nil, err + } + h := &Header{} + ver, err := beUint32(b) + if err != nil { + return nil, err + } + h.Version = ver + if h.Version != 0 && typeByte&0x40 == 0 { + return nil, errors.New("not a QUIC packet") + } + destConnIDLen, err := b.ReadByte() + if err != nil { + return nil, err + } + h.DestConnectionID = make([]byte, int(destConnIDLen)) + if err := readConnectionID(b, h.DestConnectionID); err != nil { + return nil, err + } + srcConnIDLen, err := b.ReadByte() + if err != nil { + return nil, err + } + h.SrcConnectionID = make([]byte, int(srcConnIDLen)) + if err := readConnectionID(b, h.SrcConnectionID); err != nil { + return nil, err + } + + initialPacketType := byte(0b00) + if h.Version == V2 { + initialPacketType = 0b01 + } + if (typeByte >> 4 & 0b11) == initialPacketType { + tokenLen, err := quicvarint.Read(b) + if err != nil { + return nil, err + } + if tokenLen > uint64(b.Len()) { + return nil, io.EOF + } + h.Token = make([]byte, tokenLen) + if _, err := io.ReadFull(b, h.Token); err != nil { + return nil, err + } + } + + pl, err := quicvarint.Read(b) + if err != nil { + return nil, err + } + h.Length = int64(pl) + return h, err +} + +func readConnectionID(r io.Reader, cid []byte) error { + _, err := io.ReadFull(r, cid) + if err == io.ErrUnexpectedEOF { + return io.EOF + } + return nil +} + +func beUint32(r io.Reader) (uint32, error) { + b := make([]byte, 4) + if _, err := io.ReadFull(r, b); err != nil { + return 0, err + } + return binary.BigEndian.Uint32(b), nil +} diff --git a/hysteria/extras/sniff/internal/quic/packet_protector.go b/hysteria/extras/sniff/internal/quic/packet_protector.go new file mode 100644 index 0000000000..42de841134 --- /dev/null +++ b/hysteria/extras/sniff/internal/quic/packet_protector.go @@ -0,0 +1,193 @@ +package quic + +import ( + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/sha256" + "crypto/tls" + "encoding/binary" + "errors" + "fmt" + "hash" + + "golang.org/x/crypto/chacha20" + "golang.org/x/crypto/chacha20poly1305" + "golang.org/x/crypto/cryptobyte" + "golang.org/x/crypto/hkdf" +) + +// NewProtectionKey creates a new ProtectionKey. +func NewProtectionKey(suite uint16, secret []byte, v uint32) (*ProtectionKey, error) { + return newProtectionKey(suite, secret, v) +} + +// NewInitialProtectionKey is like NewProtectionKey, but the returned protection key +// is used for encrypt/decrypt Initial Packet only. +// +// See: https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#name-initial-secrets +func NewInitialProtectionKey(secret []byte, v uint32) (*ProtectionKey, error) { + return NewProtectionKey(tls.TLS_AES_128_GCM_SHA256, secret, v) +} + +// NewPacketProtector creates a new PacketProtector. +func NewPacketProtector(key *ProtectionKey) *PacketProtector { + return &PacketProtector{key: key} +} + +// PacketProtector is used for protecting a QUIC packet. +// +// See: https://www.rfc-editor.org/rfc/rfc9001.html#name-packet-protection +type PacketProtector struct { + key *ProtectionKey +} + +// UnProtect decrypts a QUIC packet. +func (pp *PacketProtector) UnProtect(packet []byte, pnOffset, pnMax int64) ([]byte, error) { + if isLongHeader(packet[0]) && int64(len(packet)) < pnOffset+4+16 { + return nil, errors.New("packet with long header is too small") + } + + // https://www.rfc-editor.org/rfc/rfc9001.html#name-header-protection-sample + sampleOffset := pnOffset + 4 + sample := packet[sampleOffset : sampleOffset+16] + + // https://www.rfc-editor.org/rfc/rfc9001.html#name-header-protection-applicati + mask := pp.key.headerProtection(sample) + if isLongHeader(packet[0]) { + // Long header: 4 bits masked + packet[0] ^= mask[0] & 0x0f + } else { + // Short header: 5 bits masked + packet[0] ^= mask[0] & 0x1f + } + + pnLen := packet[0]&0x3 + 1 + pn := int64(0) + for i := uint8(0); i < pnLen; i++ { + packet[pnOffset:][i] ^= mask[1+i] + pn = (pn << 8) | int64(packet[pnOffset:][i]) + } + pn = decodePacketNumber(pnMax, pn, pnLen) + hdr := packet[:pnOffset+int64(pnLen)] + payload := packet[pnOffset:][pnLen:] + dec, err := pp.key.aead.Open(payload[:0], pp.key.nonce(pn), payload, hdr) + if err != nil { + return nil, fmt.Errorf("decryption failed: %w", err) + } + return dec, nil +} + +// ProtectionKey is the key used to protect a QUIC packet. +type ProtectionKey struct { + aead cipher.AEAD + headerProtection func(sample []byte) (mask []byte) + iv []byte +} + +// https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#name-aead-usage +// +// "The 62 bits of the reconstructed QUIC packet number in network byte order are +// left-padded with zeros to the size of the IV. The exclusive OR of the padded +// packet number and the IV forms the AEAD nonce." +func (pk *ProtectionKey) nonce(pn int64) []byte { + nonce := make([]byte, len(pk.iv)) + binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(pn)) + for i := range pk.iv { + nonce[i] ^= pk.iv[i] + } + return nonce +} + +func newProtectionKey(suite uint16, secret []byte, v uint32) (*ProtectionKey, error) { + switch suite { + case tls.TLS_AES_128_GCM_SHA256: + key := hkdfExpandLabel(crypto.SHA256.New, secret, keyLabel(v), nil, 16) + c, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + aead, err := cipher.NewGCM(c) + if err != nil { + panic(err) + } + iv := hkdfExpandLabel(crypto.SHA256.New, secret, ivLabel(v), nil, aead.NonceSize()) + hpKey := hkdfExpandLabel(crypto.SHA256.New, secret, headerProtectionLabel(v), nil, 16) + hp, err := aes.NewCipher(hpKey) + if err != nil { + panic(err) + } + k := &ProtectionKey{} + k.aead = aead + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#name-aes-based-header-protection + k.headerProtection = func(sample []byte) []byte { + mask := make([]byte, hp.BlockSize()) + hp.Encrypt(mask, sample) + return mask + } + k.iv = iv + return k, nil + case tls.TLS_CHACHA20_POLY1305_SHA256: + key := hkdfExpandLabel(crypto.SHA256.New, secret, keyLabel(v), nil, chacha20poly1305.KeySize) + aead, err := chacha20poly1305.New(key) + if err != nil { + return nil, err + } + iv := hkdfExpandLabel(crypto.SHA256.New, secret, ivLabel(v), nil, aead.NonceSize()) + hpKey := hkdfExpandLabel(sha256.New, secret, headerProtectionLabel(v), nil, chacha20.KeySize) + k := &ProtectionKey{} + k.aead = aead + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#name-chacha20-based-header-prote + k.headerProtection = func(sample []byte) []byte { + nonce := sample[4:16] + c, err := chacha20.NewUnauthenticatedCipher(hpKey, nonce) + if err != nil { + panic(err) + } + c.SetCounter(binary.LittleEndian.Uint32(sample[:4])) + mask := make([]byte, 5) + c.XORKeyStream(mask, mask) + return mask + } + k.iv = iv + return k, nil + } + return nil, errors.New("not supported cipher suite") +} + +// decodePacketNumber decode the packet number after header protection removed. +// +// See: https://datatracker.ietf.org/doc/html/draft-ietf-quic-transport-32#section-appendix.a +func decodePacketNumber(largest, truncated int64, nbits uint8) int64 { + expected := largest + 1 + win := int64(1 << (nbits * 8)) + hwin := win / 2 + mask := win - 1 + candidate := (expected &^ mask) | truncated + switch { + case candidate <= expected-hwin && candidate < (1<<62)-win: + return candidate + win + case candidate > expected+hwin && candidate >= win: + return candidate - win + } + return candidate +} + +// Copied from crypto/tls/key_schedule.go. +func hkdfExpandLabel(hash func() hash.Hash, secret []byte, label string, context []byte, length int) []byte { + var hkdfLabel cryptobyte.Builder + hkdfLabel.AddUint16(uint16(length)) + hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes([]byte("tls13 ")) + b.AddBytes([]byte(label)) + }) + hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(context) + }) + out := make([]byte, length) + n, err := hkdf.Expand(hash, secret, hkdfLabel.BytesOrPanic()).Read(out) + if err != nil || n != length { + panic("quic: HKDF-Expand-Label invocation failed unexpectedly") + } + return out +} diff --git a/hysteria/extras/sniff/internal/quic/packet_protector_test.go b/hysteria/extras/sniff/internal/quic/packet_protector_test.go new file mode 100644 index 0000000000..bc355d2186 --- /dev/null +++ b/hysteria/extras/sniff/internal/quic/packet_protector_test.go @@ -0,0 +1,94 @@ +package quic + +import ( + "bytes" + "crypto" + "crypto/tls" + "encoding/hex" + "strings" + "testing" + "unicode" + + "golang.org/x/crypto/hkdf" +) + +func TestInitialPacketProtector_UnProtect(t *testing.T) { + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#name-server-initial + protect := mustHexDecodeString(` + c7ff0000200008f067a5502a4262b500 4075fb12ff07823a5d24534d906ce4c7 + 6782a2167e3479c0f7f6395dc2c91676 302fe6d70bb7cbeb117b4ddb7d173498 + 44fd61dae200b8338e1b932976b61d91 e64a02e9e0ee72e3a6f63aba4ceeeec5 + be2f24f2d86027572943533846caa13e 6f163fb257473d0eda5047360fd4a47e + fd8142fafc0f76 + `) + unProtect := mustHexDecodeString(` + 02000000000600405a020000560303ee fce7f7b37ba1d1632e96677825ddf739 + 88cfc79825df566dc5430b9a045a1200 130100002e00330024001d00209d3c94 + 0d89690b84d08a60993c144eca684d10 81287c834d5311bcf32bb9da1a002b00 + 020304 + `) + + connID := mustHexDecodeString(`8394c8f03e515708`) + + packet := append([]byte{}, protect...) + hdr, offset, err := ParseInitialHeader(packet) + if err != nil { + t.Fatal(err) + } + + initialSecret := hkdf.Extract(crypto.SHA256.New, connID, getSalt(hdr.Version)) + serverSecret := hkdfExpandLabel(crypto.SHA256.New, initialSecret, "server in", []byte{}, crypto.SHA256.Size()) + key, err := NewInitialProtectionKey(serverSecret, hdr.Version) + if err != nil { + t.Fatal(err) + } + pp := NewPacketProtector(key) + got, err := pp.UnProtect(protect, offset, 1) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, unProtect) { + t.Error("UnProtect returns wrong result") + } +} + +func TestPacketProtectorShortHeader_UnProtect(t *testing.T) { + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#name-chacha20-poly1305-short-hea + protect := mustHexDecodeString(`4cfe4189655e5cd55c41f69080575d7999c25a5bfb`) + unProtect := mustHexDecodeString(`01`) + hdr := mustHexDecodeString(`4200bff4`) + + secret := mustHexDecodeString(`9ac312a7f877468ebe69422748ad00a1 5443f18203a07d6060f688f30f21632b`) + k, err := NewProtectionKey(tls.TLS_CHACHA20_POLY1305_SHA256, secret, V1) + if err != nil { + t.Fatal(err) + } + + pnLen := int(hdr[0]&0x03) + 1 + offset := len(hdr) - pnLen + pp := NewPacketProtector(k) + got, err := pp.UnProtect(protect, int64(offset), 654360564) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, unProtect) { + t.Error("UnProtect returns wrong result") + } +} + +func mustHexDecodeString(s string) []byte { + b, err := hex.DecodeString(normalizeHex(s)) + if err != nil { + panic(err) + } + return b +} + +func normalizeHex(s string) string { + return strings.Map(func(c rune) rune { + if unicode.IsSpace(c) { + return -1 + } + return c + }, s) +} diff --git a/hysteria/extras/sniff/internal/quic/payload.go b/hysteria/extras/sniff/internal/quic/payload.go new file mode 100644 index 0000000000..453b714a4c --- /dev/null +++ b/hysteria/extras/sniff/internal/quic/payload.go @@ -0,0 +1,122 @@ +package quic + +import ( + "bytes" + "crypto" + "errors" + "fmt" + "io" + "sort" + + "github.com/apernet/quic-go/quicvarint" + "golang.org/x/crypto/hkdf" +) + +func ReadCryptoPayload(packet []byte) ([]byte, error) { + hdr, offset, err := ParseInitialHeader(packet) + if err != nil { + return nil, err + } + // Some sanity checks + if hdr.Version != V1 && hdr.Version != V2 { + return nil, fmt.Errorf("unsupported version: %x", hdr.Version) + } + if offset == 0 || hdr.Length == 0 { + return nil, errors.New("invalid packet") + } + + initialSecret := hkdf.Extract(crypto.SHA256.New, hdr.DestConnectionID, getSalt(hdr.Version)) + clientSecret := hkdfExpandLabel(crypto.SHA256.New, initialSecret, "client in", []byte{}, crypto.SHA256.Size()) + key, err := NewInitialProtectionKey(clientSecret, hdr.Version) + if err != nil { + return nil, fmt.Errorf("NewInitialProtectionKey: %w", err) + } + pp := NewPacketProtector(key) + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#name-client-initial + // + // "The unprotected header includes the connection ID and a 4-byte packet number encoding for a packet number of 2" + if int64(len(packet)) < offset+hdr.Length { + return nil, fmt.Errorf("packet is too short: %d < %d", len(packet), offset+hdr.Length) + } + unProtectedPayload, err := pp.UnProtect(packet[:offset+hdr.Length], offset, 2) + if err != nil { + return nil, err + } + frs, err := extractCryptoFrames(bytes.NewReader(unProtectedPayload)) + if err != nil { + return nil, err + } + data := assembleCryptoFrames(frs) + if data == nil { + return nil, errors.New("unable to assemble crypto frames") + } + return data, nil +} + +const ( + paddingFrameType = 0x00 + pingFrameType = 0x01 + cryptoFrameType = 0x06 +) + +type cryptoFrame struct { + Offset int64 + Data []byte +} + +func extractCryptoFrames(r *bytes.Reader) ([]cryptoFrame, error) { + var frames []cryptoFrame + for r.Len() > 0 { + typ, err := quicvarint.Read(r) + if err != nil { + return nil, err + } + if typ == paddingFrameType || typ == pingFrameType { + continue + } + if typ != cryptoFrameType { + return nil, fmt.Errorf("encountered unexpected frame type: %d", typ) + } + var frame cryptoFrame + offset, err := quicvarint.Read(r) + if err != nil { + return nil, err + } + frame.Offset = int64(offset) + dataLen, err := quicvarint.Read(r) + if err != nil { + return nil, err + } + frame.Data = make([]byte, dataLen) + if _, err := io.ReadFull(r, frame.Data); err != nil { + return nil, err + } + frames = append(frames, frame) + } + return frames, nil +} + +// assembleCryptoFrames assembles multiple crypto frames into a single slice (if possible). +// It returns an error if the frames cannot be assembled. This can happen if the frames are not contiguous. +func assembleCryptoFrames(frames []cryptoFrame) []byte { + if len(frames) == 0 { + return nil + } + if len(frames) == 1 { + return frames[0].Data + } + // sort the frames by offset + sort.Slice(frames, func(i, j int) bool { return frames[i].Offset < frames[j].Offset }) + // check if the frames are contiguous + for i := 1; i < len(frames); i++ { + if frames[i].Offset != frames[i-1].Offset+int64(len(frames[i-1].Data)) { + return nil + } + } + // concatenate the frames + data := make([]byte, frames[len(frames)-1].Offset+int64(len(frames[len(frames)-1].Data))) + for _, frame := range frames { + copy(data[frame.Offset:], frame.Data) + } + return data +} diff --git a/hysteria/extras/sniff/internal/quic/quic.go b/hysteria/extras/sniff/internal/quic/quic.go new file mode 100644 index 0000000000..1cfa103867 --- /dev/null +++ b/hysteria/extras/sniff/internal/quic/quic.go @@ -0,0 +1,59 @@ +package quic + +const ( + V1 uint32 = 0x1 + V2 uint32 = 0x6b3343cf + + hkdfLabelKeyV1 = "quic key" + hkdfLabelKeyV2 = "quicv2 key" + hkdfLabelIVV1 = "quic iv" + hkdfLabelIVV2 = "quicv2 iv" + hkdfLabelHPV1 = "quic hp" + hkdfLabelHPV2 = "quicv2 hp" +) + +var ( + quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99} + // https://www.rfc-editor.org/rfc/rfc9001.html#name-initial-secrets + quicSaltV1 = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a} + // https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-initial-salt-2 + quicSaltV2 = []byte{0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9} +) + +// isLongHeader reports whether b is the first byte of a long header packet. +func isLongHeader(b byte) bool { + return b&0x80 > 0 +} + +func getSalt(v uint32) []byte { + switch v { + case V1: + return quicSaltV1 + case V2: + return quicSaltV2 + } + return quicSaltOld +} + +func keyLabel(v uint32) string { + kl := hkdfLabelKeyV1 + if v == V2 { + kl = hkdfLabelKeyV2 + } + return kl +} + +func ivLabel(v uint32) string { + ivl := hkdfLabelIVV1 + if v == V2 { + ivl = hkdfLabelIVV2 + } + return ivl +} + +func headerProtectionLabel(v uint32) string { + if v == V2 { + return hkdfLabelHPV2 + } + return hkdfLabelHPV1 +} diff --git a/hysteria/extras/sniff/mock_Stream.go b/hysteria/extras/sniff/mock_Stream.go new file mode 100644 index 0000000000..8b21e953b9 --- /dev/null +++ b/hysteria/extras/sniff/mock_Stream.go @@ -0,0 +1,492 @@ +// Code generated by mockery v2.43.0. DO NOT EDIT. + +package sniff + +import ( + context "context" + + qerr "github.com/apernet/quic-go" + mock "github.com/stretchr/testify/mock" + + time "time" +) + +// mockStream is an autogenerated mock type for the Stream type +type mockStream struct { + mock.Mock +} + +type mockStream_Expecter struct { + mock *mock.Mock +} + +func (_m *mockStream) EXPECT() *mockStream_Expecter { + return &mockStream_Expecter{mock: &_m.Mock} +} + +// CancelRead provides a mock function with given fields: _a0 +func (_m *mockStream) CancelRead(_a0 qerr.StreamErrorCode) { + _m.Called(_a0) +} + +// mockStream_CancelRead_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelRead' +type mockStream_CancelRead_Call struct { + *mock.Call +} + +// CancelRead is a helper method to define mock.On call +// - _a0 qerr.StreamErrorCode +func (_e *mockStream_Expecter) CancelRead(_a0 interface{}) *mockStream_CancelRead_Call { + return &mockStream_CancelRead_Call{Call: _e.mock.On("CancelRead", _a0)} +} + +func (_c *mockStream_CancelRead_Call) Run(run func(_a0 qerr.StreamErrorCode)) *mockStream_CancelRead_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(qerr.StreamErrorCode)) + }) + return _c +} + +func (_c *mockStream_CancelRead_Call) Return() *mockStream_CancelRead_Call { + _c.Call.Return() + return _c +} + +func (_c *mockStream_CancelRead_Call) RunAndReturn(run func(qerr.StreamErrorCode)) *mockStream_CancelRead_Call { + _c.Call.Return(run) + return _c +} + +// CancelWrite provides a mock function with given fields: _a0 +func (_m *mockStream) CancelWrite(_a0 qerr.StreamErrorCode) { + _m.Called(_a0) +} + +// mockStream_CancelWrite_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelWrite' +type mockStream_CancelWrite_Call struct { + *mock.Call +} + +// CancelWrite is a helper method to define mock.On call +// - _a0 qerr.StreamErrorCode +func (_e *mockStream_Expecter) CancelWrite(_a0 interface{}) *mockStream_CancelWrite_Call { + return &mockStream_CancelWrite_Call{Call: _e.mock.On("CancelWrite", _a0)} +} + +func (_c *mockStream_CancelWrite_Call) Run(run func(_a0 qerr.StreamErrorCode)) *mockStream_CancelWrite_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(qerr.StreamErrorCode)) + }) + return _c +} + +func (_c *mockStream_CancelWrite_Call) Return() *mockStream_CancelWrite_Call { + _c.Call.Return() + return _c +} + +func (_c *mockStream_CancelWrite_Call) RunAndReturn(run func(qerr.StreamErrorCode)) *mockStream_CancelWrite_Call { + _c.Call.Return(run) + return _c +} + +// Close provides a mock function with given fields: +func (_m *mockStream) Close() error { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Close") + } + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockStream_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type mockStream_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +func (_e *mockStream_Expecter) Close() *mockStream_Close_Call { + return &mockStream_Close_Call{Call: _e.mock.On("Close")} +} + +func (_c *mockStream_Close_Call) Run(run func()) *mockStream_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockStream_Close_Call) Return(_a0 error) *mockStream_Close_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockStream_Close_Call) RunAndReturn(run func() error) *mockStream_Close_Call { + _c.Call.Return(run) + return _c +} + +// Context provides a mock function with given fields: +func (_m *mockStream) Context() context.Context { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Context") + } + + var r0 context.Context + if rf, ok := ret.Get(0).(func() context.Context); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(context.Context) + } + } + + return r0 +} + +// mockStream_Context_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Context' +type mockStream_Context_Call struct { + *mock.Call +} + +// Context is a helper method to define mock.On call +func (_e *mockStream_Expecter) Context() *mockStream_Context_Call { + return &mockStream_Context_Call{Call: _e.mock.On("Context")} +} + +func (_c *mockStream_Context_Call) Run(run func()) *mockStream_Context_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockStream_Context_Call) Return(_a0 context.Context) *mockStream_Context_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockStream_Context_Call) RunAndReturn(run func() context.Context) *mockStream_Context_Call { + _c.Call.Return(run) + return _c +} + +// Read provides a mock function with given fields: p +func (_m *mockStream) Read(p []byte) (int, error) { + ret := _m.Called(p) + + if len(ret) == 0 { + panic("no return value specified for Read") + } + + var r0 int + var r1 error + if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok { + return rf(p) + } + if rf, ok := ret.Get(0).(func([]byte) int); ok { + r0 = rf(p) + } else { + r0 = ret.Get(0).(int) + } + + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(p) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockStream_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read' +type mockStream_Read_Call struct { + *mock.Call +} + +// Read is a helper method to define mock.On call +// - p []byte +func (_e *mockStream_Expecter) Read(p interface{}) *mockStream_Read_Call { + return &mockStream_Read_Call{Call: _e.mock.On("Read", p)} +} + +func (_c *mockStream_Read_Call) Run(run func(p []byte)) *mockStream_Read_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]byte)) + }) + return _c +} + +func (_c *mockStream_Read_Call) Return(n int, err error) *mockStream_Read_Call { + _c.Call.Return(n, err) + return _c +} + +func (_c *mockStream_Read_Call) RunAndReturn(run func([]byte) (int, error)) *mockStream_Read_Call { + _c.Call.Return(run) + return _c +} + +// SetDeadline provides a mock function with given fields: t +func (_m *mockStream) SetDeadline(t time.Time) error { + ret := _m.Called(t) + + if len(ret) == 0 { + panic("no return value specified for SetDeadline") + } + + var r0 error + if rf, ok := ret.Get(0).(func(time.Time) error); ok { + r0 = rf(t) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockStream_SetDeadline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDeadline' +type mockStream_SetDeadline_Call struct { + *mock.Call +} + +// SetDeadline is a helper method to define mock.On call +// - t time.Time +func (_e *mockStream_Expecter) SetDeadline(t interface{}) *mockStream_SetDeadline_Call { + return &mockStream_SetDeadline_Call{Call: _e.mock.On("SetDeadline", t)} +} + +func (_c *mockStream_SetDeadline_Call) Run(run func(t time.Time)) *mockStream_SetDeadline_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(time.Time)) + }) + return _c +} + +func (_c *mockStream_SetDeadline_Call) Return(_a0 error) *mockStream_SetDeadline_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockStream_SetDeadline_Call) RunAndReturn(run func(time.Time) error) *mockStream_SetDeadline_Call { + _c.Call.Return(run) + return _c +} + +// SetReadDeadline provides a mock function with given fields: t +func (_m *mockStream) SetReadDeadline(t time.Time) error { + ret := _m.Called(t) + + if len(ret) == 0 { + panic("no return value specified for SetReadDeadline") + } + + var r0 error + if rf, ok := ret.Get(0).(func(time.Time) error); ok { + r0 = rf(t) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockStream_SetReadDeadline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetReadDeadline' +type mockStream_SetReadDeadline_Call struct { + *mock.Call +} + +// SetReadDeadline is a helper method to define mock.On call +// - t time.Time +func (_e *mockStream_Expecter) SetReadDeadline(t interface{}) *mockStream_SetReadDeadline_Call { + return &mockStream_SetReadDeadline_Call{Call: _e.mock.On("SetReadDeadline", t)} +} + +func (_c *mockStream_SetReadDeadline_Call) Run(run func(t time.Time)) *mockStream_SetReadDeadline_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(time.Time)) + }) + return _c +} + +func (_c *mockStream_SetReadDeadline_Call) Return(_a0 error) *mockStream_SetReadDeadline_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockStream_SetReadDeadline_Call) RunAndReturn(run func(time.Time) error) *mockStream_SetReadDeadline_Call { + _c.Call.Return(run) + return _c +} + +// SetWriteDeadline provides a mock function with given fields: t +func (_m *mockStream) SetWriteDeadline(t time.Time) error { + ret := _m.Called(t) + + if len(ret) == 0 { + panic("no return value specified for SetWriteDeadline") + } + + var r0 error + if rf, ok := ret.Get(0).(func(time.Time) error); ok { + r0 = rf(t) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockStream_SetWriteDeadline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetWriteDeadline' +type mockStream_SetWriteDeadline_Call struct { + *mock.Call +} + +// SetWriteDeadline is a helper method to define mock.On call +// - t time.Time +func (_e *mockStream_Expecter) SetWriteDeadline(t interface{}) *mockStream_SetWriteDeadline_Call { + return &mockStream_SetWriteDeadline_Call{Call: _e.mock.On("SetWriteDeadline", t)} +} + +func (_c *mockStream_SetWriteDeadline_Call) Run(run func(t time.Time)) *mockStream_SetWriteDeadline_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(time.Time)) + }) + return _c +} + +func (_c *mockStream_SetWriteDeadline_Call) Return(_a0 error) *mockStream_SetWriteDeadline_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockStream_SetWriteDeadline_Call) RunAndReturn(run func(time.Time) error) *mockStream_SetWriteDeadline_Call { + _c.Call.Return(run) + return _c +} + +// StreamID provides a mock function with given fields: +func (_m *mockStream) StreamID() qerr.StreamID { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for StreamID") + } + + var r0 qerr.StreamID + if rf, ok := ret.Get(0).(func() qerr.StreamID); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(qerr.StreamID) + } + + return r0 +} + +// mockStream_StreamID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StreamID' +type mockStream_StreamID_Call struct { + *mock.Call +} + +// StreamID is a helper method to define mock.On call +func (_e *mockStream_Expecter) StreamID() *mockStream_StreamID_Call { + return &mockStream_StreamID_Call{Call: _e.mock.On("StreamID")} +} + +func (_c *mockStream_StreamID_Call) Run(run func()) *mockStream_StreamID_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockStream_StreamID_Call) Return(_a0 qerr.StreamID) *mockStream_StreamID_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockStream_StreamID_Call) RunAndReturn(run func() qerr.StreamID) *mockStream_StreamID_Call { + _c.Call.Return(run) + return _c +} + +// Write provides a mock function with given fields: p +func (_m *mockStream) Write(p []byte) (int, error) { + ret := _m.Called(p) + + if len(ret) == 0 { + panic("no return value specified for Write") + } + + var r0 int + var r1 error + if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok { + return rf(p) + } + if rf, ok := ret.Get(0).(func([]byte) int); ok { + r0 = rf(p) + } else { + r0 = ret.Get(0).(int) + } + + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(p) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockStream_Write_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Write' +type mockStream_Write_Call struct { + *mock.Call +} + +// Write is a helper method to define mock.On call +// - p []byte +func (_e *mockStream_Expecter) Write(p interface{}) *mockStream_Write_Call { + return &mockStream_Write_Call{Call: _e.mock.On("Write", p)} +} + +func (_c *mockStream_Write_Call) Run(run func(p []byte)) *mockStream_Write_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]byte)) + }) + return _c +} + +func (_c *mockStream_Write_Call) Return(n int, err error) *mockStream_Write_Call { + _c.Call.Return(n, err) + return _c +} + +func (_c *mockStream_Write_Call) RunAndReturn(run func([]byte) (int, error)) *mockStream_Write_Call { + _c.Call.Return(run) + return _c +} + +// newMockStream creates a new instance of mockStream. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockStream(t interface { + mock.TestingT + Cleanup(func()) +}) *mockStream { + mock := &mockStream{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/hysteria/extras/sniff/sniff.go b/hysteria/extras/sniff/sniff.go new file mode 100644 index 0000000000..e0c94d44f6 --- /dev/null +++ b/hysteria/extras/sniff/sniff.go @@ -0,0 +1,193 @@ +package sniff + +import ( + "bufio" + "io" + "net" + "net/http" + "strconv" + "strings" + "time" + + "github.com/apernet/quic-go" + utls "github.com/refraction-networking/utls" + + "github.com/apernet/hysteria/core/v2/server" + quicInternal "github.com/apernet/hysteria/extras/v2/sniff/internal/quic" + "github.com/apernet/hysteria/extras/v2/utils" +) + +const ( + sniffDefaultTimeout = 4 * time.Second +) + +var _ server.RequestHook = (*Sniffer)(nil) + +// Sniffer is a server core RequestHook that performs packet inspection and possibly +// rewrites the request address based on what's in the protocol header. +// This is mainly for inbounds that inherently cannot get domain information (e.g. TUN), +// in which case sniffing can restore the domains and apply ACLs correctly. +// Currently supports HTTP, HTTPS (TLS) and QUIC. +type Sniffer struct { + Timeout time.Duration + RewriteDomain bool // Whether to rewrite the address even when it's already a domain + TCPPorts utils.PortUnion + UDPPorts utils.PortUnion +} + +func (h *Sniffer) isDomain(addr string) bool { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return false + } + return net.ParseIP(host) == nil +} + +func (h *Sniffer) isHTTP(buf []byte) bool { + if len(buf) < 3 { + return false + } + // First 3 bytes should be English letters (whatever HTTP method) + for _, b := range buf[:3] { + if (b < 'A' || b > 'Z') && (b < 'a' || b > 'z') { + return false + } + } + return true +} + +func (h *Sniffer) isTLS(buf []byte) bool { + if len(buf) < 3 { + return false + } + return buf[0] >= 0x16 && buf[0] <= 0x17 && + buf[1] == 0x03 && buf[2] <= 0x09 +} + +func (h *Sniffer) Check(isUDP bool, reqAddr string) bool { + // @ means it's internal (e.g. speed test) + if strings.HasPrefix(reqAddr, "@") { + return false + } + host, port, err := net.SplitHostPort(reqAddr) + if err != nil { + return false + } + if !h.RewriteDomain && net.ParseIP(host) == nil { + // Is a domain and domain rewriting is disabled + return false + } + portNum, err := strconv.Atoi(port) + if err != nil { + return false + } + if isUDP { + return h.UDPPorts == nil || h.UDPPorts.Contains(uint16(portNum)) + } else { + return h.TCPPorts == nil || h.TCPPorts.Contains(uint16(portNum)) + } +} + +func (h *Sniffer) TCP(stream quic.Stream, reqAddr *string) ([]byte, error) { + var err error + if h.Timeout == 0 { + err = stream.SetReadDeadline(time.Now().Add(sniffDefaultTimeout)) + } else { + err = stream.SetReadDeadline(time.Now().Add(h.Timeout)) + } + if err != nil { + return nil, err + } + // Make sure to reset the deadline after sniffing + defer stream.SetReadDeadline(time.Time{}) + // Read 3 bytes to determine the protocol + pre := make([]byte, 3) + n, err := io.ReadFull(stream, pre) + if err != nil { + // Not enough within the timeout, just return what we have + return pre[:n], nil + } + if h.isHTTP(pre) { + // HTTP + tr := &teeReader{Stream: stream, Pre: pre} + req, _ := http.ReadRequest(bufio.NewReader(tr)) + if req != nil && req.Host != "" { + _, port, err := net.SplitHostPort(*reqAddr) + if err != nil { + return nil, err + } + *reqAddr = net.JoinHostPort(req.Host, port) + } + return tr.Buffer(), nil + } else if h.isTLS(pre) { + // TLS + // Need to read 2 more bytes (content length) + pre = append(pre, make([]byte, 2)...) + n, err = io.ReadFull(stream, pre[3:]) + if err != nil { + // Not enough within the timeout, just return what we have + return pre[:3+n], nil + } + contentLength := int(pre[3])<<8 | int(pre[4]) + pre = append(pre, make([]byte, contentLength)...) + n, err = io.ReadFull(stream, pre[5:]) + if err != nil { + // Not enough within the timeout, just return what we have + return pre[:5+n], nil + } + clientHello := utls.UnmarshalClientHello(pre[5:]) + if clientHello != nil && clientHello.ServerName != "" { + _, port, err := net.SplitHostPort(*reqAddr) + if err != nil { + return nil, err + } + *reqAddr = net.JoinHostPort(clientHello.ServerName, port) + } + return pre, nil + } else { + // Unrecognized protocol, just return what we have + return pre, nil + } +} + +func (h *Sniffer) UDP(data []byte, reqAddr *string) error { + pl, err := quicInternal.ReadCryptoPayload(data) + if err != nil || len(pl) < 4 || pl[0] != 0x01 { + // Unrecognized protocol, incomplete payload or not a client hello + return nil + } + clientHello := utls.UnmarshalClientHello(pl) + if clientHello != nil && clientHello.ServerName != "" { + _, port, err := net.SplitHostPort(*reqAddr) + if err != nil { + return err + } + *reqAddr = net.JoinHostPort(clientHello.ServerName, port) + } + return nil +} + +type teeReader struct { + Stream quic.Stream + Pre []byte + + buf []byte +} + +func (c *teeReader) Read(b []byte) (n int, err error) { + if len(c.Pre) > 0 { + n = copy(b, c.Pre) + c.Pre = c.Pre[n:] + c.buf = append(c.buf, b[:n]...) + return n, nil + } + n, err = c.Stream.Read(b) + if n > 0 { + c.buf = append(c.buf, b[:n]...) + } + return n, err +} + +func (c *teeReader) Buffer() []byte { + return append(c.Pre, c.buf...) +} diff --git a/hysteria/extras/sniff/sniff_test.go b/hysteria/extras/sniff/sniff_test.go new file mode 100644 index 0000000000..a22784ef11 --- /dev/null +++ b/hysteria/extras/sniff/sniff_test.go @@ -0,0 +1,135 @@ +package sniff + +import ( + "encoding/base64" + "io" + "testing" + "time" + + "github.com/apernet/hysteria/extras/v2/utils" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestSnifferCheck(t *testing.T) { + sniffer := &Sniffer{ + Timeout: 1 * time.Second, + RewriteDomain: false, + TCPPorts: nil, // nil = all + UDPPorts: nil, // nil = all + } + + assert.True(t, sniffer.Check(false, "1.1.1.1:80")) + assert.False(t, sniffer.Check(false, "example.com:443")) + + sniffer.RewriteDomain = true + assert.True(t, sniffer.Check(false, "example.com:443")) + + sniffer.TCPPorts = []utils.PortRange{{80, 80}} + assert.True(t, sniffer.Check(false, "google.com:80")) + assert.False(t, sniffer.Check(false, "google.com:443")) + + sniffer.UDPPorts = []utils.PortRange{{443, 443}} + assert.True(t, sniffer.Check(true, "google.com:443")) + assert.False(t, sniffer.Check(true, "google.com:80")) +} + +func TestSnifferTCP(t *testing.T) { + sniffer := &Sniffer{ + Timeout: 1 * time.Second, + RewriteDomain: false, + } + + buf := &[]byte{} + + // Test HTTP + *buf = []byte("POST /hello HTTP/1.1\r\n" + + "Host: example.com\r\n" + + "User-Agent: mamamiya\r\n" + + "Content-Length: 27\r\n" + + "Connection: keep-alive\r\n\r\n" + + "param1=value1¶m2=value2") + index := 0 + stream := &mockStream{} + stream.EXPECT().SetReadDeadline(mock.Anything).Return(nil) + stream.EXPECT().Read(mock.Anything).RunAndReturn(func(bs []byte) (int, error) { + if index < len(*buf) { + n := copy(bs, (*buf)[index:]) + index += n + return n, nil + } else { + return 0, io.EOF + } + }) + + // Rewrite IP to domain + reqAddr := "111.111.111.111:80" + putback, err := sniffer.TCP(stream, &reqAddr) + assert.NoError(t, err) + assert.Equal(t, *buf, putback) + assert.Equal(t, "example.com:80", reqAddr) + + // Test TLS + *buf, err = base64.StdEncoding.DecodeString("FgMBARcBAAETAwPJL2jlt1OAo+Rslkjv/aqKiTthKMaCKg2Gvd+uALDbDCDdY+UIk8ouadEB9fC3j52Y1i7SJZqGIgBRIS6kKieYrAAoEwITAcAswCvAMMAvwCTAI8AowCfACsAJwBTAEwCdAJwAPQA8ADUALwEAAKIAAAAOAAwAAAlpcGluZm8uaW8ABQAFAQAAAAAAKwAJCAMEAwMDAgMBAA0AGgAYCAQIBQgGBAEFAQIBBAMFAwIDAgIGAQYDACMAAAAKAAgABgAdABcAGAAQAAsACQhodHRwLzEuMQAzACYAJAAdACBguQbqNJNyamYxYcrBFpBP7pWv5TgZsP9gwGtMYNKVBQAxAAAAFwAA/wEAAQAALQACAQE=") + assert.NoError(t, err) + index = 0 + reqAddr = "222.222.222.222:443" + putback, err = sniffer.TCP(stream, &reqAddr) + assert.NoError(t, err) + assert.Equal(t, *buf, putback) + assert.Equal(t, "ipinfo.io:443", reqAddr) + + // Test unrecognized 1 + *buf = []byte("Wait It's All Ohio? Always Has Been.") + index = 0 + reqAddr = "123.123.123.123:123" + putback, err = sniffer.TCP(stream, &reqAddr) + assert.NoError(t, err) + assert.Equal(t, *buf, putback) + assert.Equal(t, "123.123.123.123:123", reqAddr) + + // Test unrecognized 2 + *buf = []byte("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a") + index = 0 + reqAddr = "45.45.45.45:45" + putback, err = sniffer.TCP(stream, &reqAddr) + assert.NoError(t, err) + assert.Equal(t, []byte("\x01\x02\x03"), putback) + assert.Equal(t, "45.45.45.45:45", reqAddr) + + // Test timeout + blockStream := &mockStream{} + blockStream.EXPECT().SetReadDeadline(mock.Anything).Return(nil) + blockStream.EXPECT().Read(mock.Anything).RunAndReturn(func(bs []byte) (int, error) { + time.Sleep(2 * time.Second) + return 0, io.EOF + }) + reqAddr = "66.66.66.66:66" + putback, err = sniffer.TCP(blockStream, &reqAddr) + assert.NoError(t, err) + assert.Equal(t, []byte{}, putback) + assert.Equal(t, "66.66.66.66:66", reqAddr) +} + +func TestSnifferUDP(t *testing.T) { + sniffer := &Sniffer{ + Timeout: 1 * time.Second, + RewriteDomain: false, + } + + // Test QUIC + reqAddr := "2.3.4.5:443" + pkt, err := base64.StdEncoding.DecodeString("ygAAAAEIwugWgPS7ulYAAES8hY891uwgGE9GG4CPOLd+nsDe28raso24lCSFmlFwYQG1uF39ikbL13/R9ZTghYmTl+jEbr6F9TxxRiOgpTmKRmh6aKZiIiVfy5pVRckovaI8lq0WRoW9xoFNTyYtQP8TVJ3bLCK+zUqpquEQSyWf7CE43ywayyMpE9UlIoPXFWCoopXLM1SvzdQ+17P51N9KR7m4emti4DWWTBLMQOvrwd2HEEkbiZdRO1wf6ZXJlIat5dN0R/6uod60OFPO+u+awvq67MoMReC7+5I/xWI+xx6o4JpnZNn6YPG8Gqi8hS6doNcAAdtD8h5eMLuHCCgkpX3QVjjfWtcOhtw9xKjU43HhUPwzUTv+JDLgwuTQCTmlfYlb3B+pk4b2I9si0tJ0SBuYaZ2VQPtZbj2hpGXw3gn11pbN8xsbKkQL50+Scd4dGJxWQlGaJHeaU5WOCkxLXc635z8m5XO/CBHVYPGp4pfwfwNUgbe5WF+3MaUIlDB8dMfsnrO0BmZPo379jVx0SFLTAiS8wAdHib1WNEY8qKYnTWuiyxYg1GZEhJt0nXmI+8f0eJq42DgHBWC+Rf5rRBr/Sf25o3mFAmTUaul0Woo9/CIrpT73B63N91xd9A77i4ru995YG8l9Hen+eLtpDU9Q9376nwMDYBzeYG9U/Rn0Urbm6q4hmAgV/xlNJ2rAyDS+yLnwqD6I0PRy8bZJEttcidb/SkOyrpgMiAzWeT+SO+c/k+Y8H0UTRa05faZUrhuUaym9wAcaIVRA6nFI+fejfjVp+7afFv+kWn3vCqQEij+CRHuxkltrixZMD2rfYj6NUW7TTYBtPRtuV/V0ZIDjRR26vr4K+0D84+l3c0mA/l6nmpP5kkco3nmpdjtQN6sGXL7+5o0nnsftX5d6/n5mLyEpP+AEDl1zk3iqkS62RsITwql6DMMoGbSDdUpMclCIeM0vlo3CkxGMO7QA9ruVeNddkL3EWMivl+uxO43sXEEqYQHVl4N75y63t05GOf7/gm9Kb/BJ8MpG9ViEkVYaskQCzi3D8bVpzo8FfTj8te8B6c3ikc/cm7r8k0ZcZpr+YiLGDYq+0ilHxpqJfmq8dPkSvxdzLcUSvy7+LMQ/TTobRSF7L4JhtDKck0+00vl9H35Tkh9N+MsVtpKdWyoqZ4XaK2Nx1M6AieczXpdFc0y7lYPoUfF4IeW8WzeVUclol5ElYjkyFz/lDOGAe1bF2g5AYaGWCPiGleVZknNdD5ihB8W8Mfkt1pEwq2S97AHrppqkf/VoIfZzeqH8wUFw8fDDrZIpnoa0rW7HfwIQaqJhPCyB9Z6TVbV4x9UWmaHfVAcinCK/7o10dtaj3rvEqcUC/iPceGq3Tqv/p9GGNJ+Ci2JBjXqNxYr893Llk75VdPD9pM6y1SM0P80oXNy32VMtafkFFST8GpvvqWcxUJ93kzaY8RmU1g3XFOImSU2utU6+FUQ2Pn5uLwcfT2cTYfTpPGh+WXjSbZ6trqdEMEsLHybuPo2UN4WpVLXVQma3kSaHQggcLlEip8GhEUAy/xCb2eKqhI4HkDpDjwDnDVKufWlnRaOHf58cc8Woi+WT8JTOkHC+nBEG6fKRPHDG08U5yayIQIjI") + assert.NoError(t, err) + err = sniffer.UDP(pkt, &reqAddr) + assert.NoError(t, err) + assert.Equal(t, "www.notion.so:443", reqAddr) + + // Test unrecognized + pkt = []byte("oh my sweet summer child") + reqAddr = "90.90.90.90:90" + err = sniffer.UDP(pkt, &reqAddr) + assert.NoError(t, err) + assert.Equal(t, "90.90.90.90:90", reqAddr) +} diff --git a/hysteria/extras/transport/udphop/addr.go b/hysteria/extras/transport/udphop/addr.go index 3c704728d7..afde26a3b3 100644 --- a/hysteria/extras/transport/udphop/addr.go +++ b/hysteria/extras/transport/udphop/addr.go @@ -3,8 +3,8 @@ package udphop import ( "fmt" "net" - "strconv" - "strings" + + "github.com/apernet/hysteria/extras/v2/utils" ) type InvalidPortError struct { @@ -57,36 +57,11 @@ func ResolveUDPHopAddr(addr string) (*UDPHopAddr, error) { PortStr: portStr, } - portStrs := strings.Split(portStr, ",") - for _, portStr := range portStrs { - if strings.Contains(portStr, "-") { - // Port range - portRange := strings.Split(portStr, "-") - if len(portRange) != 2 { - return nil, InvalidPortError{portStr} - } - start, err := strconv.ParseUint(portRange[0], 10, 16) - if err != nil { - return nil, InvalidPortError{portStr} - } - end, err := strconv.ParseUint(portRange[1], 10, 16) - if err != nil { - return nil, InvalidPortError{portStr} - } - if start > end { - start, end = end, start - } - for i := start; i <= end; i++ { - result.Ports = append(result.Ports, uint16(i)) - } - } else { - // Single port - port, err := strconv.ParseUint(portStr, 10, 16) - if err != nil { - return nil, InvalidPortError{portStr} - } - result.Ports = append(result.Ports, uint16(port)) - } + pu := utils.ParsePortUnion(portStr) + if pu == nil { + return nil, InvalidPortError{portStr} } + result.Ports = pu.Ports() + return result, nil } diff --git a/hysteria/extras/transport/udphop/addr_test.go b/hysteria/extras/transport/udphop/addr_test.go deleted file mode 100644 index 94a101624e..0000000000 --- a/hysteria/extras/transport/udphop/addr_test.go +++ /dev/null @@ -1,132 +0,0 @@ -package udphop - -import ( - "net" - "reflect" - "testing" -) - -func TestResolveUDPHopAddr(t *testing.T) { - type args struct { - addr string - } - tests := []struct { - name string - args args - want *UDPHopAddr - wantErr bool - }{ - { - name: "empty", - args: args{ - addr: "", - }, - want: nil, - wantErr: true, - }, - { - name: "no port", - args: args{ - addr: "8.8.8.8", - }, - want: nil, - wantErr: true, - }, - { - name: "single port", - args: args{ - addr: "8.8.4.4:1234", - }, - want: &UDPHopAddr{ - IP: net.ParseIP("8.8.4.4"), - Ports: []uint16{1234}, - PortStr: "1234", - }, - wantErr: false, - }, - { - name: "multiple ports", - args: args{ - addr: "8.8.3.3:1234,5678,9012", - }, - want: &UDPHopAddr{ - IP: net.ParseIP("8.8.3.3"), - Ports: []uint16{1234, 5678, 9012}, - PortStr: "1234,5678,9012", - }, - wantErr: false, - }, - { - name: "port range", - args: args{ - addr: "1.2.3.4:1234-1240", - }, - want: &UDPHopAddr{ - IP: net.ParseIP("1.2.3.4"), - Ports: []uint16{1234, 1235, 1236, 1237, 1238, 1239, 1240}, - PortStr: "1234-1240", - }, - wantErr: false, - }, - { - name: "port range reversed", - args: args{ - addr: "123.123.123.123:9990-9980", - }, - want: &UDPHopAddr{ - IP: net.ParseIP("123.123.123.123"), - Ports: []uint16{9980, 9981, 9982, 9983, 9984, 9985, 9986, 9987, 9988, 9989, 9990}, - PortStr: "9990-9980", - }, - wantErr: false, - }, - { - name: "port range & port list", - args: args{ - addr: "9.9.9.9:1234-1236,5678,9012", - }, - want: &UDPHopAddr{ - IP: net.ParseIP("9.9.9.9"), - Ports: []uint16{1234, 1235, 1236, 5678, 9012}, - PortStr: "1234-1236,5678,9012", - }, - wantErr: false, - }, - { - name: "invalid port", - args: args{ - addr: "5.5.5.5:1234,bs", - }, - want: nil, - wantErr: true, - }, - { - name: "invalid port range 1", - args: args{ - addr: "6.6.6.6:7788-bbss", - }, - want: nil, - wantErr: true, - }, - { - name: "invalid port range 2", - args: args{ - addr: "1.0.0.1:8899-9002-9005", - }, - want: nil, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ResolveUDPHopAddr(tt.args.addr) - if (err != nil) != tt.wantErr { - t.Errorf("ParseUDPHopAddr() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("ParseUDPHopAddr() got = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/hysteria/extras/utils/portunion.go b/hysteria/extras/utils/portunion.go new file mode 100644 index 0000000000..20a31d0f1b --- /dev/null +++ b/hysteria/extras/utils/portunion.go @@ -0,0 +1,107 @@ +package utils + +import ( + "sort" + "strconv" + "strings" +) + +// PortUnion is a collection of multiple port ranges. +type PortUnion []PortRange + +// PortRange represents a range of ports. +// Start and End are inclusive. [Start, End] +type PortRange struct { + Start, End uint16 +} + +// ParsePortUnion parses a string of comma-separated port ranges (or single ports) into a PortUnion. +// Returns nil if the input is invalid. +// The returned PortUnion is guaranteed to be normalized. +func ParsePortUnion(s string) PortUnion { + if s == "all" || s == "*" { + // Wildcard special case + return PortUnion{PortRange{0, 65535}} + } + var result PortUnion + portStrs := strings.Split(s, ",") + for _, portStr := range portStrs { + if strings.Contains(portStr, "-") { + // Port range + portRange := strings.Split(portStr, "-") + if len(portRange) != 2 { + return nil + } + start, err := strconv.ParseUint(portRange[0], 10, 16) + if err != nil { + return nil + } + end, err := strconv.ParseUint(portRange[1], 10, 16) + if err != nil { + return nil + } + if start > end { + start, end = end, start + } + result = append(result, PortRange{uint16(start), uint16(end)}) + } else { + // Single port + port, err := strconv.ParseUint(portStr, 10, 16) + if err != nil { + return nil + } + result = append(result, PortRange{uint16(port), uint16(port)}) + } + } + if result == nil { + return nil + } + return result.Normalize() +} + +// Normalize normalizes a PortUnion. +// No overlapping ranges, ranges are sorted from low to high. +func (u PortUnion) Normalize() PortUnion { + if len(u) == 0 { + return u + } + sort.Slice(u, func(i, j int) bool { + if u[i].Start == u[j].Start { + return u[i].End < u[j].End + } + return u[i].Start < u[j].Start + }) + normalized := PortUnion{u[0]} + for _, current := range u[1:] { + last := &normalized[len(normalized)-1] + if current.Start <= last.End+1 { + if current.End > last.End { + last.End = current.End + } + } else { + normalized = append(normalized, current) + } + } + return normalized +} + +// Ports returns all ports in the PortUnion as a slice. +func (u PortUnion) Ports() []uint16 { + var ports []uint16 + for _, r := range u { + for i := r.Start; i <= r.End; i++ { + ports = append(ports, i) + } + } + return ports +} + +// Contains returns true if the PortUnion contains the given port. +func (u PortUnion) Contains(port uint16) bool { + for _, r := range u { + if port >= r.Start && port <= r.End { + return true + } + } + return false +} diff --git a/hysteria/extras/utils/portunion_test.go b/hysteria/extras/utils/portunion_test.go new file mode 100644 index 0000000000..551bae137a --- /dev/null +++ b/hysteria/extras/utils/portunion_test.go @@ -0,0 +1,92 @@ +package utils + +import ( + "reflect" + "testing" +) + +func TestParsePortUnion(t *testing.T) { + tests := []struct { + name string + s string + want PortUnion + }{ + { + name: "empty", + s: "", + want: nil, + }, + { + name: "all 1", + s: "all", + want: PortUnion{{0, 65535}}, + }, + { + name: "all 2", + s: "*", + want: PortUnion{{0, 65535}}, + }, + { + name: "single port", + s: "1234", + want: PortUnion{{1234, 1234}}, + }, + { + name: "multiple ports (unsorted)", + s: "5678,1234,9012", + want: PortUnion{{1234, 1234}, {5678, 5678}, {9012, 9012}}, + }, + { + name: "one range", + s: "1234-1240", + want: PortUnion{{1234, 1240}}, + }, + { + name: "one range (reversed)", + s: "1240-1234", + want: PortUnion{{1234, 1240}}, + }, + { + name: "multiple ports and ranges (reversed, unsorted, overlapping)", + s: "5678,1200-1236,9100-9012,1234-1240", + want: PortUnion{{1200, 1240}, {5678, 5678}, {9012, 9100}}, + }, + { + name: "invalid 1", + s: "1234-", + want: nil, + }, + { + name: "invalid 2", + s: "1234-ggez", + want: nil, + }, + { + name: "invalid 3", + s: "233,", + want: nil, + }, + { + name: "invalid 4", + s: "1234-1240-1250", + want: nil, + }, + { + name: "invalid 5", + s: "-,,", + want: nil, + }, + { + name: "invalid 6", + s: "http", + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ParsePortUnion(tt.s); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ParsePortUnion() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/hysteria/go.work.sum b/hysteria/go.work.sum index 4370b0e538..f0551e7035 100644 --- a/hysteria/go.work.sum +++ b/hysteria/go.work.sum @@ -41,6 +41,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625 h1:ckJgFhFWywOx+ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= @@ -309,6 +311,8 @@ golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= diff --git a/lede/package/boot/arm-trusted-firmware-mediatek/Makefile b/lede/package/boot/arm-trusted-firmware-mediatek/Makefile index 5324563042..798070a59e 100644 --- a/lede/package/boot/arm-trusted-firmware-mediatek/Makefile +++ b/lede/package/boot/arm-trusted-firmware-mediatek/Makefile @@ -397,6 +397,15 @@ define Trusted-Firmware-A/mt7988-snand-comb DRAM_USE_COMB:=1 endef +define Trusted-Firmware-A/mt7988-snand-ubi-comb + NAME:=MediaTek MT7988 (SPI-NAND via SNFI, UBI) + BOOT_DEVICE:=snand + BUILD_SUBTARGET:=filogic + PLAT:=mt7988 + DRAM_USE_COMB:=1 + USE_UBI:=1 +endef + define Trusted-Firmware-A/mt7988-spim-nand-comb NAME:=MediaTek MT7988 (SPI-NAND via SPIM) BOOT_DEVICE:=spim-nand @@ -460,6 +469,7 @@ TFA_TARGETS:= \ mt7988-nor-comb \ mt7988-sdmmc-comb \ mt7988-snand-comb \ + mt7988-snand-ubi-comb \ mt7988-spim-nand-comb \ mt7988-spim-nand-ubi-comb @@ -472,7 +482,6 @@ TFA_MAKE_FLAGS += \ HAVE_DRAM_OBJ_FILE=yes \ $(if $(DDR3_FLYBY),DDR3_FLYBY=1) \ $(if $(DRAM_USE_COMB),DRAM_USE_COMB=1) \ - $(if $(RAM_BOOT_UART_DL),RAM_BOOT_UART_DL=1) \ $(if $(USE_UBI),UBI=1 $(if $(findstring mt7622,$(PLAT)),OVERRIDE_UBI_START_ADDR=0x80000)) \ $(if $(USE_UBI),UBI=1 $(if $(findstring mt7981,$(PLAT)),OVERRIDE_UBI_START_ADDR=0x100000)) \ all diff --git a/lede/package/boot/uboot-envtools/files/mediatek_filogic b/lede/package/boot/uboot-envtools/files/mediatek_filogic index e8f3c14664..5f81a699fb 100644 --- a/lede/package/boot/uboot-envtools/files/mediatek_filogic +++ b/lede/package/boot/uboot-envtools/files/mediatek_filogic @@ -11,45 +11,28 @@ touch /etc/config/ubootenv board=$(board_name) -ubootenv_add_mmc_default() { - local envdev="$(find_mmc_part "ubootenv" "${1:-mmcblk0}")" - ubootenv_add_uci_config "$envdev" "0x0" "0x40000" "0x40000" "1" - ubootenv_add_uci_config "$envdev" "0x40000" "0x40000" "0x40000" "1" -} - -ubootenv_add_nor_default() { - local envdev="/dev/mtd$(find_mtd_index "u-boot-env")" - ubootenv_add_uci_config "$envdev" "0x0" "0x20000" "0x20000" "1" - ubootenv_add_uci_config "$envdev" "0x20000" "0x20000" "0x20000" "1" -} - -ubootenv_add_ubi_default() { - . /lib/upgrade/nand.sh - local envubi=$(nand_find_ubi ubi) - local envdev=/dev/$(nand_find_volume $envubi ubootenv) - local envdev2=/dev/$(nand_find_volume $envubi ubootenv2) - ubootenv_add_uci_config "$envdev" "0x0" "0x1f000" "0x1f000" "1" - ubootenv_add_uci_config "$envdev2" "0x0" "0x1f000" "0x1f000" "1" -} - case "$board" in bananapi,bpi-r3|\ -bananapi,bpi-r3-mini|\ bananapi,bpi-r4|\ -bananapi,bpi-r4-poe|\ -jdcloud,re-cp-03) - . /lib/upgrade/common.sh - - bootdev="$(fitblk_get_bootdev)" - case "$bootdev" in - ubi*) - ubootenv_add_ubi_default +bananapi,bpi-r4-poe) + case "$(cmdline_get_var root)" in + /dev/mmc*) + local envdev=$(find_mmc_part "ubootenv" $rootdev) + ubootenv_add_uci_config "$envdev" "0x0" "0x40000" "0x40000" "1" + ubootenv_add_uci_config "$envdev" "0x40000" "0x40000" "0x40000" "1" ;; - mmc*) - ubootenv_add_mmc_default "${bootdev%%p[0-9]*}" + /dev/mtd*) + local envdev=/dev/mtd$(find_mtd_index "u-boot-env") + ubootenv_add_uci_config "$envdev" "0x0" "0x20000" "0x20000" "1" + ubootenv_add_uci_config "$envdev" "0x20000" "0x20000" "0x20000" "1" ;; - mtd*) - ubootenv_add_nor_default + /dev/ubi*) + . /lib/upgrade/nand.sh + local envubi=$(nand_find_ubi ubi) + local envdev=/dev/$(nand_find_volume $envubi ubootenv) + local envdev2=/dev/$(nand_find_volume $envubi ubootenv2) + ubootenv_add_uci_config "$envdev" "0x0" "0x1f000" "0x1f000" "1" + ubootenv_add_uci_config "$envdev2" "0x0" "0x1f000" "0x1f000" "1" ;; esac ;; diff --git a/lede/package/boot/uboot-mediatek/Makefile b/lede/package/boot/uboot-mediatek/Makefile index 8827bcf8c2..4f3041c0ca 100644 --- a/lede/package/boot/uboot-mediatek/Makefile +++ b/lede/package/boot/uboot-mediatek/Makefile @@ -5,8 +5,6 @@ PKG_VERSION:=2024.01 PKG_HASH:=b99611f1ed237bf3541bdc8434b68c96a6e05967061f992443cb30aabebef5b3 PKG_BUILD_DEPENDS:=!(TARGET_ramips||TARGET_mediatek_mt7623):arm-trusted-firmware-tools/host -UBOOT_USE_INTREE_DTC:=1 - include $(INCLUDE_DIR)/u-boot.mk include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/host-build.mk @@ -36,7 +34,6 @@ endif define U-Boot/Default BUILD_TARGET:=mediatek UBOOT_IMAGE:=u-boot-mtk.bin - HIDDEN:=1 endef define U-Boot/mt7620_rfb @@ -75,15 +72,6 @@ define U-Boot/mt7621_nand_rfb UBOOT_IMAGE:=u-boot-mt7621.bin endef -define U-Boot/mt7621_zbtlink_zbt-wg3526-16m - NAME:=Zbtlink ZBT-WG3526-16m - UBOOT_CONFIG:=mt7621_zbtlink_zbt-wg3526-16m - BUILD_DEVICES:=zbtlink_zbt-wg3526-16m - BUILD_TARGET:=ramips - BUILD_SUBTARGET:=mt7621 - UBOOT_IMAGE:=u-boot-mt7621.bin -endef - define U-Boot/mt7622_rfb1 NAME:=MT7622 Reference Board 1 UBOOT_CONFIG:=mt7622_rfb @@ -97,9 +85,9 @@ define U-Boot/mt7622_linksys_e8450 BUILD_DEVICES:=linksys_e8450-ubi BUILD_SUBTARGET:=mt7622 UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=snand-ubi + BL2_BOOTDEV:=snand BL2_DDRBLOB:=1 - DEPENDS:=+trusted-firmware-a-mt7622-snand-ubi-1ddr + DEPENDS:=+trusted-firmware-a-mt7622-snand-1ddr endef define U-Boot/mt7622_bananapi_bpi-r64-emmc @@ -130,15 +118,15 @@ define U-Boot/mt7622_bananapi_bpi-r64-snand BUILD_DEVICES:=bananapi_bpi-r64 BUILD_SUBTARGET:=mt7622 UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=snand-ubi + BL2_BOOTDEV:=snand BL2_DDRBLOB:=2 - DEPENDS:=+trusted-firmware-a-mt7622-snand-ubi-2ddr + DEPENDS:=+trusted-firmware-a-mt7622-snand-2ddr endef -define U-Boot/mt7622_ubnt_unifi-6-lr-v1 +define U-Boot/mt7622_ubnt_unifi-6-lr NAME:=Ubiquiti UniFi 6 LR - UBOOT_CONFIG:=mt7622_ubnt_unifi-6-lr-v1 - BUILD_DEVICES:=ubnt_unifi-6-lr-v1-ubootmod + UBOOT_CONFIG:=mt7622_ubnt_unifi-6-lr + BUILD_DEVICES:=ubnt_unifi-6-lr-v1-ubootmod ubnt_unifi-6-lr-v2-ubootmod BUILD_SUBTARGET:=mt7622 UBOOT_IMAGE:=u-boot.fip BL2_BOOTDEV:=nor @@ -147,38 +135,6 @@ define U-Boot/mt7622_ubnt_unifi-6-lr-v1 FIP_COMPRESS:=1 endef -define U-Boot/mt7622_ubnt_unifi-6-lr-v2 - NAME:=Ubiquiti UniFi 6 LR v2 - UBOOT_CONFIG:=mt7622_ubnt_unifi-6-lr-v2 - BUILD_DEVICES:=ubnt_unifi-6-lr-v2-ubootmod - BUILD_SUBTARGET:=mt7622 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=nor - BL2_DDRBLOB:=2 - DEPENDS:=+trusted-firmware-a-mt7622-nor-2ddr - FIP_COMPRESS:=1 -endef - -define U-Boot/mt7622_ubnt_unifi-6-lr-v3 - NAME:=Ubiquiti UniFi 6 LR v3 - UBOOT_CONFIG:=mt7622_ubnt_unifi-6-lr-v3 - BUILD_DEVICES:=ubnt_unifi-6-lr-v3-ubootmod - BUILD_SUBTARGET:=mt7622 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=nor - BL2_DDRBLOB:=2 - DEPENDS:=+trusted-firmware-a-mt7622-nor-2ddr - FIP_COMPRESS:=1 -endef - -define U-Boot/mt7622_xiaomi_redmi-router-ax6s-ubi-loader - NAME:=Xiaomi Redmi Router AX6S (as UBI loader) - UBOOT_CONFIG:=mt7622_xiaomi_redmi-router-ax6s-ubi-loader - BUILD_DEVICES:=xiaomi_redmi-router-ax6s - BUILD_SUBTARGET:=mt7622 - UBOOT_IMAGE:=u-boot.bin -endef - define U-Boot/mt7623a_unielec_u7623 NAME:=UniElec U7623 (mt7623) BUILD_DEVICES:=unielec_u7623-02 @@ -203,7 +159,7 @@ define U-Boot/mt7628_rfb UBOOT_IMAGE:=u-boot-with-spl.bin endef -define U-Boot/mt7628_ravpower_rp-wd009 +define U-Boot/ravpower_rp-wd009 NAME:=RAVPower RP-WD009 BUILD_TARGET:=ramips BUILD_DEVICES:=ravpower_rp-wd009 @@ -219,91 +175,6 @@ define U-Boot/mt7629_rfb UBOOT_CONFIG:=mt7629_rfb endef -define U-Boot/mt7981_cmcc_rax3000m-emmc - NAME:=CMCC RAX3000M - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=cmcc_rax3000m - UBOOT_CONFIG:=mt7981_cmcc_rax3000m-emmc - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=emmc - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr4 - DEPENDS:=+trusted-firmware-a-mt7981-emmc-ddr4 -endef - -define U-Boot/mt7981_cmcc_rax3000m-nand - NAME:=CMCC RAX3000M - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=cmcc_rax3000m - UBOOT_CONFIG:=mt7981_cmcc_rax3000m-nand - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr4 - DEPENDS:=+trusted-firmware-a-mt7981-spim-nand-ddr4 -endef - -define U-Boot/mt7981_h3c_magic-nx30-pro - NAME:=H3C Magic NX30 Pro - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=h3c_magic-nx30-pro - UBOOT_CONFIG:=mt7981_h3c_magic-nx30-pro - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7981-spim-nand-ddr3 -endef - -define U-Boot/mt7981_jcg_q30-pro - NAME:=JCG Q30 PRO - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=jcg_q30-pro - UBOOT_CONFIG:=mt7981_jcg_q30-pro - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7981-spim-nand-ddr3 -endef - -define U-Boot/mt7981_nokia_ea0326gmp - NAME:=Nokia EA0326GMP - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=nokia_ea0326gmp - UBOOT_CONFIG:=mt7981_nokia_ea0326gmp - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7981-spim-nand-ddr3 -endef - -define U-Boot/mt7981_openwrt_one-snand - NAME:=OpenWrt One NAND - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=openwrt_one - UBOOT_CONFIG:=mt7981_openwrt-one-spi-nand - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand-ubi - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr4 - DEPENDS:=+trusted-firmware-a-mt7981-spim-nand-ubi-ddr4 -endef - -define U-Boot/mt7981_openwrt_one-nor - NAME:=OpenWrt One NOR - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=openwrt_one - UBOOT_CONFIG:=mt7981_openwrt-one-nor - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=nor - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr4 - FIP_COMPRESS:=1 - DEPENDS:=+trusted-firmware-a-mt7981-nor-ddr4 -endef - define U-Boot/mt7981_rfb-spim-nand NAME:=MT7981 Reference Board BUILD_SUBTARGET:=filogic @@ -364,42 +235,6 @@ define U-Boot/mt7981_rfb-snfi DEPENDS:=+trusted-firmware-a-mt7981-snand-ddr3 endef -define U-Boot/mt7981_qihoo_360t7 - NAME:=Qihoo 360T7 - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=qihoo_360t7 - UBOOT_CONFIG:=mt7981_qihoo-360t7 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7981-spim-nand-ddr3 -endef - -define U-Boot/mt7981_xiaomi_mi-router-ax3000t - NAME:=Xiaomi Router AX3000T - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=xiaomi_mi-router-ax3000t-ubootmod - UBOOT_CONFIG:=mt7981_xiaomi_mi-router-ax3000t - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7981-spim-nand-ddr3 -endef - -define U-Boot/mt7981_xiaomi_mi-router-wr30u - NAME:=Xiaomi Router WR30U - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=xiaomi_mi-router-wr30u-ubootmod - UBOOT_CONFIG:=mt7981_xiaomi_mi-router-wr30u - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7981 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7981-spim-nand-ddr3 -endef - define U-Boot/mt7986_rfb NAME:=MT7986 Reference Board BUILD_SUBTARGET:=filogic @@ -461,126 +296,6 @@ define U-Boot/mt7986_bananapi_bpi-r3-nor FIP_COMPRESS:=1 endef -define U-Boot/mt7986_bananapi_bpi-r3-mini-emmc - NAME:=BananaPi BPi-R3 Mini - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=bananapi_bpi-r3-mini - UBOOT_CONFIG:=mt7986a_bpi-r3-mini-emmc - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=emmc - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr4 - DEPENDS:=+trusted-firmware-a-mt7986-emmc-ddr4 -endef - -define U-Boot/mt7986_bananapi_bpi-r3-mini-snand - NAME:=BananaPi BPi-R3 Mini - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=bananapi_bpi-r3-mini - UBOOT_CONFIG:=mt7986a_bpi-r3-mini-snand - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand-ubi - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr4 - DEPENDS:=+trusted-firmware-a-mt7986-spim-nand-ubi-ddr4 -endef - -define U-Boot/mt7986_glinet_gl-mt6000 - NAME:=GL.iNet GL-MT6000 - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=glinet_gl-mt6000 - UBOOT_CONFIG:=mt7986a_glinet_gl-mt6000 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=emmc - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr4 - DEPENDS:=+trusted-firmware-a-mt7986-emmc-ddr4 -endef - -define U-Boot/mt7986_jdcloud_re-cp-03 - NAME:=JDCloud RE-CP-03 - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=jdcloud_re-cp-03 - UBOOT_CONFIG:=mt7986a_jdcloud_re-cp-03 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=emmc - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr4 - DEPENDS:=+trusted-firmware-a-mt7986-emmc-ddr4 -endef - -define U-Boot/mt7986_netcore_n60 - NAME:=Netcore N60 - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=netcore_n60 - UBOOT_CONFIG:=mt7986_netcore_n60 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7986-spim-nand-ddr3 -endef - -define U-Boot/mt7986_tplink_tl-xdr4288 - NAME:=TP-LINK TL-XDR4288 - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=tplink_tl-xdr4288 - UBOOT_CONFIG:=mt7986_tplink_tl-xdr4288 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7986-spim-nand-ddr3 -endef - -define U-Boot/mt7986_tplink_tl-xdr6086 - NAME:=TP-LINK TL-XDR6086 - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=tplink_tl-xdr6086 - UBOOT_CONFIG:=mt7986_tplink_tl-xdr6086 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7986-spim-nand-ddr3 -endef - -define U-Boot/mt7986_tplink_tl-xdr6088 - NAME:=TP-LINK TL-XDR6088 - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=tplink_tl-xdr6088 - UBOOT_CONFIG:=mt7986_tplink_tl-xdr6088 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr3 - DEPENDS:=+trusted-firmware-a-mt7986-spim-nand-ddr3 -endef - -define U-Boot/mt7986_xiaomi_redmi-router-ax6000 - NAME:=Xiaomi Redmi AX6000 - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=xiaomi_redmi-router-ax6000-ubootmod - UBOOT_CONFIG:=mt7986_xiaomi_redmi-ax6000 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr4 - DEPENDS:=+trusted-firmware-a-mt7986-spim-nand-ddr4 -endef - -define U-Boot/mt7986_zyxel_ex5601-t0 - NAME:=Zyxel EX5601-T0 - BUILD_SUBTARGET:=filogic - BUILD_DEVICES:=zyxel_ex5601-t0-ubootmod - UBOOT_CONFIG:=mt7986_zyxel_ex5601-t0 - UBOOT_IMAGE:=u-boot.fip - BL2_BOOTDEV:=spim-nand-4k - BL2_SOC:=mt7986 - BL2_DDRTYPE:=ddr4 - DEPENDS:=+trusted-firmware-a-mt7986-spim-nand-4k-ddr4 -endef - define U-Boot/mt7988_bananapi_bpi-r4-emmc NAME:=BananaPi BPi-R4 BUILD_SUBTARGET:=filogic @@ -719,50 +434,26 @@ UBOOT_TARGETS := \ mt7620_rfb \ mt7621_nand_rfb \ mt7621_rfb \ - mt7621_zbtlink_zbt-wg3526-16m \ mt7622_bananapi_bpi-r64-emmc \ mt7622_bananapi_bpi-r64-sdmmc \ mt7622_bananapi_bpi-r64-snand \ mt7622_linksys_e8450 \ mt7622_rfb1 \ - mt7622_ubnt_unifi-6-lr-v1 \ - mt7622_ubnt_unifi-6-lr-v2 \ - mt7622_ubnt_unifi-6-lr-v3 \ - mt7622_xiaomi_redmi-router-ax6s-ubi-loader \ + mt7622_ubnt_unifi-6-lr \ mt7623n_bpir2 \ mt7623a_unielec_u7623 \ mt7628_rfb \ mt7628_ravpower_rp-wd009 \ mt7629_rfb \ - mt7981_cmcc_rax3000m-emmc \ - mt7981_cmcc_rax3000m-nand \ - mt7981_h3c_magic-nx30-pro \ - mt7981_jcg_q30-pro \ - mt7981_nokia_ea0326gmp \ - mt7981_openwrt_one-snand \ - mt7981_openwrt_one-nor \ mt7981_rfb-spim-nand \ mt7981_rfb-emmc \ mt7981_rfb-nor \ mt7981_rfb-sd \ mt7981_rfb-snfi \ - mt7981_qihoo_360t7 \ - mt7981_xiaomi_mi-router-ax3000t \ - mt7981_xiaomi_mi-router-wr30u \ mt7986_bananapi_bpi-r3-emmc \ mt7986_bananapi_bpi-r3-sdmmc \ mt7986_bananapi_bpi-r3-snand \ mt7986_bananapi_bpi-r3-nor \ - mt7986_bananapi_bpi-r3-mini-emmc \ - mt7986_bananapi_bpi-r3-mini-snand \ - mt7986_glinet_gl-mt6000 \ - mt7986_jdcloud_re-cp-03 \ - mt7986_netcore_n60 \ - mt7986_tplink_tl-xdr4288 \ - mt7986_tplink_tl-xdr6086 \ - mt7986_tplink_tl-xdr6088 \ - mt7986_xiaomi_redmi-router-ax6000 \ - mt7986_zyxel_ex5601-t0 \ mt7986_rfb \ mt7988_bananapi_bpi-r4-emmc \ mt7988_bananapi_bpi-r4-sdmmc \ diff --git a/lede/package/boot/uboot-mediatek/patches/111-force-pylibfdt-build.patch b/lede/package/boot/uboot-mediatek/patches/111-force-pylibfdt-build.patch new file mode 100644 index 0000000000..e55fad489b --- /dev/null +++ b/lede/package/boot/uboot-mediatek/patches/111-force-pylibfdt-build.patch @@ -0,0 +1,30 @@ +--- a/Makefile ++++ b/Makefile +@@ -2011,26 +2011,7 @@ endif + # Check dtc and pylibfdt, if DTC is provided, else build them + PHONY += scripts_dtc + scripts_dtc: scripts_basic +- $(Q)if test "$(DTC)" = "$(DTC_INTREE)"; then \ +- $(MAKE) $(build)=scripts/dtc; \ +- else \ +- if ! $(DTC) -v >/dev/null; then \ +- echo '*** Failed to check dtc version: $(DTC)'; \ +- false; \ +- else \ +- if test "$(call dtc-version)" -lt $(DTC_MIN_VERSION); then \ +- echo '*** Your dtc is too old, please upgrade to dtc $(DTC_MIN_VERSION) or newer'; \ +- false; \ +- else \ +- if [ -n "$(CONFIG_PYLIBFDT)" ]; then \ +- if ! echo "import libfdt" | $(PYTHON3) 2>/dev/null; then \ +- echo '*** pylibfdt does not seem to be available with $(PYTHON3)'; \ +- false; \ +- fi; \ +- fi; \ +- fi; \ +- fi; \ +- fi ++ $(MAKE) $(build)=scripts/dtc + + # --------------------------------------------------------------------------- + quiet_cmd_cpp_lds = LDS $@ diff --git a/lede/package/boot/uboot-mediatek/patches/160-net-phy-add-support-for-Airoha-ethernet-PHY-driver.patch b/lede/package/boot/uboot-mediatek/patches/160-net-phy-add-support-for-Airoha-ethernet-PHY-driver.patch deleted file mode 100644 index f8e8659952..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/160-net-phy-add-support-for-Airoha-ethernet-PHY-driver.patch +++ /dev/null @@ -1,1929 +0,0 @@ -From 70157a6148ad47734f1dc646b4157ca83cc5df9f Mon Sep 17 00:00:00 2001 -From: Weijie Gao -Date: Thu, 13 Jul 2023 16:34:48 +0800 -Subject: [PATCH] net: phy: add support for Airoha ethernet PHY driver - -This patch adds support for Airoha ethernet PHY driver. - -If GMAC2 of your board connects to Airoha EN8801S, please change the eth -node as follow: - -ð { - status = "okay"; - mediatek,gmac-id = <1>; - mediatek,sgmiisys = <&sgmiisys1>; - phy-mode = "sgmii"; - phy-handle = <&phy5>; - - phy5: eth-phy@5 { - reg = <24>; - }; -}; - -If GMAC2 of your board connects to Airoha EN8811H, please change the eth -node as follow: - -ð { - status = "okay"; - mediatek,gmac-id = <1>; - mediatek,sgmiisys = <&sgmiisys1>; - phy-mode = "2500base-x"; - phy-handle = <&phy5>; - - fixed-link { - speed = <2500>; - full-duplex; - }; - - phy5: eth-phy@5 { - reg = <15>; - }; -}; - -Signed-off-by: Weijie Gao ---- - .../drivers/net/phy/Kconfig | 15 + - .../drivers/net/phy/Makefile | 2 + - .../drivers/net/phy/air_en8801s.c | 633 ++ - .../drivers/net/phy/air_en8801s.h | 267 + - .../drivers/net/phy/air_en8811h.c | 649 ++ - .../drivers/net/phy/air_en8811h.h | 160 + - .../drivers/net/phy/air_en8811h_fw.h | 9227 +++++++++++++++++ - 7 files changed, 10953 insertions(+) - create mode 100644 drivers/net/phy/air_en8801s.c - create mode 100644 drivers/net/phy/air_en8801s.h - create mode 100644 drivers/net/phy/air_en8811h.c - create mode 100644 drivers/net/phy/air_en8811h.h - create mode 100644 drivers/net/phy/air_en8811h_fw.h - ---- a/drivers/net/phy/Kconfig -+++ b/drivers/net/phy/Kconfig -@@ -77,6 +77,37 @@ config PHY_ADIN - help - Add support for configuring RGMII on Analog Devices ADIN PHYs. - -+menuconfig PHY_AIROHA -+ bool "Airoha Ethernet PHYs support" -+ -+config PHY_AIROHA_EN8801S -+ bool "Airoha Ethernet EN8801S support" -+ depends on PHY_AIROHA -+ help -+ AIROHA EN8801S supported. -+ -+config PHY_AIROHA_EN8811H -+ bool "Airoha Ethernet EN8811H support" -+ depends on PHY_AIROHA -+ help -+ AIROHA EN8811H supported. -+ -+choice -+ prompt "Location of the Airoha PHY firmware" -+ default PHY_AIROHA_FW_IN_UBI -+ depends on PHY_AIROHA_EN8811H -+ -+config PHY_AIROHA_FW_IN_MMC -+ bool "Airoha firmware in MMC boot1 partition" -+ -+config PHY_AIROHA_FW_IN_UBI -+ bool "Airoha firmware in UBI volume en8811h-fw on NAND flash" -+ -+config PHY_AIROHA_FW_IN_MTD -+ bool "Airoha firmware in MTD partition on raw flash" -+ -+endchoice -+ - menuconfig PHY_AQUANTIA - bool "Aquantia Ethernet PHYs support" - select PHY_GIGE ---- a/drivers/net/phy/Makefile -+++ b/drivers/net/phy/Makefile -@@ -11,6 +11,8 @@ obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6 - obj-$(CONFIG_PHYLIB) += phy.o - obj-$(CONFIG_PHYLIB_10G) += generic_10g.o - obj-$(CONFIG_PHY_ADIN) += adin.o -+obj-$(CONFIG_PHY_AIROHA_EN8801S) += air_en8801s.o -+obj-$(CONFIG_PHY_AIROHA_EN8811H) += air_en8811h.o - obj-$(CONFIG_PHY_AQUANTIA) += aquantia.o - obj-$(CONFIG_PHY_ATHEROS) += atheros.o - obj-$(CONFIG_PHY_BROADCOM) += broadcom.o ---- /dev/null -+++ b/drivers/net/phy/air_en8801s.c -@@ -0,0 +1,633 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/************************************************* -+ * FILE NAME: air_en8801s.c -+ * PURPOSE: -+ * EN8801S PHY Driver for Uboot -+ * NOTES: -+ * -+ * Copyright (C) 2023 Airoha Technology Corp. -+ *************************************************/ -+ -+/* INCLUDE FILE DECLARATIONS -+ */ -+#include -+#include -+#include -+#include -+#include "air_en8801s.h" -+ -+#if AIR_UBOOT_REVISION > 0x202004 -+#include -+#endif -+ -+static struct phy_device *s_phydev = 0; -+/****************************************************** -+ * The following led_cfg example is for reference only. -+ * LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0, -+ * LED6 10/100M/LINK/ACT (GPIO9) <-> BASE_T_LED1, -+ * LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2, -+ ******************************************************/ -+/* User-defined.B */ -+#define AIR_LED_SUPPORT -+#ifdef AIR_LED_SUPPORT -+static const AIR_BASE_T_LED_CFG_T led_cfg[4] = -+{ -+ /* -+ * LED Enable, GPIO, LED Polarity, LED ON, LED Blink -+ */ -+ {LED_ENABLE, 5, AIR_ACTIVE_LOW, BASE_T_LED0_ON_CFG, BASE_T_LED0_BLK_CFG}, /* BASE-T LED0 */ -+ {LED_ENABLE, 9, AIR_ACTIVE_LOW, BASE_T_LED1_ON_CFG, BASE_T_LED1_BLK_CFG}, /* BASE-T LED1 */ -+ {LED_ENABLE, 8, AIR_ACTIVE_LOW, BASE_T_LED2_ON_CFG, BASE_T_LED2_BLK_CFG}, /* BASE-T LED2 */ -+ {LED_DISABLE, 1, AIR_ACTIVE_LOW, BASE_T_LED3_ON_CFG, BASE_T_LED3_BLK_CFG} /* BASE-T LED3 */ -+}; -+static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M; -+#endif -+/* User-defined.E */ -+/************************************************************************ -+ * F U N C T I O N S -+ ************************************************************************/ -+/* Airoha MII read function */ -+static int airoha_cl22_read(struct mii_dev *bus, int phy_addr, int phy_register) -+{ -+ int read_data = bus->read(bus, phy_addr, MDIO_DEVAD_NONE, phy_register); -+ -+ if (read_data < 0) -+ return -EIO; -+ return read_data; -+} -+ -+/* Airoha MII write function */ -+static int airoha_cl22_write(struct mii_dev *bus, int phy_addr, int phy_register, int write_data) -+{ -+ int ret = bus->write(bus, phy_addr, MDIO_DEVAD_NONE, phy_register, write_data); -+ -+ return ret; -+} -+ -+static int airoha_cl45_write(struct phy_device *phydev, int devad, int reg, int val) -+{ -+ int ret = 0; -+ -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, devad); -+ AIR_RTN_ERR(ret); -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, reg); -+ AIR_RTN_ERR(ret); -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); -+ AIR_RTN_ERR(ret); -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, val); -+ AIR_RTN_ERR(ret); -+ return ret; -+} -+ -+static int airoha_cl45_read(struct phy_device *phydev, int devad, int reg) -+{ -+ int read_data, ret; -+ -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, devad); -+ AIR_RTN_ERR(ret); -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, reg); -+ AIR_RTN_ERR(ret); -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); -+ AIR_RTN_ERR(ret); -+ read_data = phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG); -+ if (read_data < 0) -+ return -EIO; -+ return read_data; -+} -+ -+/* EN8801 PBUS write function */ -+int airoha_pbus_write(struct mii_dev *bus, int pbus_addr, int pbus_reg, unsigned long pbus_data) -+{ -+ int ret = 0; -+ -+ ret = airoha_cl22_write(bus, pbus_addr, 0x1F, (pbus_reg >> 6)); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl22_write(bus, pbus_addr, ((pbus_reg >> 2) & 0xf), (pbus_data & 0xFFFF)); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl22_write(bus, pbus_addr, 0x10, (pbus_data >> 16)); -+ AIR_RTN_ERR(ret); -+ return ret; -+} -+ -+/* EN8801 PBUS read function */ -+unsigned long airoha_pbus_read(struct mii_dev *bus, int pbus_addr, int pbus_reg) -+{ -+ unsigned long pbus_data; -+ unsigned int pbus_data_low, pbus_data_high; -+ -+ airoha_cl22_write(bus, pbus_addr, 0x1F, (pbus_reg >> 6)); -+ pbus_data_low = airoha_cl22_read(bus, pbus_addr, ((pbus_reg >> 2) & 0xf)); -+ pbus_data_high = airoha_cl22_read(bus, pbus_addr, 0x10); -+ pbus_data = (pbus_data_high << 16) + pbus_data_low; -+ return pbus_data; -+} -+ -+/* Airoha Token Ring Write function */ -+static int airoha_tr_reg_write(struct phy_device *phydev, unsigned long tr_address, unsigned long tr_data) -+{ -+ int ret; -+ -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, 0x52b5); /* page select */ -+ AIR_RTN_ERR(ret); -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x11, (int)(tr_data & 0xffff)); -+ AIR_RTN_ERR(ret); -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x12, (int)(tr_data >> 16)); -+ AIR_RTN_ERR(ret); -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x10, (int)(tr_address | TrReg_WR)); -+ AIR_RTN_ERR(ret); -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, 0x0); /* page resetore */ -+ AIR_RTN_ERR(ret); -+ return ret; -+} -+ -+int airoha_phy_process(void) -+{ -+ int ret = 0, pbus_addr = EN8801S_PBUS_PHY_ID; -+ unsigned long pbus_data; -+ struct mii_dev *mbus; -+ -+ mbus = s_phydev->bus; -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19e0); -+ pbus_data |= BIT(0); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, pbus_data); -+ if(ret) -+ printf("error: airoha_pbus_write fail ret: %d\n", ret); -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19e0); -+ pbus_data &= ~BIT(0); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, pbus_data); -+ if(ret) -+ printf("error: airoha_pbus_write fail ret: %d\n", ret); -+ -+ if(ret) -+ printf("error: FCM regs reset fail, ret: %d\n", ret); -+ else -+ debug("FCM regs reset successful\n"); -+ return ret; -+} -+ -+#ifdef AIR_LED_SUPPORT -+static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity, int polar, -+ u16 on_evt, u16 blk_evt) -+{ -+ int ret = 0; -+ -+ if (AIR_ACTIVE_HIGH == polar) { -+ on_evt |= LED_ON_POL; -+ } else { -+ on_evt &= ~LED_ON_POL; -+ } -+ ret = airoha_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), on_evt | LED_ON_EN); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt); -+ AIR_RTN_ERR(ret); -+ return 0; -+} -+ -+static int airoha_led_set_mode(struct phy_device *phydev, u8 mode) -+{ -+ u16 cl45_data; -+ int err = 0; -+ -+ cl45_data = airoha_cl45_read(phydev, 0x1f, LED_BCR); -+ switch (mode) { -+ case AIR_LED_MODE_DISABLE: -+ cl45_data &= ~LED_BCR_EXT_CTRL; -+ cl45_data &= ~LED_BCR_MODE_MASK; -+ cl45_data |= LED_BCR_MODE_DISABLE; -+ break; -+ case AIR_LED_MODE_USER_DEFINE: -+ cl45_data |= LED_BCR_EXT_CTRL; -+ cl45_data |= LED_BCR_CLK_EN; -+ break; -+ default: -+ printf("LED mode%d is not supported!\n", mode); -+ return -EINVAL; -+ } -+ err = airoha_cl45_write(phydev, 0x1f, LED_BCR, cl45_data); -+ AIR_RTN_ERR(err); -+ return 0; -+} -+ -+static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state) -+{ -+ u16 cl45_data; -+ int err; -+ -+ cl45_data = airoha_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity)); -+ if (LED_ENABLE == state) { -+ cl45_data |= LED_ON_EN; -+ } else { -+ cl45_data &= ~LED_ON_EN; -+ } -+ -+ err = airoha_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), cl45_data); -+ AIR_RTN_ERR(err); -+ return 0; -+} -+ -+static int en8801s_led_init(struct phy_device *phydev) -+{ -+ -+ unsigned long led_gpio = 0, reg_value = 0; -+ int ret = 0, led_id; -+ struct mii_dev *mbus = phydev->bus; -+ int gpio_led_rg[3] = {0x1870, 0x1874, 0x1878}; -+ u16 cl45_data = led_dur; -+ -+ ret = airoha_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data); -+ AIR_RTN_ERR(ret); -+ cl45_data >>= 1; -+ ret = airoha_cl45_write(phydev, 0x1f, LED_ON_DUR, cl45_data); -+ AIR_RTN_ERR(ret); -+ ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE); -+ if (ret != 0) { -+ printf("LED fail to set mode, ret %d !\n", ret); -+ return ret; -+ } -+ for(led_id = 0; led_id < EN8801S_LED_COUNT; led_id++) { -+ reg_value = 0; -+ ret = airoha_led_set_state(phydev, led_id, led_cfg[led_id].en); -+ if (ret != 0) { -+ printf("LED fail to set state, ret %d !\n", ret); -+ return ret; -+ } -+ if (LED_ENABLE == led_cfg[led_id].en) { -+ if ( (led_cfg[led_id].gpio < 0) || led_cfg[led_id].gpio > 9) { -+ printf("GPIO%d is out of range!! GPIO number is 0~9.\n", led_cfg[led_id].gpio); -+ return -EIO; -+ } -+ led_gpio |= BIT(led_cfg[led_id].gpio); -+ reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, gpio_led_rg[led_cfg[led_id].gpio / 4]); -+ LED_SET_GPIO_SEL(led_cfg[led_id].gpio, led_id, reg_value); -+ debug("[Airoha] gpio%d, reg_value 0x%lx\n", led_cfg[led_id].gpio, reg_value); -+ ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, gpio_led_rg[led_cfg[led_id].gpio / 4], reg_value); -+ AIR_RTN_ERR(ret); -+ ret = airoha_led_set_usr_def(phydev, led_id, led_cfg[led_id].pol, led_cfg[led_id].on_cfg, led_cfg[led_id].blk_cfg); -+ if (ret != 0) { -+ printf("LED fail to set usr def, ret %d !\n", ret); -+ return ret; -+ } -+ } -+ } -+ reg_value = (airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1880) & ~led_gpio); -+ ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1880, reg_value); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x186c, led_gpio); -+ AIR_RTN_ERR(ret); -+ -+ printf("LED initialize OK !\n"); -+ return 0; -+} -+#endif /* AIR_LED_SUPPORT */ -+ -+static int en8801s_config(struct phy_device *phydev) -+{ -+ int reg_value = 0, ret = 0; -+ struct mii_dev *mbus = phydev->bus; -+ int retry, pbus_addr = EN8801S_PBUS_DEFAULT_ID; -+ int phy_addr = EN8801S_MDIO_PHY_ID; -+ unsigned long pbus_data = 0; -+ gephy_all_REG_LpiReg1Ch GPHY_RG_LPI_1C; -+ gephy_all_REG_dev1Eh_reg324h GPHY_RG_1E_324; -+ gephy_all_REG_dev1Eh_reg012h GPHY_RG_1E_012; -+ gephy_all_REG_dev1Eh_reg017h GPHY_RG_1E_017; -+ -+ s_phydev = phydev; -+ retry = MAX_OUI_CHECK; -+ while (1) { -+ /* PHY OUI */ -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_ETHER_PHY_OUI); -+ if (EN8801S_PBUS_OUI == pbus_data) { -+ printf("PBUS addr 0x%x: Start initialized.\n", pbus_addr); -+ ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_BUCK_CTL, 0x03); -+ AIR_RTN_ERR(ret); -+ break; -+ } else -+ pbus_addr = EN8801S_PBUS_PHY_ID; -+ -+ if (0 == --retry) { -+ printf("EN8801S Probe fail !\n"); -+ return 0; -+ } -+ } -+ -+ /* SMI ADDR */ -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_SMI_ADDR); -+ pbus_data = (pbus_data & 0xffff0000) | (unsigned long)(pbus_addr << 8) | (unsigned long)(EN8801S_MDIO_DEFAULT_ID); -+ ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_SMI_ADDR, pbus_data); -+ AIR_RTN_ERR(ret); -+ mdelay(10); -+ -+ pbus_data = (airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_LTR_CTL) & (~0x3)) | BIT(2) ; -+ ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_LTR_CTL, pbus_data); -+ AIR_RTN_ERR(ret); -+ mdelay(500); -+ pbus_data = (pbus_data & ~BIT(2)) | EN8801S_RX_POLARITY_NORMAL | EN8801S_TX_POLARITY_NORMAL; -+ ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_LTR_CTL, pbus_data); -+ AIR_RTN_ERR(ret); -+ mdelay(500); -+ /* SMI ADDR */ -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_SMI_ADDR); -+ pbus_data = (pbus_data & 0xffff0000) | (unsigned long)(EN8801S_PBUS_PHY_ID << 8) | (unsigned long)(EN8801S_MDIO_PHY_ID); -+ ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_SMI_ADDR, pbus_data); -+ pbus_addr = EN8801S_PBUS_PHY_ID; -+ AIR_RTN_ERR(ret); -+ mdelay(10); -+ -+ /* Optimze 10M IoT */ -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1690); -+ pbus_data |= (1 << 31); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1690, pbus_data); -+ AIR_RTN_ERR(ret); -+ /* set SGMII Base Page */ -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD801); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0003); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); -+ AIR_RTN_ERR(ret); -+ /* Set FCM control */ -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x004b); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007); -+ AIR_RTN_ERR(ret); -+ -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x142c, 0x05050505); -+ AIR_RTN_ERR(ret); -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1440); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1440, pbus_data & ~BIT(11)); -+ AIR_RTN_ERR(ret); -+ -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1408); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1408, pbus_data | BIT(5)); -+ AIR_RTN_ERR(ret); -+ -+ /* Set GPHY Perfomance*/ -+ /* Token Ring */ -+ ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_15h, 0x0055A0); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_17h, 0x07FF3F); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_00h, 0x00001E); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_01h, 0x6FB90A); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_17h, 0x060671); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_18h, 0x0E2F00); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_TR_26h, 0x444444); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_03h, 0x000000); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_06h, 0x2EBAEF); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_08h, 0x00000B); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Ch, 0x00504D); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Dh, 0x02314F); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Fh, 0x003028); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_10h, 0x005010); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_11h, 0x040001); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_13h, 0x018670); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_14h, 0x00024A); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Bh, 0x000072); -+ AIR_RTN_ERR(ret); -+ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Ch, 0x003210); -+ AIR_RTN_ERR(ret); -+ /* CL22 & CL45 */ -+ ret = airoha_cl22_write(mbus, phy_addr, 0x1f, 0x03); -+ AIR_RTN_ERR(ret); -+ GPHY_RG_LPI_1C.DATA = airoha_cl22_read(mbus, phy_addr, RgAddr_LPI_1Ch); -+ if (GPHY_RG_LPI_1C.DATA < 0) -+ return -EIO; -+ GPHY_RG_LPI_1C.DataBitField.smi_deton_th = 0x0C; -+ ret = airoha_cl22_write(mbus, phy_addr, RgAddr_LPI_1Ch, GPHY_RG_LPI_1C.DATA); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl22_write(mbus, phy_addr, RgAddr_LPI_1Ch, 0xC92); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl22_write(mbus, phy_addr, RgAddr_AUXILIARY_1Dh, 0x1); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl22_write(mbus, phy_addr, 0x1f, 0x0); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x120, 0x8014); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x122, 0xffff); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x123, 0xffff); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x144, 0x0200); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x14A, 0xEE20); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x189, 0x0110); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x19B, 0x0111); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x234, 0x0181); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x238, 0x0120); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x239, 0x0117); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x268, 0x07F4); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x2D1, 0x0733); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x323, 0x0011); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x324, 0x013F); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x326, 0x0037); -+ AIR_RTN_ERR(ret); -+ -+ reg_value = airoha_cl45_read(phydev, 0x1E, 0x324); -+ if (reg_value < 0) -+ return -EIO; -+ GPHY_RG_1E_324.DATA = (int)reg_value; -+ GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = 0; -+ ret = airoha_cl45_write(phydev, 0x1E, 0x324, GPHY_RG_1E_324.DATA); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x19E, 0xC2); -+ AIR_RTN_ERR(ret); -+ ret = airoha_cl45_write(phydev, 0x1E, 0x013, 0x0); -+ AIR_RTN_ERR(ret); -+ -+ /* EFUSE */ -+ airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40000040); -+ retry = MAX_RETRY; -+ while (0 != retry) { -+ mdelay(1); -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08); -+ if ((pbus_data & (1 << 30)) == 0) { -+ break; -+ } -+ retry--; -+ } -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C38); /* RAW#2 */ -+ reg_value = airoha_cl45_read(phydev, 0x1E, 0x12); -+ if (reg_value < 0) -+ return -EIO; -+ GPHY_RG_1E_012.DATA = reg_value; -+ GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt = pbus_data & 0x03f; -+ ret = airoha_cl45_write(phydev, 0x1E, 0x12, GPHY_RG_1E_012.DATA); -+ AIR_RTN_ERR(ret); -+ reg_value = airoha_cl45_read(phydev, 0x1E, 0x17); -+ if (reg_value < 0) -+ return -EIO; -+ GPHY_RG_1E_017.DataBitField.da_tx_i2mpb_b_tbt = (reg_value >> 8) & 0x03f; -+ ret = airoha_cl45_write(phydev, 0x1E, 0x17, GPHY_RG_1E_017.DATA); -+ AIR_RTN_ERR(ret); -+ -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40400040); -+ AIR_RTN_ERR(ret); -+ retry = MAX_RETRY; -+ while (0 != retry) { -+ mdelay(1); -+ reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1C08); -+ if ((reg_value & (1 << 30)) == 0) { -+ break; -+ } -+ retry--; -+ } -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C30); /* RAW#16 */ -+ GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = (pbus_data >> 12) & 0x01; -+ ret = airoha_cl45_write(phydev, 0x1E, 0x324, GPHY_RG_1E_324.DATA); -+ AIR_RTN_ERR(ret); -+#ifdef AIR_LED_SUPPORT -+ ret = en8801s_led_init(phydev); -+ if (ret != 0){ -+ printf("en8801s_led_init fail (ret:%d) !\n", ret); -+ } -+#endif -+ printf("EN8801S initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION); -+ return 0; -+} -+ -+int en8801s_read_status(struct phy_device *phydev) -+{ -+ int ret, pbus_addr = EN8801S_PBUS_PHY_ID; -+ struct mii_dev *mbus; -+ unsigned long pbus_data; -+ -+ mbus = phydev->bus; -+ if (SPEED_10 == phydev->speed) { -+ /* set the bit for Optimze 10M IoT */ -+ debug("[Airoha] SPEED_10 0x1694\n"); -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1694); -+ pbus_data |= (1 << 31); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, pbus_data); -+ AIR_RTN_ERR(ret); -+ } else { -+ debug("[Airoha] SPEED_1000/100 0x1694\n"); -+ /* clear the bit for other speeds */ -+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1694); -+ pbus_data &= ~(1 << 31); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, pbus_data); -+ AIR_RTN_ERR(ret); -+ } -+ -+ airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); -+ if(SPEED_1000 == phydev->speed) { -+ debug("[Airoha] SPEED_1000\n"); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD801); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140); -+ AIR_RTN_ERR(ret); -+ -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0003); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); -+ AIR_RTN_ERR(ret); -+ mdelay(2); /* delay 2 ms */ -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x004b); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007); -+ AIR_RTN_ERR(ret); -+ } -+ else if (SPEED_100 == phydev->speed) { -+ debug("[Airoha] SPEED_100\n"); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD401); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0007); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c11); -+ AIR_RTN_ERR(ret); -+ mdelay(2); /* delay 2 ms */ -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x0027); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007); -+ AIR_RTN_ERR(ret); -+ } -+ else { -+ debug("[Airoha] SPEED_10\n"); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD001); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140); -+ AIR_RTN_ERR(ret); -+ -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x000b); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c11); -+ AIR_RTN_ERR(ret); -+ mdelay(2); /* delay 2 ms */ -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x0047); -+ AIR_RTN_ERR(ret); -+ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007); -+ AIR_RTN_ERR(ret); -+ } -+ return 0; -+} -+ -+static int en8801s_startup(struct phy_device *phydev) -+{ -+ int ret; -+ -+ ret = genphy_update_link(phydev); -+ if (ret) -+ return ret; -+ ret = genphy_parse_link(phydev); -+ if (ret) -+ return ret; -+ return en8801s_read_status(phydev); -+} -+#if AIR_UBOOT_REVISION > 0x202303 -+U_BOOT_PHY_DRIVER(en8801s) = { -+ .name = "Airoha EN8801S", -+ .uid = EN8801S_PHY_ID, -+ .mask = 0x0ffffff0, -+ .features = PHY_GBIT_FEATURES, -+ .config = &en8801s_config, -+ .startup = &en8801s_startup, -+ .shutdown = &genphy_shutdown, -+}; -+#else -+static struct phy_driver AIR_EN8801S_driver = { -+ .name = "Airoha EN8801S", -+ .uid = EN8801S_PHY_ID, -+ .mask = 0x0ffffff0, -+ .features = PHY_GBIT_FEATURES, -+ .config = &en8801s_config, -+ .startup = &en8801s_startup, -+ .shutdown = &genphy_shutdown, -+}; -+ -+int phy_air_en8801s_init(void) -+{ -+ phy_register(&AIR_EN8801S_driver); -+ return 0; -+} -+#endif ---- /dev/null -+++ b/drivers/net/phy/air_en8801s.h -@@ -0,0 +1,267 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/************************************************* -+ * FILE NAME: air_en8801s.h -+ * PURPOSE: -+ * EN8801S PHY Driver for Uboot -+ * NOTES: -+ * -+ * Copyright (C) 2023 Airoha Technology Corp. -+ *************************************************/ -+ -+#ifndef __EN8801S_H -+#define __EN8801S_H -+ -+/************************************************************************ -+* D E F I N E S -+************************************************************************/ -+#define AIR_UBOOT_REVISION ((((U_BOOT_VERSION_NUM / 1000) % 10) << 20) | \ -+ (((U_BOOT_VERSION_NUM / 100) % 10) << 16) | \ -+ (((U_BOOT_VERSION_NUM / 10) % 10) << 12) | \ -+ ((U_BOOT_VERSION_NUM % 10) << 8) | \ -+ (((U_BOOT_VERSION_NUM_PATCH / 10) % 10) << 4) | \ -+ ((U_BOOT_VERSION_NUM_PATCH % 10) << 0)) -+ -+#define EN8801S_MDIO_DEFAULT_ID 0x1d -+#define EN8801S_PBUS_DEFAULT_ID (EN8801S_MDIO_DEFAULT_ID + 1) -+#define EN8801S_MDIO_PHY_ID 0x18 /* Range PHY_ADDRESS_RANGE .. 0x1e */ -+#define EN8801S_PBUS_PHY_ID (EN8801S_MDIO_PHY_ID + 1) -+#define EN8801S_DRIVER_VERSION "v1.1.3" -+ -+#define EN8801S_RG_ETHER_PHY_OUI 0x19a4 -+#define EN8801S_RG_SMI_ADDR 0x19a8 -+#define EN8801S_PBUS_OUI 0x17a5 -+#define EN8801S_RG_BUCK_CTL 0x1a20 -+#define EN8801S_RG_LTR_CTL 0x0cf8 -+ -+#define EN8801S_PHY_ID1 0x03a2 -+#define EN8801S_PHY_ID2 0x9461 -+#define EN8801S_PHY_ID (unsigned long)((EN8801S_PHY_ID1 << 16) | EN8801S_PHY_ID2) -+ -+/* -+SFP Sample for verification -+Tx Reverse, Rx Reverse -+*/ -+#define EN8801S_TX_POLARITY_NORMAL 0x0 -+#define EN8801S_TX_POLARITY_REVERSE 0x1 -+ -+#define EN8801S_RX_POLARITY_NORMAL (0x1 << 1) -+#define EN8801S_RX_POLARITY_REVERSE (0x0 << 1) -+ -+#ifndef BIT -+#define BIT(nr) (1UL << (nr)) -+#endif -+ -+#define MAX_RETRY 5 -+#define MAX_OUI_CHECK 2 -+ -+/* CL45 MDIO control */ -+#define MII_MMD_ACC_CTL_REG 0x0d -+#define MII_MMD_ADDR_DATA_REG 0x0e -+#define MMD_OP_MODE_DATA BIT(14) -+ -+#define MAX_TRG_COUNTER 5 -+ -+/* TokenRing Reg Access */ -+#define TrReg_PKT_XMT_STA 0x8000 -+#define TrReg_WR 0x8000 -+#define TrReg_RD 0xA000 -+ -+#define RgAddr_LPI_1Ch 0x1c -+#define RgAddr_AUXILIARY_1Dh 0x1d -+#define RgAddr_PMA_00h 0x0f80 -+#define RgAddr_PMA_01h 0x0f82 -+#define RgAddr_PMA_17h 0x0fae -+#define RgAddr_PMA_18h 0x0fb0 -+#define RgAddr_DSPF_03h 0x1686 -+#define RgAddr_DSPF_06h 0x168c -+#define RgAddr_DSPF_08h 0x1690 -+#define RgAddr_DSPF_0Ch 0x1698 -+#define RgAddr_DSPF_0Dh 0x169a -+#define RgAddr_DSPF_0Fh 0x169e -+#define RgAddr_DSPF_10h 0x16a0 -+#define RgAddr_DSPF_11h 0x16a2 -+#define RgAddr_DSPF_13h 0x16a6 -+#define RgAddr_DSPF_14h 0x16a8 -+#define RgAddr_DSPF_1Bh 0x16b6 -+#define RgAddr_DSPF_1Ch 0x16b8 -+#define RgAddr_TR_26h 0x0ecc -+#define RgAddr_R1000DEC_15h 0x03aa -+#define RgAddr_R1000DEC_17h 0x03ae -+ -+/* -+The following led_cfg example is for reference only. -+LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0, -+LED6 10/100M/LINK/ACT(GPIO9) <-> BASE_T_LED1, -+LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2, -+*/ -+/* User-defined.B */ -+#define BASE_T_LED0_ON_CFG (LED_ON_EVT_LINK_1000M) -+#define BASE_T_LED0_BLK_CFG (LED_BLK_EVT_1000M_TX_ACT | LED_BLK_EVT_1000M_RX_ACT) -+#define BASE_T_LED1_ON_CFG (LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M) -+#define BASE_T_LED1_BLK_CFG (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT | \ -+ LED_BLK_EVT_10M_TX_ACT | LED_BLK_EVT_10M_RX_ACT ) -+#define BASE_T_LED2_ON_CFG (LED_ON_EVT_LINK_100M) -+#define BASE_T_LED2_BLK_CFG (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT) -+#define BASE_T_LED3_ON_CFG (0x0) -+#define BASE_T_LED3_BLK_CFG (0x0) -+/* User-defined.E */ -+ -+#define EN8801S_LED_COUNT 4 -+ -+#define LED_BCR (0x021) -+#define LED_BCR_EXT_CTRL (1 << 15) -+#define LED_BCR_CLK_EN (1 << 3) -+#define LED_BCR_TIME_TEST (1 << 2) -+#define LED_BCR_MODE_MASK (3) -+#define LED_BCR_MODE_DISABLE (0) -+#define LED_ON_CTRL(i) (0x024 + ((i)*2)) -+#define LED_ON_EN (1 << 15) -+#define LED_ON_POL (1 << 14) -+#define LED_ON_EVT_MASK (0x7f) -+/* LED ON Event Option.B */ -+#define LED_ON_EVT_FORCE (1 << 6) -+#define LED_ON_EVT_LINK_DOWN (1 << 3) -+#define LED_ON_EVT_LINK_10M (1 << 2) -+#define LED_ON_EVT_LINK_100M (1 << 1) -+#define LED_ON_EVT_LINK_1000M (1 << 0) -+/* LED ON Event Option.E */ -+#define LED_BLK_CTRL(i) (0x025 + ((i)*2)) -+#define LED_BLK_EVT_MASK (0x3ff) -+/* LED Blinking Event Option.B*/ -+#define LED_BLK_EVT_FORCE (1 << 9) -+#define LED_BLK_EVT_10M_RX_ACT (1 << 5) -+#define LED_BLK_EVT_10M_TX_ACT (1 << 4) -+#define LED_BLK_EVT_100M_RX_ACT (1 << 3) -+#define LED_BLK_EVT_100M_TX_ACT (1 << 2) -+#define LED_BLK_EVT_1000M_RX_ACT (1 << 1) -+#define LED_BLK_EVT_1000M_TX_ACT (1 << 0) -+/* LED Blinking Event Option.E*/ -+#define LED_ON_DUR (0x022) -+#define LED_ON_DUR_MASK (0xffff) -+#define LED_BLK_DUR (0x023) -+#define LED_BLK_DUR_MASK (0xffff) -+ -+#define LED_ENABLE 1 -+#define LED_DISABLE 0 -+ -+#define UNIT_LED_BLINK_DURATION 1024 -+ -+#define AIR_RTN_ON_ERR(cond, err) \ -+ do { if ((cond)) return (err); } while(0) -+ -+#define AIR_RTN_ERR(err) AIR_RTN_ON_ERR(err < 0, err) -+ -+#define LED_SET_EVT(reg, cod, result, bit) do \ -+ { \ -+ if(reg & cod) { \ -+ result |= bit; \ -+ } \ -+ } while(0) -+ -+#define LED_SET_GPIO_SEL(gpio, led, val) do \ -+ { \ -+ val |= (led << (8 * (gpio % 4))); \ -+ } while(0) -+ -+/* DATA TYPE DECLARATIONS -+ */ -+typedef struct -+{ -+ int DATA_Lo; -+ int DATA_Hi; -+}TR_DATA_T; -+ -+typedef union -+{ -+ struct -+ { -+ /* b[15:00] */ -+ int smi_deton_wt : 3; -+ int smi_det_mdi_inv : 1; -+ int smi_detoff_wt : 3; -+ int smi_sigdet_debouncing_en : 1; -+ int smi_deton_th : 6; -+ int rsv_14 : 2; -+ } DataBitField; -+ int DATA; -+} gephy_all_REG_LpiReg1Ch, *Pgephy_all_REG_LpiReg1Ch; -+ -+typedef union -+{ -+ struct -+ { -+ /* b[15:00] */ -+ int rg_smi_detcnt_max : 6; -+ int rsv_6 : 2; -+ int rg_smi_det_max_en : 1; -+ int smi_det_deglitch_off : 1; -+ int rsv_10 : 6; -+ } DataBitField; -+ int DATA; -+} gephy_all_REG_dev1Eh_reg324h, *Pgephy_all_REG_dev1Eh_reg324h; -+ -+typedef union -+{ -+ struct -+ { -+ /* b[15:00] */ -+ int da_tx_i2mpb_a_tbt : 6; -+ int rsv_6 : 4; -+ int da_tx_i2mpb_a_gbe : 6; -+ } DataBitField; -+ int DATA; -+} gephy_all_REG_dev1Eh_reg012h, *Pgephy_all_REG_dev1Eh_reg012h; -+ -+typedef union -+{ -+ struct -+ { -+ /* b[15:00] */ -+ int da_tx_i2mpb_b_tbt : 6; -+ int rsv_6 : 2; -+ int da_tx_i2mpb_b_gbe : 6; -+ int rsv_14 : 2; -+ } DataBitField; -+ int DATA; -+} gephy_all_REG_dev1Eh_reg017h, *Pgephy_all_REG_dev1Eh_reg017h; -+ -+typedef struct AIR_BASE_T_LED_CFG_S -+{ -+ u16 en; -+ u16 gpio; -+ u16 pol; -+ u16 on_cfg; -+ u16 blk_cfg; -+}AIR_BASE_T_LED_CFG_T; -+ -+typedef enum -+{ -+ AIR_LED_BLK_DUR_32M, -+ AIR_LED_BLK_DUR_64M, -+ AIR_LED_BLK_DUR_128M, -+ AIR_LED_BLK_DUR_256M, -+ AIR_LED_BLK_DUR_512M, -+ AIR_LED_BLK_DUR_1024M, -+ AIR_LED_BLK_DUR_LAST -+} AIR_LED_BLK_DUT_T; -+ -+typedef enum -+{ -+ AIR_ACTIVE_LOW, -+ AIR_ACTIVE_HIGH, -+} AIR_LED_POLARITY; -+typedef enum -+{ -+ AIR_LED_MODE_DISABLE, -+ AIR_LED_MODE_USER_DEFINE, -+ AIR_LED_MODE_LAST -+} AIR_LED_MODE_T; -+ -+/************************************************************************ -+* F U N C T I O N P R O T O T Y P E S -+************************************************************************/ -+ -+unsigned long airoha_pbus_read(struct mii_dev *bus, int pbus_addr, int pbus_reg); -+int airoha_pbus_write(struct mii_dev *bus, int pbus_addr, int pbus_reg, unsigned long pbus_data); -+int airoha_phy_process(void); -+#endif /* __EN8801S_H */ ---- /dev/null -+++ b/drivers/net/phy/air_en8811h.c -@@ -0,0 +1,725 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/************************************************* -+ * FILE NAME: air_en8811h.c -+ * PURPOSE: -+ * EN8811H PHY Driver for Uboot -+ * NOTES: -+ * -+ * Copyright (C) 2023 Airoha Technology Corp. -+ *************************************************/ -+ -+/* INCLUDE FILE DECLARATIONS -+*/ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "air_en8811h.h" -+ -+#ifdef CONFIG_PHY_AIROHA_FW_IN_UBI -+#include -+#endif -+ -+#ifdef CONFIG_PHY_AIROHA_FW_IN_MMC -+#include -+#endif -+ -+#ifdef CONFIG_PHY_AIROHA_FW_IN_MTD -+#include -+#endif -+ -+#if AIR_UBOOT_REVISION > 0x202004 -+#include -+#endif -+ -+/************************** -+ * GPIO5 <-> BASE_T_LED0, -+ * GPIO4 <-> BASE_T_LED1, -+ * GPIO3 <-> BASE_T_LED2, -+ **************************/ -+/* User-defined.B */ -+#define AIR_LED_SUPPORT -+#ifdef AIR_LED_SUPPORT -+static const struct air_base_t_led_cfg_s led_cfg[3] = { -+/********************************************************************* -+ *Enable, GPIO, LED Polarity, LED ON, LED Blink -+**********************************************************************/ -+ {1, AIR_LED0_GPIO5, AIR_ACTIVE_HIGH, AIR_LED0_ON, AIR_LED0_BLK}, -+ {1, AIR_LED1_GPIO4, AIR_ACTIVE_HIGH, AIR_LED1_ON, AIR_LED1_BLK}, -+ {1, AIR_LED2_GPIO3, AIR_ACTIVE_HIGH, AIR_LED2_ON, AIR_LED2_BLK}, -+}; -+static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M; -+#endif -+/* User-defined.E */ -+/************************************************************* -+ * F U N C T I O N S -+ **************************************************************/ -+/* Airoha MII read function */ -+static int air_mii_cl22_read(struct mii_dev *bus, int phy_addr, int phy_register) -+{ -+ int read_data = bus->read(bus, phy_addr, MDIO_DEVAD_NONE, phy_register); -+ -+ if (read_data < 0) -+ return -EIO; -+ return read_data; -+} -+ -+/* Airoha MII write function */ -+static int air_mii_cl22_write(struct mii_dev *bus, int phy_addr, int phy_register, int write_data) -+{ -+ int ret = 0; -+ -+ ret = bus->write(bus, phy_addr, MDIO_DEVAD_NONE, phy_register, write_data); -+ if (ret < 0) { -+ printf("bus->write, ret: %d\n", ret); -+ return ret; -+ } -+ return ret; -+} -+ -+static int air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg) -+{ -+ int ret = 0; -+ int data; -+ -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, devad); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return INVALID_DATA; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, reg); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return INVALID_DATA; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return INVALID_DATA; -+ } -+ data = phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG); -+ return data; -+} -+ -+static int air_mii_cl45_write(struct phy_device *phydev, int devad, u16 reg, u16 write_data) -+{ -+ int ret = 0; -+ -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, devad); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, reg); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, write_data); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ return 0; -+} -+/* Use default PBUS_PHY_ID */ -+/* EN8811H PBUS write function */ -+static int air_pbus_reg_write(struct phy_device *phydev, unsigned long pbus_address, unsigned long pbus_data) -+{ -+ int ret = 0; -+ struct mii_dev *mbus = phydev->bus; -+ -+ ret = air_mii_cl22_write(mbus, ((phydev->addr) + 8), 0x1F, (unsigned int)(pbus_address >> 6)); -+ if (ret < 0) -+ return ret; -+ ret = air_mii_cl22_write(mbus, ((phydev->addr) + 8), (unsigned int)((pbus_address >> 2) & 0xf), (unsigned int)(pbus_data & 0xFFFF)); -+ if (ret < 0) -+ return ret; -+ ret = air_mii_cl22_write(mbus, ((phydev->addr) + 8), 0x10, (unsigned int)(pbus_data >> 16)); -+ if (ret < 0) -+ return ret; -+ return 0; -+} -+ -+/* EN8811H BUCK write function */ -+static int air_buckpbus_reg_write(struct phy_device *phydev, unsigned long pbus_address, unsigned int pbus_data) -+{ -+ int ret = 0; -+ -+ /* page 4 */ -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)4); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x10, (unsigned int)0); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x11, (unsigned int)((pbus_address >> 16) & 0xffff)); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x12, (unsigned int)(pbus_address & 0xffff)); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x13, (unsigned int)((pbus_data >> 16) & 0xffff)); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x14, (unsigned int)(pbus_data & 0xffff)); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ return 0; -+} -+ -+/* EN8811H BUCK read function */ -+static unsigned int air_buckpbus_reg_read(struct phy_device *phydev, unsigned long pbus_address) -+{ -+ unsigned int pbus_data = 0, pbus_data_low, pbus_data_high; -+ int ret = 0; -+ -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)4); /* page 4 */ -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return PBUS_INVALID_DATA; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x10, (unsigned int)0); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return PBUS_INVALID_DATA; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x15, (unsigned int)((pbus_address >> 16) & 0xffff)); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return PBUS_INVALID_DATA; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x16, (unsigned int)(pbus_address & 0xffff)); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return PBUS_INVALID_DATA; -+ } -+ -+ pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, 0x17); -+ pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, 0x18); -+ pbus_data = (pbus_data_high << 16) + pbus_data_low; -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)0); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ return pbus_data; -+} -+ -+static int MDIOWriteBuf(struct phy_device *phydev, unsigned long address, unsigned long array_size, const unsigned char *buffer) -+{ -+ unsigned int write_data, offset ; -+ int ret = 0; -+ -+ /* page 4 */ -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)4); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ /* address increment*/ -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x10, (unsigned int)0x8000); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x11, (unsigned int)((address >> 16) & 0xffff)); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x12, (unsigned int)(address & 0xffff)); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ -+ for (offset = 0; offset < array_size; offset += 4) { -+ write_data = (buffer[offset + 3] << 8) | buffer[offset + 2]; -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x13, write_data); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ write_data = (buffer[offset + 1] << 8) | buffer[offset]; -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x14, write_data); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ } -+ ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)0); -+ if (ret < 0) { -+ printf("phy_write, ret: %d\n", ret); -+ return ret; -+ } -+ return 0; -+} -+ -+#ifdef AIR_LED_SUPPORT -+static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity, int polar, -+ u16 on_evt, u16 blk_evt) -+{ -+ int ret = 0; -+ -+ if (AIR_ACTIVE_HIGH == polar) -+ on_evt |= LED_ON_POL; -+ else -+ on_evt &= ~LED_ON_POL; -+ -+ ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), on_evt | LED_ON_EN); -+ if (ret < 0) -+ return ret; -+ ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt); -+ if (ret < 0) -+ return ret; -+ return 0; -+} -+ -+static int airoha_led_set_mode(struct phy_device *phydev, u8 mode) -+{ -+ u16 cl45_data; -+ int err = 0; -+ -+ cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_BCR); -+ switch (mode) { -+ case AIR_LED_MODE_DISABLE: -+ cl45_data &= ~LED_BCR_EXT_CTRL; -+ cl45_data &= ~LED_BCR_MODE_MASK; -+ cl45_data |= LED_BCR_MODE_DISABLE; -+ break; -+ case AIR_LED_MODE_USER_DEFINE: -+ cl45_data |= LED_BCR_EXT_CTRL; -+ cl45_data |= LED_BCR_CLK_EN; -+ break; -+ default: -+ printf("LED mode%d is not supported!\n", mode); -+ return -EINVAL; -+ } -+ err = air_mii_cl45_write(phydev, 0x1f, LED_BCR, cl45_data); -+ if (err < 0) -+ return err; -+ return 0; -+} -+ -+static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state) -+{ -+ u16 cl45_data; -+ int err; -+ -+ cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity)); -+ if (LED_ENABLE == state) -+ cl45_data |= LED_ON_EN; -+ else -+ cl45_data &= ~LED_ON_EN; -+ -+ err = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), cl45_data); -+ if (err < 0) -+ return err; -+ return 0; -+} -+ -+static int en8811h_led_init(struct phy_device *phydev) -+{ -+ unsigned int led_gpio = 0, reg_value = 0; -+ u16 cl45_data = led_dur; -+ int ret, led_id; -+ -+ cl45_data = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M; -+ ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data); -+ if (ret < 0) -+ return ret; -+ cl45_data >>= 1; -+ ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_DUR, cl45_data); -+ if (ret < 0) -+ return ret; -+ -+ ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE); -+ if (ret != 0) { -+ printf("LED fail to set mode, ret %d !\n", ret); -+ return ret; -+ } -+ for(led_id = 0; led_id < EN8811H_LED_COUNT; led_id++) -+ { -+ /* LED0 <-> GPIO5, LED1 <-> GPIO4, LED0 <-> GPIO3 */ -+ if ( led_cfg[led_id].gpio != (led_id + (AIR_LED0_GPIO5 - (2 * led_id)))) { -+ printf("LED%d uses incorrect GPIO%d !\n", led_id, led_cfg[led_id].gpio); -+ return -EINVAL; -+ } -+ reg_value = 0; -+ if (led_cfg[led_id].en == LED_ENABLE) -+ { -+ led_gpio |= BIT(led_cfg[led_id].gpio); -+ ret = airoha_led_set_state(phydev, led_id, led_cfg[led_id].en); -+ if (ret != 0) { -+ printf("LED fail to set state, ret %d !\n", ret); -+ return ret; -+ } -+ ret = airoha_led_set_usr_def(phydev, led_id, led_cfg[led_id].pol, led_cfg[led_id].on_cfg, led_cfg[led_id].blk_cfg); -+ if (ret != 0) { -+ printf("LED fail to set default, ret %d !\n", ret); -+ return ret; -+ } -+ } -+ } -+ ret = air_buckpbus_reg_write(phydev, 0xcf8b8, led_gpio); -+ if (ret < 0) -+ return ret; -+ printf("LED initialize OK !\n"); -+ return 0; -+} -+#endif /* AIR_LED_SUPPORT */ -+ -+static char *firmware_buf; -+static int en8811h_load_firmware(struct phy_device *phydev) -+{ -+ u32 pbus_value; -+ int ret = 0; -+ -+ if (!firmware_buf) { -+ firmware_buf = malloc(EN8811H_MD32_DM_SIZE + EN8811H_MD32_DSP_SIZE); -+ if (!firmware_buf) { -+ printf("[Airoha] cannot allocated buffer for firmware.\n"); -+ return -ENOMEM; -+ } -+ -+#ifdef CONFIG_PHY_AIROHA_FW_IN_UBI -+ ret = ubi_volume_read("en8811h-fw", firmware_buf, EN8811H_MD32_DM_SIZE + EN8811H_MD32_DSP_SIZE); -+ if (ret) { -+ printf("[Airoha] read firmware from UBI failed.\n"); -+ free(firmware_buf); -+ firmware_buf = NULL; -+ return ret; -+ } -+#elif defined(CONFIG_PHY_AIROHA_FW_IN_MMC) -+ struct mmc *mmc = find_mmc_device(0); -+ if (!mmc) { -+ printf("[Airoha] opening MMC device failed.\n"); -+ free(firmware_buf); -+ firmware_buf = NULL; -+ return -ENODEV; -+ } -+ if (mmc_init(mmc)) { -+ printf("[Airoha] initializing MMC device failed.\n"); -+ free(firmware_buf); -+ firmware_buf = NULL; -+ return -ENODEV; -+ } -+ if (IS_SD(mmc)) { -+ printf("[Airoha] SD card is not supported.\n"); -+ free(firmware_buf); -+ firmware_buf = NULL; -+ return -EINVAL; -+ } -+ ret = mmc_set_part_conf(mmc, 1, 2, 2); -+ if (ret) { -+ printf("[Airoha] cannot access eMMC boot1 hw partition.\n"); -+ free(firmware_buf); -+ firmware_buf = NULL; -+ return ret; -+ } -+ ret = blk_dread(mmc_get_blk_desc(mmc), 0, 0x120, firmware_buf); -+ mmc_set_part_conf(mmc, 1, 1, 0); -+ if (ret != 0x120) { -+ printf("[Airoha] cannot read firmware from eMMC.\n"); -+ free(firmware_buf); -+ firmware_buf = NULL; -+ return -EIO; -+ } -+#else -+#warning EN8811H firmware loading not implemented -+ free(firmware_buf); -+ firmware_buf = NULL; -+ return -EOPNOTSUPP; -+#endif -+ } -+ -+ ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x0); -+ if (ret < 0) -+ return ret; -+ pbus_value = air_buckpbus_reg_read(phydev, 0x800000); -+ pbus_value |= BIT(11); -+ ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value); -+ if (ret < 0) -+ return ret; -+ /* Download DM */ -+ ret = MDIOWriteBuf(phydev, 0x00000000, EN8811H_MD32_DM_SIZE, firmware_buf); -+ if (ret < 0) { -+ printf("[Airoha] MDIOWriteBuf 0x00000000 fail.\n"); -+ return ret; -+ } -+ /* Download PM */ -+ ret = MDIOWriteBuf(phydev, 0x00100000, EN8811H_MD32_DSP_SIZE, firmware_buf + EN8811H_MD32_DM_SIZE); -+ if (ret < 0) { -+ printf("[Airoha] MDIOWriteBuf 0x00100000 fail.\n"); -+ return ret; -+ } -+ pbus_value = air_buckpbus_reg_read(phydev, 0x800000); -+ pbus_value &= ~BIT(11); -+ ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value); -+ if (ret < 0) -+ return ret; -+ ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x01); -+ if (ret < 0) -+ return ret; -+ return 0; -+} -+ -+static int en8811h_config(struct phy_device *phydev) -+{ -+ int ret = 0; -+ int pid1 = 0, pid2 = 0; -+ -+ ret = air_pbus_reg_write(phydev, 0xcf928 , 0x0); -+ if (ret < 0) -+ return ret; -+ -+ pid1 = phy_read(phydev, MDIO_DEVAD_NONE, MII_PHYSID1); -+ pid2 = phy_read(phydev, MDIO_DEVAD_NONE, MII_PHYSID2); -+ if ((EN8811H_PHY_ID1 != pid1) || (EN8811H_PHY_ID2 != pid2)) { -+ printf("EN8811H does not exist !\n"); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static int en8811h_get_autonego(struct phy_device *phydev, int *an) -+{ -+ int reg; -+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); -+ if (reg < 0) -+ return -EINVAL; -+ if (reg & BMCR_ANENABLE) -+ *an = AUTONEG_ENABLE; -+ else -+ *an = AUTONEG_DISABLE; -+ return 0; -+} -+ -+static int en8811h_startup(struct phy_device *phydev) -+{ -+ ofnode node = phy_get_ofnode(phydev); -+ int ret = 0, lpagb = 0, lpa = 0, common_adv_gb = 0, common_adv = 0, advgb = 0, adv = 0, reg = 0, an = AUTONEG_DISABLE, bmcr = 0, reg_value; -+ int old_link = phydev->link; -+ u32 pbus_value = 0, retry; -+ -+ eth_phy_reset(phydev->dev, 1); -+ mdelay(10); -+ eth_phy_reset(phydev->dev, 0); -+ mdelay(1); -+ -+ ret = en8811h_load_firmware(phydev); -+ if (ret) { -+ printf("EN8811H load firmware fail.\n"); -+ return ret; -+ } -+ retry = MAX_RETRY; -+ do { -+ mdelay(300); -+ reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009); -+ if (EN8811H_PHY_READY == reg_value) { -+ printf("EN8811H PHY ready!\n"); -+ break; -+ } -+ retry--; -+ } while (retry); -+ if (0 == retry) { -+ printf("EN8811H PHY is not ready. (MD32 FW Status reg: 0x%x)\n", reg_value); -+ pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c); -+ printf("Check MD32 FW Version(0x3b3c) : %08x\n", pbus_value); -+ printf("EN8811H initialize fail!\n"); -+ return 0; -+ } -+ /* Mode selection*/ -+ printf("EN8811H Mode 1 !\n"); -+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0); -+ if (ret < 0) -+ return ret; -+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0); -+ if (ret < 0) -+ return ret; -+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101); -+ if (ret < 0) -+ return ret; -+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002); -+ if (ret < 0) -+ return ret; -+ -+ /* Serdes polarity */ -+ pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8); -+ pbus_value &= 0xfffffffc; -+ pbus_value |= ofnode_read_bool(node, "airoha,rx-pol-reverse") ? -+ EN8811H_RX_POLARITY_REVERSE : EN8811H_RX_POLARITY_NORMAL; -+ pbus_value |= ofnode_read_bool(node, "airoha,tx-pol-reverse") ? -+ EN8811H_TX_POLARITY_REVERSE : EN8811H_TX_POLARITY_NORMAL; -+ ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value); -+ if (ret < 0) -+ return ret; -+ pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8); -+ printf("Tx, Rx Polarity(0xca0f8): %08x\n", pbus_value); -+ pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c); -+ printf("MD32 FW Version(0x3b3c) : %08x\n", pbus_value); -+#if defined(AIR_LED_SUPPORT) -+ ret = en8811h_led_init(phydev); -+ if (ret < 0) { -+ printf("en8811h_led_init fail\n"); -+ } -+#endif -+ printf("EN8811H initialize OK ! (%s)\n", EN8811H_DRIVER_VERSION); -+ -+ ret = genphy_update_link(phydev); -+ if (ret) -+ { -+ printf("ret %d!\n", ret); -+ return ret; -+ } -+ -+ ret = genphy_parse_link(phydev); -+ if (ret) -+ { -+ printf("ret %d!\n", ret); -+ return ret; -+ } -+ -+ if (old_link && phydev->link) -+ return 0; -+ -+ phydev->speed = SPEED_100; -+ phydev->duplex = DUPLEX_FULL; -+ phydev->pause = 0; -+ phydev->asym_pause = 0; -+ -+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); -+ if (reg < 0) -+ { -+ printf("MII_BMSR reg %d!\n", reg); -+ return reg; -+ } -+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); -+ if (reg < 0) -+ { -+ printf("MII_BMSR reg %d!\n", reg); -+ return reg; -+ } -+ if(reg & BMSR_LSTATUS) -+ { -+ pbus_value = air_buckpbus_reg_read(phydev, 0x109D4); -+ if (0x10 & pbus_value) { -+ phydev->speed = SPEED_2500; -+ phydev->duplex = DUPLEX_FULL; -+ } -+ else -+ { -+ ret = en8811h_get_autonego(phydev, &an); -+ if ((AUTONEG_ENABLE == an) && (0 == ret)) -+ { -+ printf("AN mode!\n"); -+ printf("SPEED 1000/100!\n"); -+ lpagb = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000); -+ if (lpagb < 0 ) -+ return lpagb; -+ advgb = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000); -+ if (adv < 0 ) -+ return adv; -+ common_adv_gb = (lpagb & (advgb << 2)); -+ -+ lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA); -+ if (lpa < 0 ) -+ return lpa; -+ adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE); -+ if (adv < 0 ) -+ return adv; -+ common_adv = (lpa & adv); -+ -+ phydev->speed = SPEED_10; -+ phydev->duplex = DUPLEX_HALF; -+ if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) -+ { -+ phydev->speed = SPEED_1000; -+ if (common_adv_gb & LPA_1000FULL) -+ -+ phydev->duplex = DUPLEX_FULL; -+ } -+ else if (common_adv & (LPA_100FULL | LPA_100HALF)) -+ { -+ phydev->speed = SPEED_100; -+ if (common_adv & LPA_100FULL) -+ phydev->duplex = DUPLEX_FULL; -+ } -+ else -+ { -+ if (common_adv & LPA_10FULL) -+ phydev->duplex = DUPLEX_FULL; -+ } -+ } -+ else -+ { -+ printf("Force mode!\n"); -+ bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); -+ -+ if (bmcr < 0) -+ return bmcr; -+ -+ if (bmcr & BMCR_FULLDPLX) -+ phydev->duplex = DUPLEX_FULL; -+ else -+ phydev->duplex = DUPLEX_HALF; -+ -+ if (bmcr & BMCR_SPEED1000) -+ phydev->speed = SPEED_1000; -+ else if (bmcr & BMCR_SPEED100) -+ phydev->speed = SPEED_100; -+ else -+ phydev->speed = SPEED_100; -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+#if AIR_UBOOT_REVISION > 0x202303 -+U_BOOT_PHY_DRIVER(en8811h) = { -+ .name = "Airoha EN8811H", -+ .uid = EN8811H_PHY_ID, -+ .mask = 0x0ffffff0, -+ .config = &en8811h_config, -+ .startup = &en8811h_startup, -+ .shutdown = &genphy_shutdown, -+}; -+#else -+static struct phy_driver AIR_EN8811H_driver = { -+ .name = "Airoha EN8811H", -+ .uid = EN8811H_PHY_ID, -+ .mask = 0x0ffffff0, -+ .config = &en8811h_config, -+ .startup = &en8811h_startup, -+ .shutdown = &genphy_shutdown, -+}; -+ -+int phy_air_en8811h_init(void) -+{ -+ phy_register(&AIR_EN8811H_driver); -+ return 0; -+} -+#endif ---- /dev/null -+++ b/drivers/net/phy/air_en8811h.h -@@ -0,0 +1,163 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/************************************************* -+ * FILE NAME: air_en8811h.h -+ * PURPOSE: -+ * EN8811H PHY Driver for Uboot -+ * NOTES: -+ * -+ * Copyright (C) 2023 Airoha Technology Corp. -+ *************************************************/ -+ -+#ifndef __EN8811H_H -+#define __EN8811H_H -+ -+#define AIR_UBOOT_REVISION ((((U_BOOT_VERSION_NUM / 1000) % 10) << 20) | \ -+ (((U_BOOT_VERSION_NUM / 100) % 10) << 16) | \ -+ (((U_BOOT_VERSION_NUM / 10) % 10) << 12) | \ -+ ((U_BOOT_VERSION_NUM % 10) << 8) | \ -+ (((U_BOOT_VERSION_NUM_PATCH / 10) % 10) << 4) | \ -+ ((U_BOOT_VERSION_NUM_PATCH % 10) << 0)) -+ -+#define EN8811H_PHY_ID1 0x03a2 -+#define EN8811H_PHY_ID2 0xa411 -+#define EN8811H_PHY_ID ((EN8811H_PHY_ID1 << 16) | EN8811H_PHY_ID2) -+#define EN8811H_SPEED_2500 0x03 -+#define EN8811H_PHY_READY 0x02 -+#define MAX_RETRY 5 -+ -+#define EN8811H_MD32_DM_SIZE 0x4000 -+#define EN8811H_MD32_DSP_SIZE 0x20000 -+ -+#define EN8811H_TX_POLARITY_NORMAL 0x1 -+#define EN8811H_TX_POLARITY_REVERSE 0x0 -+ -+#define EN8811H_RX_POLARITY_NORMAL (0x0 << 1) -+#define EN8811H_RX_POLARITY_REVERSE (0x1 << 1) -+ -+#ifndef BIT -+#define BIT(nr) (1UL << (nr)) -+#endif -+ -+/* CL45 MDIO control */ -+#define MII_MMD_ACC_CTL_REG 0x0d -+#define MII_MMD_ADDR_DATA_REG 0x0e -+#define MMD_OP_MODE_DATA BIT(14) -+/* MultiGBASE-T AN register */ -+#define MULTIG_ANAR_2500M (0x0080) -+#define MULTIG_LPAR_2500M (0x0020) -+ -+#define EN8811H_DRIVER_VERSION "v1.0.4" -+ -+/************************************************************ -+ * For reference only -+ * LED0 Link 2500/Blink 2500 TxRx (GPIO5) <-> BASE_T_LED0, -+ * LED1 Link 1000/Blink 1000 TxRx (GPIO4) <-> BASE_T_LED1, -+ * LED2 Link 100/Blink 100 TxRx (GPIO3) <-> BASE_T_LED2, -+ ************************************************************/ -+/* User-defined.B */ -+#define AIR_LED0_ON (LED_ON_EVT_LINK_2500M) -+#define AIR_LED0_BLK (LED_BLK_EVT_2500M_TX_ACT | LED_BLK_EVT_2500M_RX_ACT) -+#define AIR_LED1_ON (LED_ON_EVT_LINK_1000M) -+#define AIR_LED1_BLK (LED_BLK_EVT_1000M_TX_ACT | LED_BLK_EVT_1000M_RX_ACT) -+#define AIR_LED2_ON (LED_ON_EVT_LINK_100M) -+#define AIR_LED2_BLK (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT) -+/* User-defined.E */ -+ -+#define LED_ON_CTRL(i) (0x024 + ((i)*2)) -+#define LED_ON_EN (1 << 15) -+#define LED_ON_POL (1 << 14) -+#define LED_ON_EVT_MASK (0x1ff) -+/* LED ON Event Option.B */ -+#define LED_ON_EVT_LINK_2500M (1 << 8) -+#define LED_ON_EVT_FORCE (1 << 6) -+#define LED_ON_EVT_HDX (1 << 5) -+#define LED_ON_EVT_FDX (1 << 4) -+#define LED_ON_EVT_LINK_DOWN (1 << 3) -+#define LED_ON_EVT_LINK_100M (1 << 1) -+#define LED_ON_EVT_LINK_1000M (1 << 0) -+/* LED ON Event Option.E */ -+ -+#define LED_BLK_CTRL(i) (0x025 + ((i)*2)) -+#define LED_BLK_EVT_MASK (0xfff) -+/* LED Blinking Event Option.B*/ -+#define LED_BLK_EVT_2500M_RX_ACT (1 << 11) -+#define LED_BLK_EVT_2500M_TX_ACT (1 << 10) -+#define LED_BLK_EVT_FORCE (1 << 9) -+#define LED_BLK_EVT_100M_RX_ACT (1 << 3) -+#define LED_BLK_EVT_100M_TX_ACT (1 << 2) -+#define LED_BLK_EVT_1000M_RX_ACT (1 << 1) -+#define LED_BLK_EVT_1000M_TX_ACT (1 << 0) -+/* LED Blinking Event Option.E*/ -+#define LED_ENABLE 1 -+#define LED_DISABLE 0 -+ -+#define EN8811H_LED_COUNT 3 -+ -+#define LED_BCR (0x021) -+#define LED_BCR_EXT_CTRL (1 << 15) -+#define LED_BCR_CLK_EN (1 << 3) -+#define LED_BCR_TIME_TEST (1 << 2) -+#define LED_BCR_MODE_MASK (3) -+#define LED_BCR_MODE_DISABLE (0) -+#define LED_BCR_MODE_2LED (1) -+#define LED_BCR_MODE_3LED_1 (2) -+#define LED_BCR_MODE_3LED_2 (3) -+ -+#define LED_ON_DUR (0x022) -+#define LED_ON_DUR_MASK (0xffff) -+ -+#define LED_BLK_DUR (0x023) -+#define LED_BLK_DUR_MASK (0xffff) -+ -+#define LED_GPIO_SEL_MASK 0x7FFFFFF -+ -+#define UNIT_LED_BLINK_DURATION 1024 -+ -+#define INVALID_DATA 0xffff -+#define PBUS_INVALID_DATA 0xffffffff -+ -+struct air_base_t_led_cfg_s { -+ u16 en; -+ u16 gpio; -+ u16 pol; -+ u16 on_cfg; -+ u16 blk_cfg; -+}; -+ -+enum { -+ AIR_LED2_GPIO3 = 3, -+ AIR_LED1_GPIO4, -+ AIR_LED0_GPIO5, -+ AIR_LED_LAST -+}; -+ -+enum { -+ AIR_BASE_T_LED0, -+ AIR_BASE_T_LED1, -+ AIR_BASE_T_LED2, -+ AIR_BASE_T_LED3 -+}; -+ -+enum { -+ AIR_LED_BLK_DUR_32M, -+ AIR_LED_BLK_DUR_64M, -+ AIR_LED_BLK_DUR_128M, -+ AIR_LED_BLK_DUR_256M, -+ AIR_LED_BLK_DUR_512M, -+ AIR_LED_BLK_DUR_1024M, -+ AIR_LED_BLK_DUR_LAST -+}; -+ -+enum { -+ AIR_ACTIVE_LOW, -+ AIR_ACTIVE_HIGH, -+}; -+ -+enum { -+ AIR_LED_MODE_DISABLE, -+ AIR_LED_MODE_USER_DEFINE, -+ AIR_LED_MODE_LAST -+}; -+ -+#endif /* End of __EN8811H_MD32_H */ -+ ---- a/drivers/net/eth-phy-uclass.c -+++ b/drivers/net/eth-phy-uclass.c -@@ -155,7 +155,7 @@ static int eth_phy_of_to_plat(struct ude - return 0; - } - --static void eth_phy_reset(struct udevice *dev, int value) -+void eth_phy_reset(struct udevice *dev, int value) - { - struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev); - u32 delay; ---- a/include/eth_phy.h -+++ b/include/eth_phy.h -@@ -14,5 +14,6 @@ int eth_phy_binds_nodes(struct udevice * - int eth_phy_set_mdio_bus(struct udevice *eth_dev, struct mii_dev *mdio_bus); - struct mii_dev *eth_phy_get_mdio_bus(struct udevice *eth_dev); - int eth_phy_get_addr(struct udevice *dev); -+void eth_phy_reset(struct udevice *dev, int value); - - #endif diff --git a/lede/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch b/lede/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch index bbd05fe41f..a39d03adf2 100644 --- a/lede/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch +++ b/lede/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch @@ -1,5 +1,5 @@ --- /dev/null -+++ b/configs/mt7622_ubnt_unifi-6-lr-v1_defconfig ++++ b/configs/mt7622_ubnt_unifi-6-lr_defconfig @@ -0,0 +1,147 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y @@ -149,305 +149,6 @@ +CONFIG_USE_SERVERIP=y +CONFIG_SERVERIP="192.168.1.254" --- /dev/null -+++ b/configs/mt7622_ubnt_unifi-6-lr-v2_defconfig -@@ -0,0 +1,147 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7622=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_LOAD_ADDR=0x40080000 -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTDPARTS_DEFAULT="mtdparts=nor0:128k(bl2),640k(fip),64k(u-boot-env),256k(factory),64k(eeprom),15232k(recovery),-(firmware)" -+CONFIG_ENV_IS_IN_MTD=y -+CONFIG_ENV_MTD_NAME="nor0" -+CONFIG_ENV_SIZE_REDUND=0x4000 -+CONFIG_ENV_SIZE=0x4000 -+CONFIG_ENV_OFFSET=0xc0000 -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_RESET_BUTTON_SETTLE_DELAY=400 -+CONFIG_BOOTP_SEND_HOSTNAME=y -+CONFIG_DEFAULT_ENV_FILE="ubnt_unifi-6-lr-v2_env" -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=25000000 -+CONFIG_DEFAULT_DEVICE_TREE="mt7622-ubnt-unifi-6-lr" -+CONFIG_DEBUG_UART=y -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_DEFAULT_FDT_FILE="mt7622-ubnt-unifi-6-lr" -+CONFIG_SYS_PROMPT="MT7622> " -+# CONFIG_LEGACY_IMAGE_FORMAT is not set -+# CONFIG_BOOTM_PLAN9 is not set -+# CONFIG_BOOTM_RTEMS is not set -+# CONFIG_BOOTM_VXWORKS is not set -+# CONFIG_EFI is not set -+# CONFIG_EFI_LOADER is not set -+CONFIG_CMD_BOOTMENU=y -+# CONFIG_CMD_BOOTEFI is not set -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+# CONFIG_CMD_ELF is not set -+# CONFIG_CMD_BOOTEFI_BOOTMGR is not set -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_MTD=y -+CONFIG_CMD_MTDPARTS=y -+# CONFIG_CMD_PCI is not set -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+# CONFIG_CMD_UNLZ4 is not set -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_ETH=y -+CONFIG_DM_ETH_PHY=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_MDIO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+# CONFIG_DM_MMC is not set -+CONFIG_DM_SERIAL=y -+CONFIG_DM_SPI=y -+CONFIG_DM_SPI_FLASH=y -+CONFIG_HUSH_PARSER=y -+# CONFIG_PARTITION_UUIDS is not set -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+# CONFIG_LED is not set -+# CONFIG_LZ4 is not set -+CONFIG_VERSION_VARIABLE=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_PHYLIB_10G=y -+CONFIG_PHY_AQUANTIA=y -+CONFIG_PHY_ADDR_ENABLE=y -+CONFIG_PHY_ADDR=8 -+CONFIG_MEDIATEK_ETH=y -+CONFIG_MTD=y -+# CONFIG_MMC is not set -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_MTK_SNFI_SPI=y -+CONFIG_MTK_SNOR=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_SPI_FLASH=y -+CONFIG_SPI_FLASH_BAR=y -+CONFIG_SPI_FLASH_MTD=y -+CONFIG_SPI_FLASH_UNLOCK_ALL=y -+CONFIG_SPI_FLASH_EON=y -+CONFIG_SPI_FLASH_GIGADEVICE=y -+CONFIG_SPI_FLASH_MACRONIX=y -+CONFIG_SPI_FLASH_SPANSION=y -+CONFIG_SPI_FLASH_STMICRO=y -+CONFIG_SPI_FLASH_SST=y -+CONFIG_SPI_FLASH_WINBOND=y -+CONFIG_SPI_FLASH_XMC=y -+CONFIG_SPI_FLASH_USE_4K_SECTORS=y -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/configs/mt7622_ubnt_unifi-6-lr-v3_defconfig -@@ -0,0 +1,146 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7622=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_LOAD_ADDR=0x40080000 -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTDPARTS_DEFAULT="mtdparts=nor0:128k(bl2),640k(fip),64k(u-boot-env),256k(factory),64k(eeprom),15232k(recovery),-(firmware)" -+CONFIG_ENV_IS_IN_MTD=y -+CONFIG_ENV_MTD_NAME="nor0" -+CONFIG_ENV_SIZE_REDUND=0x4000 -+CONFIG_ENV_SIZE=0x4000 -+CONFIG_ENV_OFFSET=0xc0000 -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_RESET_BUTTON_SETTLE_DELAY=400 -+CONFIG_BOOTP_SEND_HOSTNAME=y -+CONFIG_DEFAULT_ENV_FILE="ubnt_unifi-6-lr_env" -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=25000000 -+CONFIG_DEFAULT_DEVICE_TREE="mt7622-ubnt-unifi-6-lr-v3" -+CONFIG_DEBUG_UART=y -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_DEFAULT_FDT_FILE="mt7622-ubnt-unifi-6-lr-v3" -+CONFIG_SYS_PROMPT="MT7622> " -+# CONFIG_LEGACY_IMAGE_FORMAT is not set -+# CONFIG_BOOTM_PLAN9 is not set -+# CONFIG_BOOTM_RTEMS is not set -+# CONFIG_BOOTM_VXWORKS is not set -+# CONFIG_EFI is not set -+# CONFIG_EFI_LOADER is not set -+CONFIG_CMD_BOOTMENU=y -+# CONFIG_CMD_BOOTEFI is not set -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+# CONFIG_CMD_ELF is not set -+# CONFIG_CMD_BOOTEFI_BOOTMGR is not set -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_MTD=y -+CONFIG_CMD_MTDPARTS=y -+# CONFIG_CMD_PCI is not set -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+# CONFIG_CMD_UNLZ4 is not set -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_ETH=y -+CONFIG_DM_ETH_PHY=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_MDIO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+# CONFIG_DM_MMC is not set -+CONFIG_DM_SERIAL=y -+CONFIG_DM_SPI=y -+CONFIG_DM_SPI_FLASH=y -+CONFIG_HUSH_PARSER=y -+# CONFIG_PARTITION_UUIDS is not set -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+# CONFIG_LED is not set -+# CONFIG_LZ4 is not set -+CONFIG_VERSION_VARIABLE=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_PHY_REALTEK=y -+CONFIG_PHY_ADDR_ENABLE=y -+CONFIG_PHY_ADDR=0 -+CONFIG_MEDIATEK_ETH=y -+CONFIG_MTD=y -+# CONFIG_MMC is not set -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_MTK_SNFI_SPI=y -+CONFIG_MTK_SNOR=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_SPI_FLASH=y -+CONFIG_SPI_FLASH_BAR=y -+CONFIG_SPI_FLASH_MTD=y -+CONFIG_SPI_FLASH_UNLOCK_ALL=y -+CONFIG_SPI_FLASH_EON=y -+CONFIG_SPI_FLASH_GIGADEVICE=y -+CONFIG_SPI_FLASH_MACRONIX=y -+CONFIG_SPI_FLASH_SPANSION=y -+CONFIG_SPI_FLASH_STMICRO=y -+CONFIG_SPI_FLASH_SST=y -+CONFIG_SPI_FLASH_WINBOND=y -+CONFIG_SPI_FLASH_XMC=y -+CONFIG_SPI_FLASH_USE_4K_SECTORS=y -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null +++ b/arch/arm/dts/mt7622-ubnt-unifi-6-lr.dts @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0 @@ -643,210 +344,13 @@ + }; + }; +}; ---- /dev/null -+++ b/arch/arm/dts/mt7622-ubnt-unifi-6-lr-v3.dts -@@ -0,0 +1,193 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2019 MediaTek Inc. -+ * Author: Sam Shih -+ */ -+ -+/dts-v1/; -+#include -+#include "mt7622.dtsi" -+#include "mt7622-u-boot.dtsi" -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "mt7622-ubnt-unifi-6-lr-v3"; -+ compatible = "mediatek,mt7622", "ubnt,unifi-6-lr-v3"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x20000000>; -+ }; -+ -+ aliases { -+ spi0 = &snor; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ reset { -+ label = "reset"; -+ gpios = <&gpio 62 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ }; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x20000000>; -+ }; -+ -+ reg_1p8v: regulator-1p8v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-1.8V"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ reg_3p3v: regulator-3p3v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-3.3V"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ reg_5v: regulator-5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+}; -+ -+&pcie { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>; -+ status = "okay"; -+ -+ pcie@0,0 { -+ status = "okay"; -+ }; -+ -+ pcie@1,0 { -+ status = "okay"; -+ }; -+}; -+ -+&pinctrl { -+ eth_pins: eth-pins { -+ mux { -+ function = "eth"; -+ groups = "mdc_mdio", "rgmii_via_gmac2"; -+ }; -+ }; -+ -+ pcie0_pins: pcie0-pins { -+ mux { -+ function = "pcie"; -+ groups = "pcie0_pad_perst", -+ "pcie0_1_waken", -+ "pcie0_1_clkreq"; -+ }; -+ }; -+ -+ pcie1_pins: pcie1-pins { -+ mux { -+ function = "pcie"; -+ groups = "pcie1_pad_perst", -+ "pcie1_0_waken", -+ "pcie1_0_clkreq"; -+ }; -+ }; -+ -+ snfi_pins: snfi-pins { -+ mux { -+ function = "flash"; -+ groups = "snfi"; -+ }; -+ }; -+ -+ snor_pins: snor-pins { -+ mux { -+ function = "flash"; -+ groups = "spi_nor"; -+ }; -+ }; -+ -+ uart0_pins: uart0 { -+ mux { -+ function = "uart"; -+ groups = "uart0_0_tx_rx" ; -+ }; -+ }; -+ -+ watchdog_pins: watchdog-default { -+ mux { -+ function = "watchdog"; -+ groups = "watchdog"; -+ }; -+ }; -+}; -+ -+&snor { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&snor_pins>; -+ status = "okay"; -+ -+ spi-flash@0 { -+ compatible = "jedec,spi-nor"; -+ reg = <0>; -+ spi-tx-bus-width = <1>; -+ spi-rx-bus-width = <4>; -+ u-boot,dm-pre-reloc; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&watchdog { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&watchdog_pins>; -+ status = "okay"; -+}; -+ -+ð { -+ status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <ð_pins>; -+ -+ mediatek,gmac-id = <0>; -+ phy-mode = "sgmii"; -+ phy-handle = <&gphy>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+ -+ mdio-bus { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ gphy: ethernet-phy@0 { -+ /* RealTek RTL8211FS */ -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0x0>; -+ }; -+ }; -+}; --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile -@@ -1423,6 +1423,8 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ +@@ -1423,6 +1423,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ mt7623a-unielec-u7623-02-emmc.dtb \ mt7622-bananapi-bpi-r64.dtb \ mt7622-linksys-e8450-ubi.dtb \ + mt7622-ubnt-unifi-6-lr.dtb \ -+ mt7622-ubnt-unifi-6-lr-v3.dtb \ mt7623n-bananapi-bpi-r2.dtb \ mt7629-rfb.dtb \ mt7981-rfb.dtb \ @@ -903,112 +407,6 @@ +_firstboot=setenv _firstboot ; run _switch_to_menu ; run ethaddr_factory ; run _init_env ; run boot_first +_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title +_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" ---- /dev/null -+++ b/ubnt_unifi-6-lr-v2_env -@@ -0,0 +1,50 @@ -+ethaddr_factory=mtd read nor0 $loadaddr 0x110000 0x10000 && env readmem -b ethaddr $loadaddr 0x6 ; setenv ethaddr_factory -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x48000000 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_nor ; fi -+bootdelay=0 -+bootfile=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-v2-ubootmod-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-v2-ubootmod-preloader.bin -+bootfile_fip=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-v2-ubootmod-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-v2-ubootmod-squashfs-sysupgrade.itb -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from flash.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from flash.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to flash.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to flash.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to flash.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to flash.=run boot_tftp_write_preloader ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=run nor_read_production && bootm $loadaddr -+boot_recovery=run nor_read_recovery ; bootm $loadaddr -+boot_serial_write_fip=loadx $loadaddr 115200 && run boot_write_fip -+boot_serial_write_preloader=loadx $loadaddr 115200 && run boot_write_preloader -+boot_tftp_forever=while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run nor_write_production ; if env exists noboot ; then else bootm $loadaddr ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run nor_write_recovery ; if env exists noboot ; then else bootm $loadaddr ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run boot_write_fip -+boot_tftp_write_preloader=tftpboot $loadaddr $bootfile_bl2 && run boot_write_preloader -+boot_nor=run boot_production ; run boot_recovery -+boot_write_fip=mtd erase nor0 0x20000 0x80000 && mtd write nor0 $loadaddr 0x20000 0x80000 -+boot_write_preloader=mtd erase nor0 0x0 0x20000 && mtd write nor0 $loadaddr 0x0 0x20000 -+reset_factory=mtd erase nor0 0xc0000 0x10000 && reset -+nor_read_production=mtd read nor0 $loadaddr 0x1000000 0x1000 && imsz $loadaddr image_size && mtd read nor0 $loadaddr 0x1000000 $image_size -+nor_read_recovery=mtd read nor0 $loadaddr 0x120000 0x1000 && imsz $loadaddr image_size && mtd read nor0 $loadaddr 0x120000 $image_size -+nor_pad_size=imsz $loadaddr image_size ; setexpr image_eb 0x$image_size / 0x1000 ; setexpr tmp1 0x$image_size % 0x1000 ; test 0x$tmp1 -gt 0 && setexpr image_eb 0x$image_eb + 1 ; setexpr image_eb 0x$image_eb * 0x1000 -+nor_write_production=run nor_pad_size ; test 0x$image_eb -le 0x3000000 && mtd erase nor0 0x1000000 0x$image_eb && mtd write nor0 $loadaddr 0x1000000 $filesize -+nor_write_recovery=run nor_pad_size ; test 0x$image_eb -le 0xee0000 && mtd erase nor0 0x120000 0x$image_eb && mtd write nor0 $loadaddr 0x120000 $filesize -+_init_env=setenv _init_env ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run ethaddr_factory ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver"--- /dev/null ---- /dev/null -+++ b/ubnt_unifi-6-lr-v3_env -@@ -0,0 +1,50 @@ -+ethaddr_factory=mtd read nor0 $loadaddr 0x110000 0x10000 && env readmem -b ethaddr $loadaddr 0x6 ; setenv ethaddr_factory -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x48000000 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_nor ; fi -+bootdelay=0 -+bootfile=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-v3-ubootmod-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-v3-ubootmod-preloader.bin -+bootfile_fip=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-v3-ubootmod-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-v3-ubootmod-squashfs-sysupgrade.itb -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from flash.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from flash.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to flash.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to flash.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to flash.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to flash.=run boot_tftp_write_preloader ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=run nor_read_production && bootm $loadaddr -+boot_recovery=run nor_read_recovery ; bootm $loadaddr -+boot_serial_write_fip=loadx $loadaddr 115200 && run boot_write_fip -+boot_serial_write_preloader=loadx $loadaddr 115200 && run boot_write_preloader -+boot_tftp_forever=while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run nor_write_production ; if env exists noboot ; then else bootm $loadaddr ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run nor_write_recovery ; if env exists noboot ; then else bootm $loadaddr ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run boot_write_fip -+boot_tftp_write_preloader=tftpboot $loadaddr $bootfile_bl2 && run boot_write_preloader -+boot_nor=run boot_production ; run boot_recovery -+boot_write_fip=mtd erase nor0 0x20000 0x80000 && mtd write nor0 $loadaddr 0x20000 0x80000 -+boot_write_preloader=mtd erase nor0 0x0 0x20000 && mtd write nor0 $loadaddr 0x0 0x20000 -+reset_factory=mtd erase nor0 0xc0000 0x10000 && reset -+nor_read_production=mtd read nor0 $loadaddr 0x1000000 0x1000 && imsz $loadaddr image_size && mtd read nor0 $loadaddr 0x1000000 $image_size -+nor_read_recovery=mtd read nor0 $loadaddr 0x120000 0x1000 && imsz $loadaddr image_size && mtd read nor0 $loadaddr 0x120000 $image_size -+nor_pad_size=imsz $loadaddr image_size ; setexpr image_eb 0x$image_size / 0x1000 ; setexpr tmp1 0x$image_size % 0x1000 ; test 0x$tmp1 -gt 0 && setexpr image_eb 0x$image_eb + 1 ; setexpr image_eb 0x$image_eb * 0x1000 -+nor_write_production=run nor_pad_size ; test 0x$image_eb -le 0x3000000 && mtd erase nor0 0x1000000 0x$image_eb && mtd write nor0 $loadaddr 0x1000000 $filesize -+nor_write_recovery=run nor_pad_size ; test 0x$image_eb -le 0xee0000 && mtd erase nor0 0x120000 0x$image_eb && mtd write nor0 $loadaddr 0x120000 $filesize -+_init_env=setenv _init_env ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run ethaddr_factory ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" --- a/common/board_r.c +++ b/common/board_r.c @@ -66,6 +66,7 @@ diff --git a/lede/package/boot/uboot-mediatek/patches/421-zbtlink_zbt-wg3526-16m.patch b/lede/package/boot/uboot-mediatek/patches/421-zbtlink_zbt-wg3526-16m.patch deleted file mode 100644 index b9b241a51d..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/421-zbtlink_zbt-wg3526-16m.patch +++ /dev/null @@ -1,314 +0,0 @@ ---- /dev/null -+++ b/configs/mt7621_zbtlink_zbt-wg3526-16m_defconfig -@@ -0,0 +1,138 @@ -+CONFIG_MIPS=y -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_SYS_MALLOC_LEN=0x100000 -+CONFIG_SPL_LIBCOMMON_SUPPORT=y -+CONFIG_SPL_LIBGENERIC_SUPPORT=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_ENV_SIZE=0x1000 -+CONFIG_ENV_IS_IN_MTD=y -+CONFIG_ENV_MTD_NAME="nor0" -+CONFIG_ENV_SIZE_REDUND=0x10000 -+CONFIG_ENV_SIZE=0x10000 -+CONFIG_ENV_OFFSET=0x30000 -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_RESET_BUTTON_SETTLE_DELAY=400 -+CONFIG_BOOTP_SEND_HOSTNAME=y -+# CONFIG_BOOTSTD is not set -+CONFIG_DEFAULT_ENV_FILE="zbtlink_zbt-wg3526-16m_env" -+CONFIG_DEFAULT_DEVICE_TREE="zbtlink,zbt-wg3526" -+CONFIG_SPL_BSS_MAX_SIZE=0x80000 -+CONFIG_SPL_BSS_START_ADDR=0x80140000 -+CONFIG_SPL_SERIAL=y -+CONFIG_SPL_SYS_MALLOC_F_LEN=0x40000 -+CONFIG_SPL=y -+CONFIG_DEBUG_UART_BASE=0xbe000c00 -+CONFIG_DEBUG_UART_CLOCK=50000000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_SYS_LOAD_ADDR=0x83000000 -+CONFIG_SYS_MIPS_TIMER_FREQ=440000000 -+CONFIG_ARCH_MTMIPS=y -+CONFIG_SOC_MT7621=y -+# CONFIG_MIPS_CACHE_SETUP is not set -+# CONFIG_MIPS_CACHE_DISABLE is not set -+CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y -+CONFIG_MIPS_BOOT_FDT=y -+CONFIG_DEBUG_UART=y -+CONFIG_TPL_SYS_MALLOC_F_LEN=0x1000 -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+# CONFIG_FIT_ENABLE_SHA256_SUPPORT is not set -+CONFIG_HUSH_PARSER=y -+CONFIG_LOGLEVEL=6 -+# CONFIG_LOG is not set -+# CONFIG_SYS_LONGHELP is not set -+# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set -+CONFIG_SYS_CONSOLE_INFO_QUIET=y -+CONFIG_SPL_SYS_MALLOC_SIMPLE=y -+CONFIG_SPL_NOR_SUPPORT=y -+CONFIG_TPL=y -+# CONFIG_TPL_FRAMEWORK is not set -+CONFIG_LEGACY_IMAGE_FORMAT=y -+# CONFIG_BOOTM_NETBSD is not set -+# CONFIG_BOOTM_PLAN9 is not set -+# CONFIG_BOOTM_RTEMS is not set -+# CONFIG_BOOTM_VXWORKS is not set -+# CONFIG_EFI is not set -+# CONFIG_EFI_LOADER is not set -+CONFIG_CMD_BOOTMENU=y -+# CONFIG_CMD_BOOTEFI is not set -+# CONFIG_CMD_BOOTD is not set -+# CONFIG_CMD_BOOTP is not set -+CONFIG_CMD_BOOTM=y -+# CONFIG_CMD_BOOTDEV is not set -+# CONFIG_CMD_BOOTFLOW is not set -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_ECHO=y -+# CONFIG_CMD_ELF is not set -+# CONFIG_CMD_BOOTEFI_BOOTMGR is not set -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_MMC=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_MTDPART=y -+# CONFIG_CMD_PCI is not set -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_TFTPBOOT=y -+# CONFIG_CMD_UNLZ4 is not set -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_DOS_PARTITION=y -+# CONFIG_SPL_DOS_PARTITION is not set -+# CONFIG_ISO_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SPL_EFI_PARTITION is not set -+CONFIG_PARTITION_TYPE_GUID=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+# CONFIG_NET_RANDOM_ETHADDR is not set -+# CONFIG_I2C is not set -+# CONFIG_INPUT is not set -+CONFIG_MMC=y -+# CONFIG_MMC_QUIRKS is not set -+# CONFIG_MMC_HW_PARTITIONING is not set -+CONFIG_MMC_MTK=y -+CONFIG_MTD=y -+CONFIG_DM_MTD=y -+CONFIG_SF_DEFAULT_SPEED=20000000 -+# CONFIG_SPI_FLASH_BAR is not set -+# CONFIG_SPI_FLASH_EON is not set -+# CONFIG_SPI_FLASH_GIGADEVICE is not set -+# CONFIG_SPI_FLASH_ISSI is not set -+# CONFIG_SPI_FLASH_MACRONIX is not set -+# CONFIG_SPI_FLASH_SPANSION is not set -+# CONFIG_SPI_FLASH_STMICRO is not set -+CONFIG_SPI_FLASH_WINBOND=y -+# CONFIG_SPI_FLASH_XMC is not set -+# CONFIG_SPI_FLASH_XTX is not set -+CONFIG_SPI_FLASH_MTD=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_DEBUG_UART_SHIFT=2 -+CONFIG_SPI=y -+CONFIG_MT7621_SPI=y -+CONFIG_SYSRESET=y -+CONFIG_SYSRESET_RESETCTL=y -+# CONFIG_SYS_XTRACE is not set -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_WDT=y -+CONFIG_WDT_MT7621=y -+# CONFIG_BINMAN_FDT is not set -+CONFIG_LZMA=y -+CONFIG_SPL_LZMA=y -+# CONFIG_GZIP is not set ---- /dev/null -+++ b/zbtlink_zbt-wg3526-16m_env -@@ -0,0 +1,36 @@ -+ethaddr_factory=mtd read factory $loadaddr 0x0 0x10000 ; setexpr macoffs $loadaddr + 0xe000 ; env readmem -b ethaddr $macoffs 0x6 ; setenv ethaddr_factory -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x83000000 -+bootcmd=run boot_nor -+bootdelay=0 -+bootfile=openwrt-ramips-mt7621-zbtlink_zbt-wg3526-16m-initramfs-kernel.bin -+bootfile_uboot=u-boot-mt7621.bin -+bootfile_upg=openwrt-ramips-mt7621-zbtlink_zbt-wg3526-16m-squashfs-sysupgrade.bin -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot system from flash.=run boot_nor ; run bootmenu_confirm_return -+bootmenu_3=Load system via TFTP then write to flash.=run boot_tftp_sysupgrade ; run bootmenu_confirm_return -+bootmenu_4=Load U-Boot via TFTP then write to flash.=run boot_tftp_write_uboot ; run bootmenu_confirm_return -+bootmenu_5=Reset all settings to factory defaults.=run reset_factory ; reset -+bootmenu_6=Reboot.=reset -+boot_first=if button reset ; then run boot_tftp ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_tftp_forever -+boot_nor=bootm 0x1fc50000 -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr -+boot_tftp_forever=while true ; do run boot_tftp ; sleep 1 ; done -+boot_tftp_sysupgrade=tftpboot $loadaddr $bootfile_upg && iminfo $loadaddr && run nor_write_production -+boot_tftp_write_uboot=tftpboot $loadaddr $bootfile_uboot && run nor_write_uboot -+reset_factory=mtd erase u-boot-env 0x0 0x10000 && reset -+nor_pad_size=setexpr image_eb $filesize / 0x1000 ; setexpr tmp1 image_size % 0x1000 ; test 0x$tmp1 -gt 0 && setexpr image_eb $image_eb + 1 ; setexpr image_eb $image_eb * 0x1000 -+nor_write_production=run nor_pad_size ; test 0x$image_eb -le 0xfb0000 && mtd erase firmware 0x0 0x$image_eb && mtd write firmware $loadaddr 0x0 $filesize -+nor_write_uboot=mtd erase u-boot 0x0 0x30000 && mtd write u-boot $loadaddr 0x0 0x30000 -+_init_env=setenv _init_env ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run ethaddr_factory ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" ---- /dev/null -+++ b/arch/mips/dts/zbtlink,zbt-wg3526.dts -@@ -0,0 +1,131 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2022 MediaTek Inc. All rights reserved. -+ * -+ * Author: Weijie Gao -+ */ -+ -+/dts-v1/; -+ -+#include "mt7621.dtsi" -+#include -+ -+/ { -+ compatible = "zbtlink,zbt-wg3526", "mediatek,mt7621-rfb", "mediatek,mt7621-soc"; -+ model = "Zbtlink WG3526"; -+ -+ aliases { -+ ethernet0 = ð -+ serial0 = &uart0; -+ spi0 = &spi; -+ }; -+ -+ chosen { -+ stdout-path = &uart0; -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ -+ reset { -+ label = "reset"; -+ gpios = <&gpio 18 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_status: status { -+ label = "green:status"; -+ gpios = <&gpio 24 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+}; -+ -+&pinctrl { -+ state_default: pin_state { -+ gpios { -+ groups = "i2c", "uart3", "pcie reset"; -+ function = "gpio"; -+ }; -+ -+ wdt { -+ groups = "wdt"; -+ function = "wdt rst"; -+ }; -+ -+ jtag { -+ groups = "jtag"; -+ function = "jtag"; -+ }; -+ }; -+}; -+ -+&uart0 { -+ status = "okay"; -+}; -+ -+&gpio { -+ status = "okay"; -+}; -+ -+&spi { -+ status = "okay"; -+ num-cs = <2>; -+ -+ spi-flash@0 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ compatible = "jedec,spi-nor"; -+ spi-max-frequency = <25000000>; -+ reg = <0>; -+ -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "u-boot"; -+ reg = <0x0 0x30000>; -+ }; -+ -+ partition@30000 { -+ label = "u-boot-env"; -+ reg = <0x30000 0x10000>; -+ }; -+ -+ factory: partition@40000 { -+ label = "factory"; -+ reg = <0x40000 0x10000>; -+ read-only; -+ }; -+ -+ firmware: partition@50000 { -+ compatible = "denx,uimage"; -+ label = "firmware"; -+ reg = <0x50000 0xfb0000>; -+ }; -+ }; -+ }; -+}; -+ -+ð { -+ status = "okay"; -+}; -+ -+&mmc { -+ cap-sd-highspeed; -+ -+ status = "okay"; -+}; -+ -+&ssusb { -+ status = "okay"; -+}; -+ -+&u3phy { -+ status = "okay"; -+}; diff --git a/lede/package/boot/uboot-mediatek/patches/429-add-netcore-n60.patch b/lede/package/boot/uboot-mediatek/patches/429-add-netcore-n60.patch deleted file mode 100644 index 2304fcd5ce..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/429-add-netcore-n60.patch +++ /dev/null @@ -1,433 +0,0 @@ ---- /dev/null -+++ b/configs/mt7986_netcore_n60_defconfig -@@ -0,0 +1,182 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7986=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-netcore-n60" -+CONFIG_DEFAULT_ENV_FILE="netcore_n60_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7986a-netcore-n60.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7986> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_USB=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_USB=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_USB=y -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+CONFIG_USB_XHCI_MTK=y -+CONFIG_USB_STORAGE=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7986=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7986a-netcore-n60.dts -@@ -0,0 +1,185 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2021 MediaTek Inc. -+ * Author: Sam Shih -+ */ -+ -+/dts-v1/; -+#include "mt7986.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "Netcore N60"; -+ compatible = "mediatek,mt7986", "mediatek,mt7986-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x20000000>; -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ -+ factory { -+ label = "reset"; -+ linux,code = ; -+ gpios = <&gpio 9 GPIO_ACTIVE_LOW>; -+ }; -+ -+ wps { -+ label = "wps"; -+ linux,code = ; -+ gpios = <&gpio 10 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ status_red { -+ label = "red:status"; -+ gpios = <&gpio 29 GPIO_ACTIVE_LOW>; -+ }; -+ -+ status_green { -+ label = "green:status"; -+ gpios = <&gpio 32 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_pins>; -+ status = "disabled"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&pinctrl { -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+ -+ spic_pins: spi1-pins-func-1 { -+ mux { -+ function = "spi"; -+ groups = "spi1_2"; -+ }; -+ }; -+ -+ uart1_pins: spi1-pins-func-3 { -+ mux { -+ function = "uart"; -+ groups = "uart1_2"; -+ }; -+ }; -+ -+ pwm_pins: pwm0-pins-func-1 { -+ mux { -+ function = "pwm"; -+ groups = "pwm0"; -+ }; -+ }; -+}; -+ -+&pwm { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm_pins>; -+ status = "okay"; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <1>; -+ sample_sel = <0>; -+ -+ spi_nand@1 { -+ compatible = "spi-nand"; -+ reg = <1>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0 0x100000>; -+ }; -+ -+ partition@100000 { -+ label = "orig-env"; -+ reg = <0x100000 0x80000>; -+ }; -+ -+ partition@160000 { -+ label = "factory"; -+ reg = <0x180000 0x200000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x380000 0x200000>; -+ }; -+ -+ partition@580000 { -+ label = "ubi"; -+ reg = <0x580000 0x7280000>; -+ }; -+ }; -+ }; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/netcore_n60_env -@@ -0,0 +1,57 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-netcore_n60-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-netcore_n60-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-netcore_n60-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-netcore_n60-squashfs-sysupgrade.itb -+bootled_pwr=green:status -+bootled_rec=red:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_default=production -+part_recovery=recovery -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+ethaddr_factory=mtd read factory 0x40080000 0x1fe000 0x1000 && env readmem -b ethaddr 0x40080f20 0x6 ; setenv ethaddr_factory -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run ethaddr_factory ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/432-add-tplink-xdr608x.patch b/lede/package/boot/uboot-mediatek/patches/432-add-tplink-xdr608x.patch deleted file mode 100644 index 365f280947..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/432-add-tplink-xdr608x.patch +++ /dev/null @@ -1,934 +0,0 @@ ---- /dev/null -+++ b/configs/mt7986_tplink_tl-xdr4288_defconfig -@@ -0,0 +1,182 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7986=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-tplink-tl-xdr608x" -+CONFIG_DEFAULT_ENV_FILE="tplink_tl-xdr4288_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7986a-tplink-tl-xdr608x.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7986> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_USB=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_USB=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_USB=y -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+CONFIG_USB_XHCI_MTK=y -+CONFIG_USB_STORAGE=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7986=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/configs/mt7986_tplink_tl-xdr6086_defconfig -@@ -0,0 +1,182 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7986=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-tplink-tl-xdr608x" -+CONFIG_DEFAULT_ENV_FILE="tplink_tl-xdr6086_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7986a-tplink-tl-xdr608x.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7986> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_USB=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_USB=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_USB=y -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+CONFIG_USB_XHCI_MTK=y -+CONFIG_USB_STORAGE=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7986=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/configs/mt7986_tplink_tl-xdr6088_defconfig -@@ -0,0 +1,182 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7986=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-tplink-tl-xdr608x" -+CONFIG_DEFAULT_ENV_FILE="tplink_tl-xdr6088_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7986a-tplink-tl-xdr608x.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7986> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_USB=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_USB=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_USB=y -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+CONFIG_USB_XHCI_MTK=y -+CONFIG_USB_STORAGE=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7986=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7986a-tplink-tl-xdr608x.dts -@@ -0,0 +1,196 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2021 MediaTek Inc. -+ * Author: Sam Shih -+ */ -+ -+/dts-v1/; -+#include "mt7986.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "TP-Link TL-XDR608x"; -+ compatible = "mediatek,mt7986", "mediatek,mt7986-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x20000000>; -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ -+ factory { -+ label = "reset"; -+ linux,code = ; -+ gpios = <&gpio 9 GPIO_ACTIVE_LOW>; -+ }; -+ -+ wps { -+ label = "wps"; -+ linux,code = ; -+ gpios = <&gpio 10 GPIO_ACTIVE_LOW>; -+ }; -+ -+ turbo { -+ label = "turbo"; -+ linux,code = ; -+ gpios = <&gpio 11 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ status_red { -+ label = "red:status"; -+ gpios = <&gpio 7 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ status_green { -+ label = "green:status"; -+ gpios = <&gpio 8 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ turbo { -+ label = "green:turbo"; -+ gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; -+ }; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_pins>; -+ status = "disabled"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&pinctrl { -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+ -+ spic_pins: spi1-pins-func-1 { -+ mux { -+ function = "spi"; -+ groups = "spi1_2"; -+ }; -+ }; -+ -+ uart1_pins: spi1-pins-func-3 { -+ mux { -+ function = "uart"; -+ groups = "uart1_2"; -+ }; -+ }; -+ -+ pwm_pins: pwm0-pins-func-1 { -+ mux { -+ function = "pwm"; -+ groups = "pwm0"; -+ }; -+ }; -+}; -+ -+&pwm { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm_pins>; -+ status = "okay"; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <1>; -+ sample_sel = <0>; -+ -+ spi_nand@1 { -+ compatible = "spi-nand"; -+ reg = <1>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0 0x80000>; -+ }; -+ -+ partition@100000 { -+ label = "config"; -+ reg = <0x100000 0x60000>; -+ }; -+ -+ partition@160000 { -+ label = "factory"; -+ reg = <0x160000 0x60000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x380000 0x200000>; -+ }; -+ -+ partition@580000 { -+ label = "ubi"; -+ reg = <0x580000 0x7800000>; -+ }; -+ }; -+ }; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/tplink_tl-xdr4288_env -@@ -0,0 +1,57 @@ -+ethaddr_factory=mtd read config 0x40080000 0x0 0x20000 && env readmem -b ethaddr 0x4008001c 0x6 ; setenv ethaddr_factory -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-tplink_tl-xdr4288-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-tplink_tl-xdr4288-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-tplink_tl-xdr4288-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-tplink_tl-xdr4288-squashfs-sysupgrade.itb -+bootled_pwr=green:status -+bootled_rec=red:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_default=production -+part_recovery=recovery -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run ethaddr_factory ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" ---- /dev/null -+++ b/tplink_tl-xdr6086_env -@@ -0,0 +1,57 @@ -+ethaddr_factory=mtd read config 0x40080000 0x0 0x20000 && env readmem -b ethaddr 0x4008001c 0x6 ; setenv ethaddr_factory -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-tplink_tl-xdr6086-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-tplink_tl-xdr6086-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-tplink_tl-xdr6086-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-tplink_tl-xdr6086-squashfs-sysupgrade.itb -+bootled_pwr=green:status -+bootled_rec=red:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_default=production -+part_recovery=recovery -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run ethaddr_factory ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" ---- /dev/null -+++ b/tplink_tl-xdr6088_env -@@ -0,0 +1,57 @@ -+ethaddr_factory=mtd read config 0x40080000 0x0 0x20000 && env readmem -b ethaddr 0x4008001c 0x6 ; setenv ethaddr_factory -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-tplink_tl-xdr6088-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-tplink_tl-xdr6088-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-tplink_tl-xdr6088-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-tplink_tl-xdr6088-squashfs-sysupgrade.itb -+bootled_pwr=green:status -+bootled_rec=red:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_default=production -+part_recovery=recovery -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run ethaddr_factory ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/433-add-qihoo_360t7.patch b/lede/package/boot/uboot-mediatek/patches/433-add-qihoo_360t7.patch deleted file mode 100644 index 4f98c95893..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/433-add-qihoo_360t7.patch +++ /dev/null @@ -1,425 +0,0 @@ ---- /dev/null -+++ b/configs/mt7981_qihoo-360t7_defconfig -@@ -0,0 +1,175 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7981=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7981_qihoo-360t7" -+CONFIG_DEFAULT_ENV_FILE="qihoo-360t7_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7981_qihoo-360t7.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7981> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7981=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7981_qihoo-360t7.dts -@@ -0,0 +1,185 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2022 MediaTek Inc. -+ * Author: Sam Shih -+ */ -+ -+/dts-v1/; -+#include "mt7981.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "Qihoo 360T7"; -+ compatible = "mediatek,mt7981", "mediatek,mt7981-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x10000000>; -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ -+ factory { -+ label = "reset"; -+ linux,code = ; -+ gpios = <&gpio 1 GPIO_ACTIVE_LOW>; -+ }; -+ -+ wps { -+ label = "wps"; -+ linux,code = ; -+ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ status_red { -+ label = "red:status"; -+ gpios = <&gpio 3 GPIO_ACTIVE_LOW>; -+ }; -+ -+ status_green { -+ label = "green:status"; -+ gpios = <&gpio 7 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_pins>; -+ status = "disabled"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&pinctrl { -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+ -+ spic_pins: spi1-pins-func-1 { -+ mux { -+ function = "spi"; -+ groups = "spi1_1"; -+ }; -+ }; -+ -+ uart1_pins: spi1-pins-func-3 { -+ mux { -+ function = "uart"; -+ groups = "uart1_2"; -+ }; -+ }; -+ -+ pwm_pins: pwm0-pins-func-1 { -+ mux { -+ function = "pwm"; -+ groups = "pwm0_1", "pwm1_0"; -+ }; -+ }; -+}; -+ -+&pwm { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm_pins>; -+ status = "okay"; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <2>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0 0x100000>; -+ }; -+ -+ partition@100000 { -+ label = "orig-env"; -+ reg = <0x100000 0x80000>; -+ }; -+ -+ partition@160000 { -+ label = "factory"; -+ reg = <0x180000 0x200000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x380000 0x200000>; -+ }; -+ -+ partition@580000 { -+ label = "ubi"; -+ reg = <0x580000 0x6c00000>; -+ }; -+ }; -+ }; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/qihoo-360t7_env -@@ -0,0 +1,56 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-qihoo_360t7-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-qihoo_360t7-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-qihoo_360t7-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-qihoo_360t7-squashfs-sysupgrade.itb -+bootled_pwr=green:status -+bootled_rec=red:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_default=production -+part_recovery=recovery -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/434-add-xiaomi_mi-router-wr30u.patch b/lede/package/boot/uboot-mediatek/patches/434-add-xiaomi_mi-router-wr30u.patch deleted file mode 100644 index 2bd1afe7a8..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/434-add-xiaomi_mi-router-wr30u.patch +++ /dev/null @@ -1,461 +0,0 @@ ---- /dev/null -+++ b/configs/mt7981_xiaomi_mi-router-wr30u_defconfig -@@ -0,0 +1,175 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7981=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7981_xiaomi_mi-router-wr30u" -+CONFIG_DEFAULT_ENV_FILE="xiaomi_mi-router-wr30u_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7981_xiaomi_mi-router-wr30u.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7981> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7981=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7981_xiaomi_mi-router-wr30u.dts -@@ -0,0 +1,221 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2022 MediaTek Inc. -+ * Author: Sam Shih -+ */ -+ -+/dts-v1/; -+#include "mt7981.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "Xiaomi Router WR30U"; -+ compatible = "mediatek,mt7981", "mediatek,mt7981-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ config { -+ blink_led = "yellow:network"; -+ system_led = "yellow:system"; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x10000000>; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ reset { -+ label = "reset"; -+ gpios = <&gpio 1 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ }; -+ -+ mesh { -+ label = "mesh"; -+ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ linux,input-type = ; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_system_blue { -+ label = "blue:system"; -+ gpios = <&gpio 9 GPIO_ACTIVE_LOW>; -+ }; -+ -+ led_system_yellow { -+ label = "yellow:system"; -+ gpios = <&gpio 10 GPIO_ACTIVE_LOW>; -+ }; -+ -+ led_network_blue { -+ label = "blue:network"; -+ gpios = <&gpio 11 GPIO_ACTIVE_LOW>; -+ }; -+ -+ led_network_yellow { -+ label = "yellow:network"; -+ gpios = <&gpio 12 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_pins>; -+ status = "disabled"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "sgmii"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+}; -+ -+&pinctrl { -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+ -+ spic_pins: spi1-pins-func-1 { -+ mux { -+ function = "spi"; -+ groups = "spi1_1"; -+ }; -+ }; -+ -+ uart1_pins: spi1-pins-func-3 { -+ mux { -+ function = "uart"; -+ groups = "uart1_2"; -+ }; -+ }; -+ -+ pwm_pins: pwm0-pins-func-1 { -+ mux { -+ function = "pwm"; -+ groups = "pwm0_1", "pwm1_0"; -+ }; -+ }; -+}; -+ -+&pwm { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm_pins>; -+ status = "okay"; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <2>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x00 0x100000>; -+ }; -+ -+ partition@100000 { -+ label = "Nvram"; -+ reg = <0x100000 0x40000>; -+ }; -+ -+ partition@140000 { -+ label = "Bdata"; -+ reg = <0x140000 0x40000>; -+ }; -+ -+ partition@180000 { -+ label = "factory"; -+ reg = <0x180000 0x200000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x380000 0x200000>; -+ }; -+ -+ partition@580000 { -+ label = "crash"; -+ reg = <0x580000 0x40000>; -+ }; -+ -+ partition@5c0000 { -+ label = "crash_log"; -+ reg = <0x5c0000 0x40000>; -+ }; -+ -+ partition@600000 { -+ label = "ubi"; -+ reg = <0x600000 0x7000000>; -+ }; -+ -+ partition@7600000 { -+ label = "KF"; -+ reg = <0x7600000 0x40000>; -+ }; -+ }; -+ }; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/xiaomi_mi-router-wr30u_env -@@ -0,0 +1,56 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-xiaomi_mi-router-wr30u-ubootmod-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-xiaomi_mi-router-wr30u-ubootmod-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-xiaomi_mi-router-wr30u-ubootmod-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-xiaomi_mi-router-wr30u-ubootmod-squashfs-sysupgrade.itb -+bootled_pwr=yellow:system -+bootled_rec=yellow:network -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_default=production -+part_recovery=recovery -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/435-add-h3c_magic-nx30-pro.patch b/lede/package/boot/uboot-mediatek/patches/435-add-h3c_magic-nx30-pro.patch deleted file mode 100644 index d5a149b903..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/435-add-h3c_magic-nx30-pro.patch +++ /dev/null @@ -1,445 +0,0 @@ ---- /dev/null -+++ b/configs/mt7981_h3c_magic-nx30-pro_defconfig -@@ -0,0 +1,175 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7981=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7981_h3c_magic-nx30-pro" -+CONFIG_DEFAULT_ENV_FILE="h3c_magic-nx30-pro_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7981_h3c_magic-nx30-pro.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7981> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7981=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7981_h3c_magic-nx30-pro.dts -@@ -0,0 +1,205 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2022 MediaTek Inc. -+ * Author: Sam Shih -+ */ -+ -+/dts-v1/; -+#include "mt7981.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "H3C Magic NX30 Pro"; -+ compatible = "mediatek,mt7981", "mediatek,mt7981-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x10000000>; -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ -+ factory { -+ label = "reset"; -+ linux,code = ; -+ gpios = <&gpio 1 GPIO_ACTIVE_LOW>; -+ }; -+ -+ wps { -+ label = "wps"; -+ linux,code = ; -+ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ status_red { -+ label = "red:status"; -+ gpios = <&gpio 4 GPIO_ACTIVE_LOW>; -+ }; -+ -+ status_green { -+ label = "green:status"; -+ gpios = <&gpio 5 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_pins>; -+ status = "disabled"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&pinctrl { -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+ -+ spic_pins: spi1-pins-func-1 { -+ mux { -+ function = "spi"; -+ groups = "spi1_1"; -+ }; -+ }; -+ -+ uart1_pins: spi1-pins-func-3 { -+ mux { -+ function = "uart"; -+ groups = "uart1_2"; -+ }; -+ }; -+ -+ pwm_pins: pwm0-pins-func-1 { -+ mux { -+ function = "pwm"; -+ groups = "pwm0_1", "pwm1_0"; -+ }; -+ }; -+}; -+ -+&pwm { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm_pins>; -+ status = "okay"; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <2>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0000000 0x0100000>; -+ }; -+ -+ partition@100000 { -+ label = "orig-env"; -+ reg = <0x0100000 0x0080000>; -+ }; -+ -+ partition@180000 { -+ label = "factory"; -+ reg = <0x0180000 0x0200000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x0380000 0x0200000>; -+ }; -+ -+ partition@580000 { -+ label = "ubi"; -+ reg = <0x0580000 0x4000000>; -+ }; -+ -+ partition@4580000 { -+ label = "pdt_data"; -+ reg = <0x4580000 0x0600000>; -+ }; -+ -+ partition@4b80000 { -+ label = "pdt_data_1"; -+ reg = <0x4b80000 0x0600000>; -+ }; -+ -+ partition@5180000 { -+ label = "exp"; -+ reg = <0x5180000 0x0100000>; -+ }; -+ -+ partition@5280000 { -+ label = "plugin"; -+ reg = <0x5280000 0x2580000>; -+ }; -+ }; -+ }; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/h3c_magic-nx30-pro_env -@@ -0,0 +1,56 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-h3c_magic-nx30-pro-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-h3c_magic-nx30-pro-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-h3c_magic-nx30-pro-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-h3c_magic-nx30-pro-squashfs-sysupgrade.itb -+bootled_pwr=green:status -+bootled_rec=red:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_default=production -+part_recovery=recovery -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/437-add-cmcc_rax3000m.patch b/lede/package/boot/uboot-mediatek/patches/437-add-cmcc_rax3000m.patch deleted file mode 100644 index 26e0e30a99..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/437-add-cmcc_rax3000m.patch +++ /dev/null @@ -1,697 +0,0 @@ ---- /dev/null -+++ b/configs/mt7981_cmcc_rax3000m-emmc_defconfig -@@ -0,0 +1,175 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7981=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7981-cmcc-rax3000m-emmc" -+CONFIG_DEFAULT_ENV_FILE="cmcc_rax3000m-emmc_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7981-cmcc-rax3000m-emmc.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7981> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_MMC=y -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_USB=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MMC=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_USB=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_MMC=y -+CONFIG_MMC_DEFAULT_DEV=1 -+CONFIG_MMC_HS200_SUPPORT=y -+CONFIG_MMC_MTK=y -+CONFIG_MMC_SUPPORTS_TUNING=y -+CONFIG_SUPPORT_EMMC_BOOT=y -+CONFIG_SPI=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_USB=y -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+CONFIG_USB_XHCI_MTK=y -+CONFIG_USB_STORAGE=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_MMC=y -+CONFIG_ENV_OFFSET=0x400000 -+CONFIG_ENV_OFFSET_REDUND=0x440000 -+CONFIG_ENV_SIZE=0x40000 -+CONFIG_ENV_SIZE_REDUND=0x40000 -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_SUPPORT_EMMC_BOOT=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7981=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_CMD_SF=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/configs/mt7981_cmcc_rax3000m-nand_defconfig -@@ -0,0 +1,175 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7981=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7981-cmcc-rax3000m-nand" -+CONFIG_DEFAULT_ENV_FILE="cmcc_rax3000m-nand_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7981-cmcc-rax3000m-nand.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7981> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7981=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7981-cmcc-rax3000m.dtsi -@@ -0,0 +1,85 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Copyright (c) 2022 MediaTek Inc. -+ * Author: Sam Shih -+ */ -+ -+/dts-v1/; -+#include "mt7981.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "CMCC RAX3000M"; -+ compatible = "mediatek,mt7981", "mediatek,mt7981-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x20000000>; -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ -+ button-reset { -+ label = "reset"; -+ linux,code = ; -+ gpios = <&gpio 1 GPIO_ACTIVE_LOW>; -+ }; -+ -+ button-mesh { -+ label = "mesh"; -+ linux,code = ; -+ linux,input-type = ; -+ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led-0 { -+ label = "green:status"; -+ gpios = <&gpio 9 GPIO_ACTIVE_LOW>; -+ }; -+ -+ led-1 { -+ label = "blue:status"; -+ gpios = <&gpio 12 GPIO_ACTIVE_LOW>; -+ }; -+ -+ led-2 { -+ label = "red:status"; -+ gpios = <&gpio 35 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/arch/arm/dts/mt7981-cmcc-rax3000m-emmc.dts -@@ -0,0 +1,53 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+ -+/dts-v1/; -+#include "mt7981-cmcc-rax3000m.dtsi" -+ -+/ { -+ reg_3p3v: regulator-3p3v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-3.3V"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+}; -+ -+&mmc0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&mmc0_pins_default>; -+ max-frequency = <26000000>; -+ bus-width = <8>; -+ cap-mmc-hw-reset; -+ vmmc-supply = <®_3p3v>; -+ non-removable; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ mmc0_pins_default: mmc0default { -+ mux { -+ function = "flash"; -+ groups = "emmc_45"; -+ }; -+ conf-cmd-dat { -+ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO", -+ "SPI0_CS", "SPI0_HOLD", "SPI0_WP", -+ "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO"; -+ input-enable; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ conf-clk { -+ pins = "SPI1_CS"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ conf-rst { -+ pins = "PWM0"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ }; -+}; ---- /dev/null -+++ b/arch/arm/dts/mt7981-cmcc-rax3000m-nand.dts -@@ -0,0 +1,77 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+ -+/dts-v1/; -+#include "mt7981-cmcc-rax3000m.dtsi" -+ -+&pinctrl { -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <2>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0 0x100000>; -+ }; -+ -+ partition@100000 { -+ label = "orig-env"; -+ reg = <0x100000 0x80000>; -+ }; -+ -+ partition@160000 { -+ label = "factory"; -+ reg = <0x180000 0x200000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x380000 0x200000>; -+ }; -+ -+ partition@580000 { -+ label = "ubi"; -+ reg = <0x580000 0x7200000>; -+ }; -+ }; -+ }; -+}; ---- /dev/null -+++ b/cmcc_rax3000m-emmc_env -@@ -0,0 +1,55 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootargs=root=/dev/mmcblk0p65 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_emmc ; fi -+bootconf=config-1#mt7981b-cmcc-rax3000m-emmc -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-cmcc_rax3000m-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-cmcc_rax3000m-emmc-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-cmcc_rax3000m-emmc-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-cmcc_rax3000m-squashfs-sysupgrade.itb -+bootled_pwr=red:status -+bootled_rec=blue:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) [eMMC] -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from eMMC.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from eMMC.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to eMMC.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to eMMC.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run emmc_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run emmc_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_emmc=run boot_production ; run boot_recovery -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run emmc_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run emmc_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run emmc_write_fip -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run emmc_write_bl2 -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+mmc_write_vol=imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$image_size && mmc write $loadaddr 0x$part_addr 0x$image_size -+mmc_read_vol=mmc read $loadaddr $part_addr 0x100 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size && setexpr filesize $image_size * 0x200 -+part_default=production -+part_recovery=recovery -+reset_factory=eraseenv && reset -+emmc_read_production=part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_read_vol -+emmc_read_recovery=part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_read_vol -+emmc_write_bl2=mmc partconf 0 1 1 1 && mmc erase 0x0 0x400 && mmc write $fileaddr 0x0 0x400 ; mmc partconf 0 1 1 0 -+emmc_write_fip=mmc erase 0x3400 0x2000 && mmc write $fileaddr 0x3400 0x2000 && mmc erase 0x2000 0x800 -+emmc_write_production=part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_write_vol -+emmc_write_recovery=part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_write_vol -+_init_env=setenv _init_env ; setenv _create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" ---- /dev/null -+++ b/cmcc_rax3000m-nand_env -@@ -0,0 +1,56 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootconf=config-1#mt7981b-cmcc-rax3000m-nand -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-cmcc_rax3000m-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-cmcc_rax3000m-nand-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-cmcc_rax3000m-nand-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-cmcc_rax3000m-squashfs-sysupgrade.itb -+bootled_pwr=red:status -+bootled_rec=blue:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) [SPI-NAND] -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_default=production -+part_recovery=recovery -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/438-add-jcg_q30-pro.patch b/lede/package/boot/uboot-mediatek/patches/438-add-jcg_q30-pro.patch deleted file mode 100644 index 639cae174e..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/438-add-jcg_q30-pro.patch +++ /dev/null @@ -1,420 +0,0 @@ ---- /dev/null -+++ b/configs/mt7981_jcg_q30-pro_defconfig -@@ -0,0 +1,175 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7981=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7981_jcg_q30-pro" -+CONFIG_DEFAULT_ENV_FILE="jcg_q30-pro_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7981_jcg_q30-pro.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7981> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7981=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7981_jcg_q30-pro.dts -@@ -0,0 +1,179 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2022 MediaTek Inc. -+ * Author: Sam Shih -+ */ -+ -+/dts-v1/; -+#include "mt7981.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "JCG Q30 PRO"; -+ compatible = "mediatek,mt7981", "mediatek,mt7981-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x10000000>; -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ -+ factory { -+ label = "reset"; -+ linux,code = ; -+ gpios = <&gpio 1 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ status_red { -+ label = "red:status"; -+ gpios = <&gpio 8 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ status_blue { -+ label = "blue:status"; -+ gpios = <&gpio 13 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_pins>; -+ status = "disabled"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&pinctrl { -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+ -+ spic_pins: spi1-pins-func-1 { -+ mux { -+ function = "spi"; -+ groups = "spi1_1"; -+ }; -+ }; -+ -+ uart1_pins: spi1-pins-func-3 { -+ mux { -+ function = "uart"; -+ groups = "uart1_2"; -+ }; -+ }; -+ -+ pwm_pins: pwm0-pins-func-1 { -+ mux { -+ function = "pwm"; -+ groups = "pwm0_1", "pwm1_0"; -+ }; -+ }; -+}; -+ -+&pwm { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm_pins>; -+ status = "okay"; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <2>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0 0x100000>; -+ }; -+ -+ partition@100000 { -+ label = "orig-env"; -+ reg = <0x100000 0x80000>; -+ }; -+ -+ partition@160000 { -+ label = "factory"; -+ reg = <0x180000 0x200000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x380000 0x200000>; -+ }; -+ -+ partition@580000 { -+ label = "ubi"; -+ reg = <0x580000 0x7000000>; -+ }; -+ }; -+ }; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/jcg_q30-pro_env -@@ -0,0 +1,57 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-jcg_q30-pro-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-jcg_q30-pro-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-jcg_q30-pro-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-jcg_q30-pro-squashfs-sysupgrade.itb -+bootled_pwr=blue:status -+bootled_rec=red:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_default=production -+part_recovery=recovery -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+ethaddr_factory=mtd read factory 0x40080000 0xa0000 0x800 && env readmem -b ethaddr 0x4008002a 0x6 ; setenv ethaddr_factory -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run ethaddr_factory ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/439-add-zyxel_ex5601-t0.patch b/lede/package/boot/uboot-mediatek/patches/439-add-zyxel_ex5601-t0.patch deleted file mode 100644 index 7f0564fd49..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/439-add-zyxel_ex5601-t0.patch +++ /dev/null @@ -1,431 +0,0 @@ ---- /dev/null -+++ b/configs/mt7986_zyxel_ex5601-t0_defconfig -@@ -0,0 +1,186 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7986=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-zyxel_ex5601-t0" -+CONFIG_DEFAULT_ENV_FILE="zyxel_ex5601-t0_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7986a-zyxel_ex5601-t0.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="EX5601> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_MTD=y -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_USB=y -+# CONFIG_CMD_FLASH is not set -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_USB=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+# CONFIG_DM_PCI is not set -+# CONFIG_PCIE_MEDIATEK is not set -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+# CONFIG_I2C is not set -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_USB=y -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+CONFIG_USB_XHCI_MTK=y -+CONFIG_USB_STORAGE=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7986=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7986a-zyxel_ex5601-t0.dts -@@ -0,0 +1,181 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Author: Valerio 'ftp21' Mancini -+ * Author: Nicolò Veronese -+ */ -+ -+/dts-v1/; -+#include -+#include "mt7986.dtsi" -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "Zyxel EX5601-T0 ubootmod"; -+ compatible = "mediatek,mt7986", "mediatek,mt7986-sd-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x20000000>; -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ factory { -+ label = "reset"; -+ gpios = <&gpio 21 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ }; -+ -+ wps { -+ label = "wps"; -+ gpios = <&gpio 56 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_status_green: pwr { -+ label = "green:status"; -+ gpios = <&gpio 13 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ -+ led_sfp_green: sfp { -+ label = "green:sfp"; -+ gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_pins>; -+ status = "disabled"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&pinctrl { -+ spic_pins: spi1-pins-func-1 { -+ mux { -+ function = "spi"; -+ groups = "spi1_2"; -+ }; -+ }; -+ -+ uart1_pins: spi1-pins-func-3 { -+ mux { -+ function = "uart"; -+ groups = "uart1_2"; -+ }; -+ }; -+ -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <1>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <20000000>; -+ spi-tx-buswidth = <4>; -+ spi-rx-buswidth = <4>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0 0x100000>; -+ }; -+ -+ partition@100000 { -+ label = "u-boot-env"; -+ reg = <0x0100000 0x0080000>; -+ }; -+ -+ partition@180000 { -+ label = "Factory"; -+ reg = <0x180000 0x0200000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x380000 0x0200000>; -+ }; -+ -+ partition@540000 { -+ label = "zloader"; -+ reg = <0x540000 0x0040000>; -+ read-only; -+ }; -+ partition@580000 { -+ label = "ubi"; -+ reg = <0x580000 0x1da80000>; -+ }; -+ }; -+ }; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; -+ ---- /dev/null -+++ b/zyxel_ex5601-t0_env -@@ -0,0 +1,55 @@ -+ethaddr_factory=mtd read Factory 0x40080000 0x0 0x20000 && env readmem -b ethaddr 0x4008002A 0x6 ; setenv ethaddr_factory -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootargs=console=ttyS0,115200n8 console_msg_format=syslog -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-zyxel_ex5601-t0-ubootmod-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-zyxel_ex5601-t0-ubootmod-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-zyxel_ex5601-t0-ubootmod-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-zyxel_ex5601-t0-ubootmod-squashfs-sysupgrade.itb -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=run ubi_read_production && bootm $loadaddr#$bootconf -+boot_recovery=run ubi_read_recovery && bootm $loadaddr#$bootconf -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+part_fit=fit -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr $part_fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run ethaddr_factory ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/440-add-xiaomi_mi-router-ax3000t.patch b/lede/package/boot/uboot-mediatek/patches/440-add-xiaomi_mi-router-ax3000t.patch deleted file mode 100644 index 9b50166a94..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/440-add-xiaomi_mi-router-ax3000t.patch +++ /dev/null @@ -1,414 +0,0 @@ ---- /dev/null -+++ b/configs/mt7981_xiaomi_mi-router-ax3000t_defconfig -@@ -0,0 +1,163 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7981=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7981_xiaomi_mi-router-ax3000t" -+CONFIG_DEFAULT_ENV_FILE="xiaomi_mi-router-ax3000t_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7981_xiaomi_mi-router-ax3000t.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7981> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+# CONFIG_CMD_EXT4 is not set -+# CONFIG_CMD_FAT is not set -+CONFIG_CMD_FDT=y -+# CONFIG_CMD_FS_GENERIC is not set -+# CONFIG_CMD_FS_UUID is not set -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_MTD=y -+# CONFIG_CMD_PCI is not set -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+# CONFIG_CMD_PWM is not set -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+# CONFIG_CMD_USB is not set -+# CONFIG_CMD_FLASH is not set -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+# CONFIG_DM_USB is not set -+# CONFIG_DM_PWM is not set -+# CONFIG_PWM_MTK is not set -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+# CONFIG_DM_SCSI is not set -+# CONFIG_AHCI is not set -+CONFIG_PHY=y -+# CONFIG_PHY_MTK_TPHY is not set -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+# CONFIG_PCI is not set -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+# CONFIG_DM_PCI is not set -+# CONFIG_PCIE_MEDIATEK is not set -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7981=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+# CONFIG_USB is not set -+# CONFIG_USB_HOST is not set -+# CONFIG_USB_XHCI_HCD is not set -+# CONFIG_USB_XHCI_MTK is not set -+# CONFIG_USB_STORAGE is not set -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7981_xiaomi_mi-router-ax3000t.dts -@@ -0,0 +1,187 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2022 MediaTek Inc. -+ * Author: Sam Shih -+ */ -+ -+/dts-v1/; -+#include "mt7981.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "Xiaomi Router AX3000T"; -+ compatible = "mediatek,mt7981", "mediatek,mt7981-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x10000000>; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ reset { -+ label = "reset"; -+ gpios = <&gpio 1 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ }; -+ -+ mesh { -+ label = "mesh"; -+ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ linux,input-type = ; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_status_blue { -+ label = "blue:status"; -+ gpios = <&gpio 9 GPIO_ACTIVE_LOW>; -+ }; -+ -+ led_status_yellow { -+ label = "yellow:status"; -+ gpios = <&gpio 10 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&pinctrl { -+ spic_pins: spi1-pins-func-1 { -+ mux { -+ function = "spi"; -+ groups = "spi1_1"; -+ }; -+ }; -+ -+ uart1_pins: spi1-pins-func-3 { -+ mux { -+ function = "uart"; -+ groups = "uart1_2"; -+ }; -+ }; -+ -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <2>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x00 0x100000>; -+ }; -+ -+ partition@100000 { -+ label = "Nvram"; -+ reg = <0x100000 0x40000>; -+ }; -+ -+ partition@140000 { -+ label = "Bdata"; -+ reg = <0x140000 0x40000>; -+ }; -+ -+ partition@180000 { -+ label = "factory"; -+ reg = <0x180000 0x200000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x380000 0x200000>; -+ }; -+ -+ partition@580000 { -+ label = "crash"; -+ reg = <0x580000 0x40000>; -+ }; -+ -+ partition@5c0000 { -+ label = "crash_log"; -+ reg = <0x5c0000 0x40000>; -+ }; -+ -+ partition@600000 { -+ label = "ubi"; -+ reg = <0x600000 0x7000000>; -+ }; -+ -+ partition@7600000 { -+ label = "KF"; -+ reg = <0x7600000 0x40000>; -+ }; -+ }; -+ }; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/xiaomi_mi-router-ax3000t_env -@@ -0,0 +1,55 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootargs=console=ttyS0,115200n8 console_msg_format=syslog -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-xiaomi_mi-router-ax3000t-ubootmod-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-xiaomi_mi-router-ax3000t-ubootmod-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-xiaomi_mi-router-ax3000t-ubootmod-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-xiaomi_mi-router-ax3000t-ubootmod-squashfs-sysupgrade.itb -+bootled_pwr=yellow:status -+bootled_rec=blue:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/441-add-jdcloud_re-cp-03.patch b/lede/package/boot/uboot-mediatek/patches/441-add-jdcloud_re-cp-03.patch deleted file mode 100644 index dc8dfe0140..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/441-add-jdcloud_re-cp-03.patch +++ /dev/null @@ -1,324 +0,0 @@ ---- /dev/null -+++ b/configs/mt7986a_jdcloud_re-cp-03_defconfig -@@ -0,0 +1,112 @@ -+CONFIG_ARM=y -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_ENV_SIZE=0x40000 -+CONFIG_ENV_OFFSET=0x400000 -+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-jdcloud_re-cp-03" -+CONFIG_SYS_PROMPT="MT7986> " -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_TARGET_MT7986=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_ENV_OFFSET_REDUND=0x440000 -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_DEBUG_UART=y -+CONFIG_FIT=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7986a-jdcloud_re-cp-03.dtb" -+CONFIG_LOGLEVEL=7 -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_LOG=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_HUSH_PARSER=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_MMC=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_LINK_LOCAL=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_UUID=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_MMC=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_DEFAULT_ENV_FILE="jdcloud_re-cp-03_env" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_NETCONSOLE=y -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_CLK=y -+CONFIG_GPIO_HOG=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_SUPPORT_EMMC_BOOT=y -+CONFIG_MMC_HS200_SUPPORT=y -+CONFIG_MMC_MTK=y -+CONFIG_PHY_FIXED=y -+CONFIG_DM_MDIO=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_PINCTRL_MT7986=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_RAM=y -+CONFIG_SCSI=y -+CONFIG_DM_SCSI=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_LMB_MAX_REGIONS=64 ---- /dev/null -+++ b/arch/arm/dts/mt7986a-jdcloud_re-cp-03.dts -@@ -0,0 +1,148 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+#include -+#include "mt7986.dtsi" -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "JDCloud RE-CP-03"; -+ compatible = "mediatek,mt7986", "mediatek,mt7986-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x40000000>; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ button-joylink { -+ label = "joylink"; -+ linux,code = ; -+ gpios = <&gpio 10 GPIO_ACTIVE_LOW>; -+ }; -+ -+ button-reset { -+ label = "reset"; -+ linux,code = ; -+ gpios = <&gpio 9 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ gpio-leds { -+ compatible = "gpio-leds"; -+ -+ led-0 { -+ label = "blue:status"; -+ gpios = <&gpio 7 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ -+ led-1 { -+ label = "red:status"; -+ gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led-2 { -+ label = "green:status"; -+ gpios = <&gpio 12 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ }; -+ }; -+ -+ reg_1p8v: regulator-1p8v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-1.8V"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ reg_3p3v: regulator-3p3v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-3.3V"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&mmc0 { -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ cap-mmc-hw-reset; -+ max-frequency = <200000000>; -+ non-removable; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&mmc0_pins_default>; -+ vmmc-supply = <®_3p3v>; -+ vqmmc-supply = <®_1p8v>; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ mmc0_pins_default: mmc0default { -+ mux { -+ function = "flash"; -+ groups = "emmc_51"; -+ }; -+ -+ conf-cmd-dat { -+ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", -+ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", -+ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; -+ input-enable; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-clk { -+ pins = "EMMC_CK"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ -+ conf-dsl { -+ pins = "EMMC_DSL"; -+ bias-pull-down = ; -+ }; -+ -+ conf-rst { -+ pins = "EMMC_RSTB"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ }; -+}; -+ -+&uart0 { -+ status = "okay"; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/jdcloud_re-cp-03_env -@@ -0,0 +1,55 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootargs=root=/dev/fit0 rootwait -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_emmc ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-jdcloud_re-cp-03-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-jdcloud_re-cp-03-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-jdcloud_re-cp-03-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-jdcloud_re-cp-03-squashfs-sysupgrade.itb -+bootled_pwr=red:status -+bootled_rec=blue:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from eMMC.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from eMMC.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to eMMC.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to eMMC.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run emmc_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run emmc_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_emmc=run boot_production ; run boot_recovery -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run emmc_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run emmc_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run emmc_write_fip -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run emmc_write_bl2 -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+mmc_write_vol=imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$image_size && mmc write $loadaddr 0x$part_addr 0x$image_size -+mmc_read_vol=mmc read $loadaddr $part_addr 0x100 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size && setexpr filesize $image_size * 0x200 -+part_default=production -+part_recovery=recovery -+reset_factory=eraseenv && reset -+emmc_read_production=part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_read_vol -+emmc_read_recovery=part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_read_vol -+emmc_write_bl2=mmc partconf 0 1 1 1 && mmc erase 0x0 0x400 && mmc write $fileaddr 0x0 0x400 ; mmc partconf 0 1 1 0 -+emmc_write_fip=mmc erase 0x3400 0x2000 && mmc write $fileaddr 0x3400 0x2000 && mmc erase 0x2000 0x800 -+emmc_write_production=part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_write_vol -+emmc_write_recovery=part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_write_vol -+_init_env=setenv _init_env ; setenv _create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/442-add-bpi-r3-mini.patch b/lede/package/boot/uboot-mediatek/patches/442-add-bpi-r3-mini.patch deleted file mode 100644 index 5409f7fa0d..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/442-add-bpi-r3-mini.patch +++ /dev/null @@ -1,779 +0,0 @@ ---- /dev/null -+++ b/configs/mt7986a_bpi-r3-mini-emmc_defconfig -@@ -0,0 +1,203 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7986=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-bpi-r3-mini" -+CONFIG_DEFAULT_ENV_FILE="bananapi_bpi-r3-mini_emmc_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7986a-bpi-r3-mini.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_OF_SYSTEM_SETUP=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7986> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_MDIO=y -+CONFIG_CMD_MII=y -+CONFIG_CMD_MMC=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_USB=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MDIO=y -+CONFIG_DM_MMC=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_USB=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_ETHERNET_ID=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_DM_ETH_PHY=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PHY_AIROHA=y -+CONFIG_PHY_AIROHA_EN8811H=y -+CONFIG_PHY_AIROHA_FW_IN_MMC=y -+CONFIG_PCI=y -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_MMC=y -+CONFIG_MMC_DEFAULT_DEV=1 -+CONFIG_MMC_HS200_SUPPORT=y -+CONFIG_MMC_MTK=y -+CONFIG_MMC_SUPPORTS_TUNING=y -+CONFIG_SUPPORT_EMMC_BOOT=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_USB=y -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+CONFIG_USB_XHCI_MTK=y -+CONFIG_USB_STORAGE=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_MMC=y -+CONFIG_ENV_OFFSET=0x400000 -+CONFIG_ENV_OFFSET_REDUND=0x440000 -+CONFIG_ENV_SIZE=0x40000 -+CONFIG_ENV_SIZE_REDUND=0x40000 -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_SUPPORT_EMMC_BOOT=y -+CONFIG_MMC_HS200_SUPPORT=y -+CONFIG_MMC_MTK=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7986=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+#CONFIG_MTK_SNOR=y -+CONFIG_DM_SPI_FLASH=y -+CONFIG_SPI_FLASH_MTD=y -+CONFIG_SPI_FLASH_WINBOND=y -+# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set -+CONFIG_CMD_SF=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/configs/mt7986a_bpi-r3-mini-snand_defconfig -@@ -0,0 +1,203 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7986=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-bpi-r3-mini" -+CONFIG_DEFAULT_ENV_FILE="bananapi_bpi-r3-mini_snand_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7986a-bpi-r3-mini.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_OF_SYSTEM_SETUP=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7986> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_EXT4=y -+CONFIG_CMD_FAT=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_MDIO=y -+CONFIG_CMD_MII=y -+CONFIG_CMD_MMC=y -+CONFIG_CMD_MTD=y -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+CONFIG_CMD_PWM=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+CONFIG_CMD_USB=y -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MMC=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_DM_USB=y -+CONFIG_DM_PWM=y -+CONFIG_PWM_MTK=y -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+CONFIG_DM_SCSI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_PCI=y -+CONFIG_SCSI_AHCI=y -+CONFIG_SCSI=y -+CONFIG_CMD_SCSI=y -+CONFIG_DM_MDIO=y -+CONFIG_PHY=y -+CONFIG_PHY_MTK_TPHY=y -+CONFIG_PHY_ETHERNET_ID=y -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_DM_ETH_PHY=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCI=y -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_DM_PCI=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_MMC=y -+CONFIG_MMC_DEFAULT_DEV=1 -+CONFIG_MMC_HS200_SUPPORT=y -+CONFIG_MMC_MTK=y -+CONFIG_MMC_SUPPORTS_TUNING=y -+CONFIG_SUPPORT_EMMC_BOOT=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+CONFIG_USB=y -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+CONFIG_USB_XHCI_MTK=y -+CONFIG_USB_STORAGE=y -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_SUPPORT_EMMC_BOOT=y -+CONFIG_MMC_HS200_SUPPORT=y -+CONFIG_MMC_MTK=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PHY_AIROHA=y -+CONFIG_PHY_AIROHA_EN8811H=y -+CONFIG_PHY_AIROHA_FW_IN_UBI=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7986=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_HEXDUMP=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+#CONFIG_MTK_SNOR=y -+#CONFIG_DM_SPI_FLASH=y -+#CONFIG_SPI_FLASH_MTD=y -+#CONFIG_SPI_FLASH_WINBOND=y -+# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set -+#CONFIG_CMD_SF=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y ---- /dev/null -+++ b/bananapi_bpi-r3-mini_snand_env -@@ -0,0 +1,61 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootargs=root=ubi.block=0,fit root=/dev/fit0 rootwait -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-mt7986a-bananapi-bpi-r3-mini -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-mini-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-bananapi_bpi-r3-mini-snand-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-bananapi_bpi-r3-mini-snand-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-bananapi_bpi-r3-mini-squashfs-sysupgrade.itb -+bootfile_en8811h_fw=EthMD32.bin -+bootled_pwr=green:status -+bootled_rec=blue:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) [SPI-NAND] -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load Airoha EN8811H firmware via TFTP then write to NAND.=run boot_tftp_write_en8811h_fw ; run bootmenu_confirm_return -+bootmenu_7=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_8=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_9=Reboot.=reset -+bootmenu_10=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run ubi_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run snand_write_bl2 -+boot_tftp_write_en8811h_fw=tftpboot $loadaddr $bootfile_en8811h_fw && run ubi_write_en8811h_fw -+part_default=production -+part_recovery=recovery -+reset_factory=mw $loadaddr 0xff 0x1f000 ; ubi write $loadaddr ubootenv 0x1f000 ; ubi write $loadaddr ubootenv2 0x1f000 ; ubi remove rootfs_data -+snand_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr 0x0 0x40000 && mtd write bl2 $loadaddr 0x40000 0x40000 && mtd write bl2 $loadaddr 0x80000 0x40000 && mtd write bl2 $loadaddr 0xc0000 0x40000 -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x1f000 dynamic ; ubi check ubootenv2 || ubi create ubootenv2 0x1f000 dynamic -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_read_emmc_install=ubi check emmc_install && ubi read $loadaddr emmc_install -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_fip=run ubi_remove_rootfs ; ubi check fip && ubi remove fip ; ubi create fip 0x200000 static ; ubi write $loadaddr fip 0x200000 -+ubi_write_en8811h_fw=ubi check en8811h-fw && ubi remove en8811h-fw ; ubi create en8811h-fw 0x24000 static ; ubi write $loadaddr en8811h-fw 0x24000 -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" ---- /dev/null -+++ b/bananapi_bpi-r3-mini_emmc_env -@@ -0,0 +1,59 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootargs=root=/dev/fit0 rootwait -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_emmc ; fi -+bootconf=config-mt7986a-bananapi-bpi-r3-mini -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-mini-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-bananapi_bpi-r3-mini-emmc-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-bananapi_bpi-r3-mini-emmc-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-bananapi_bpi-r3-mini-squashfs-sysupgrade.itb -+bootfile_en8811h_fw=EthMD32.bin -+bootled_pwr=green:status -+bootled_rec=blue:status -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) [eMMC] -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from eMMC.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from eMMC.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load Airoha EN8811H firmware via TFTP then write to eMMC.=run boot_tftp_write_en8811h_fw ; run bootmenu_confirm_return -+bootmenu_7=Load BL31+U-Boot FIP via TFTP then write to eMMC.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_8=Load BL2 preloader via TFTP then write to eMMC.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_9=Reboot.=reset -+bootmenu_10=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run emmc_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run emmc_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_emmc=run boot_production ; run boot_recovery -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run emmc_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run emmc_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run emmc_write_fip -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run emmc_write_bl2 -+boot_tftp_write_en8811h_fw=tftpboot $loadaddr $bootfile_en8811h_fw && run emmc_write_en8811h_fw -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+mmc_write_vol=imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$image_size && mmc write $loadaddr 0x$part_addr 0x$image_size -+mmc_read_vol=mmc read $loadaddr $part_addr 0x100 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size && setexpr filesize $image_size * 0x200 -+part_default=production -+part_recovery=recovery -+reset_factory=eraseenv && reset -+emmc_read_production=part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_read_vol -+emmc_read_recovery=part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_read_vol -+emmc_write_en8811h_fw=mmc partconf 0 1 2 2 && mmc erase 0x0 0x120 && mmc write $fileaddr 0x0 0x120 ; mmc partconf 0 1 1 0 -+emmc_write_bl2=mmc partconf 0 1 1 1 && mmc erase 0x0 0x400 && mmc write $fileaddr 0x0 0x400 ; mmc partconf 0 1 1 0 -+emmc_write_fip=mmc erase 0x3400 0x2000 && mmc write $fileaddr 0x3400 0x2000 && mmc erase 0x2000 0x800 -+emmc_write_production=part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_write_vol -+emmc_write_recovery=part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_write_vol -+_init_env=setenv _init_env ; setenv _create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" ---- /dev/null -+++ b/arch/arm/dts/mt7986a-bpi-r3-mini.dts -@@ -0,0 +1,238 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+#include "mt7986.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "Bananapi BPi-R3 Mini"; -+ compatible = "mediatek,mt7986", "mediatek,mt7986-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x80000000>; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ button-reset { -+ label = "reset"; -+ linux,code = ; -+ gpios = <&gpio 7 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ status_led: led-0 { -+ label = "green:status"; -+ gpios = <&gpio 19 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ led-1 { -+ label = "blue:wlan2g"; -+ gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ led-2 { -+ label = "blue:wlan5g"; -+ gpios = <&gpio 2 GPIO_ACTIVE_HIGH>; -+ }; -+ }; -+ -+ reg_1p8v: regulator-1p8v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-1.8V"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ reg_3p3v: regulator-3p3v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-3.3V"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+}; -+ -+ð { -+ status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&mdio_pins>; -+ -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ phy-handle = <&phy14>; -+ -+ phy14: eth-phy@e { -+ compatible = "ethernet-phy-id03a2.a411"; -+ reg = <14>; -+ -+ airoha,rx-pol-reverse; -+ -+ reset-gpios = <&gpio 49 GPIO_ACTIVE_LOW>; -+ reset-assert-us = <10000>; -+ reset-deassert-us = <20000>; -+ }; -+}; -+ -+&mmc0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&mmc0_pins_default>; -+ bus-width = <8>; -+ max-frequency = <200000000>; -+ cap-mmc-highspeed; -+ cap-mmc-hw-reset; -+ vmmc-supply = <®_3p3v>; -+ vqmmc-supply = <®_1p8v>; -+ non-removable; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ mdio_pins: mdio-pins { -+ mux { -+ function = "eth"; -+ groups = "mdc_mdio"; -+ }; -+ -+ conf-en8811-pwr-a { -+ pins = "GPIO_11"; -+ drive-strength = ; -+ bias-pull-down = ; -+ output-low; -+ }; -+ -+ conf-en8811-pwr-b { -+ pins = "GPIO_12"; -+ drive-strength = ; -+ bias-pull-down = ; -+ output-low; -+ }; -+ }; -+ -+ mmc0_pins_default: mmc0default { -+ mux { -+ function = "flash"; -+ groups = "emmc_51"; -+ }; -+ -+ conf-cmd-dat { -+ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", -+ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", -+ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; -+ input-enable; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-clk { -+ pins = "EMMC_CK"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ -+ conf-dsl { -+ pins = "EMMC_DSL"; -+ bias-pull-down = ; -+ }; -+ -+ conf-rst { -+ pins = "EMMC_RSTB"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ }; -+ -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+ -+ pwm_pins: pwm0-pins-func-1 { -+ mux { -+ function = "pwm"; -+ groups = "pwm0"; -+ }; -+ }; -+}; -+ -+&pwm { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm_pins>; -+ status = "okay"; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <1>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <20000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0 0x200000>; -+ }; -+ -+ partition@200000 { -+ label = "ubi"; -+ reg = <0x200000 0x7e00000>; -+ }; -+ }; -+ }; -+ -+}; -+ -+&uart0 { -+ status = "okay"; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; diff --git a/lede/package/boot/uboot-mediatek/patches/443-add-nokia_ea0326gmp.patch b/lede/package/boot/uboot-mediatek/patches/443-add-nokia_ea0326gmp.patch deleted file mode 100644 index 0b72e1ee98..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/443-add-nokia_ea0326gmp.patch +++ /dev/null @@ -1,413 +0,0 @@ ---- /dev/null -+++ b/configs/mt7981_nokia_ea0326gmp_defconfig -@@ -0,0 +1,163 @@ -+CONFIG_ARM=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TARGET_MT7981=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7981-nokia-ea0326gmp" -+CONFIG_DEFAULT_ENV_FILE="nokia_ea0326gmp_env" -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7981-nokia-ea0326gmp.dtb" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+CONFIG_DEBUG_UART=y -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+CONFIG_SMBIOS_PRODUCT_NAME="" -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_MENU_SHOW=y -+CONFIG_CFB_CONSOLE_ANSI=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_GPIO_HOG=y -+CONFIG_CMD_ENV_FLAGS=y -+CONFIG_FIT=y -+CONFIG_FIT_ENABLE_SHA256_SUPPORT=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+CONFIG_LOGLEVEL=7 -+CONFIG_LOG=y -+CONFIG_SYS_PROMPT="MT7981> " -+CONFIG_CMD_BOOTMENU=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_CPU=y -+CONFIG_CMD_DHCP=y -+CONFIG_CMD_DM=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ENV_READMEM=y -+CONFIG_CMD_ERASEENV=y -+# CONFIG_CMD_EXT4 is not set -+# CONFIG_CMD_FAT is not set -+CONFIG_CMD_FDT=y -+# CONFIG_CMD_FS_GENERIC is not set -+# CONFIG_CMD_FS_UUID is not set -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_GPT=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_LED=y -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_MBR is not set -+CONFIG_CMD_MTD=y -+# CONFIG_CMD_PCI is not set -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_SF_TEST=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_PXE=y -+# CONFIG_CMD_PWM is not set -+CONFIG_CMD_SMC=y -+CONFIG_CMD_TFTPBOOT=y -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_PART=y -+CONFIG_CMD_RARP=y -+CONFIG_CMD_SETEXPR=y -+CONFIG_CMD_SLEEP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_STRINGS=y -+# CONFIG_CMD_USB is not set -+# CONFIG_CMD_FLASH is not set -+CONFIG_CMD_UUID=y -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DM_MTD=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+# CONFIG_DM_USB is not set -+# CONFIG_DM_PWM is not set -+# CONFIG_PWM_MTK is not set -+CONFIG_HUSH_PARSER=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PARTITION_UUIDS=y -+CONFIG_NETCONSOLE=y -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_CLK=y -+CONFIG_DM_GPIO=y -+# CONFIG_DM_SCSI is not set -+# CONFIG_AHCI is not set -+CONFIG_PHY=y -+# CONFIG_PHY_MTK_TPHY is not set -+CONFIG_PHY_FIXED=y -+CONFIG_MTK_AHCI=y -+CONFIG_DM_ETH=y -+CONFIG_MEDIATEK_ETH=y -+# CONFIG_PCI is not set -+# CONFIG_MMC is not set -+# CONFIG_DM_MMC is not set -+CONFIG_MTD=y -+CONFIG_MTD_UBI_FASTMAP=y -+# CONFIG_DM_PCI is not set -+# CONFIG_PCIE_MEDIATEK is not set -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7981=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_WDT_MTK=y -+CONFIG_LZO=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y -+CONFIG_RANDOM_UUID=y -+CONFIG_REGEX=y -+# CONFIG_USB is not set -+# CONFIG_USB_HOST is not set -+# CONFIG_USB_XHCI_HCD is not set -+# CONFIG_USB_XHCI_MTK is not set -+# CONFIG_USB_STORAGE is not set -+CONFIG_OF_EMBED=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_ENV_SIZE_REDUND=0x1f000 -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_MTD_SPI_NAND=y -+CONFIG_MTK_SPIM=y -+CONFIG_CMD_NAND=y -+CONFIG_CMD_NAND_TRIMFFS=y -+CONFIG_LMB_MAX_REGIONS=64 -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" ---- /dev/null -+++ b/arch/arm/dts/mt7981-nokia-ea0326gmp.dts -@@ -0,0 +1,186 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+#include "mt7981.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "Nokia EA0326GMP"; -+ compatible = "mediatek,mt7981", "mediatek,mt7981-rfb"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x10000000>; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ -+ button-reset { -+ label = "reset"; -+ linux,code = ; -+ gpios = <&gpio 1 GPIO_ACTIVE_LOW>; -+ }; -+ -+ button-wps { -+ label = "wps"; -+ linux,code = ; -+ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ gpio-leds { -+ compatible = "gpio-leds"; -+ -+ power_led: led-0 { -+ label = "green:power"; -+ gpios = <&gpio 4 GPIO_ACTIVE_LOW>; -+ default-state = "on"; -+ }; -+ -+ led-1 { -+ label = "green:wan"; -+ gpios = <&gpio 5 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ }; -+ -+ led-2 { -+ label = "red:wan"; -+ gpios = <&gpio 6 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ }; -+ -+ led-3 { -+ label = "green:lan"; -+ gpios = <&gpio 7 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ }; -+ -+ led-4 { -+ label = "green:wlan"; -+ gpios = <&gpio 8 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ }; -+ -+ led-5 { -+ label = "green:wps"; -+ gpios = <&gpio 9 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ }; -+ }; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; -+ -+&pinctrl { -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <2>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x00000 0x0100000>; -+ }; -+ -+ partition@100000 { -+ label = "u-boot-env"; -+ reg = <0x0100000 0x0080000>; -+ }; -+ -+ partition@180000 { -+ label = "factory"; -+ reg = <0x180000 0x0200000>; -+ }; -+ -+ partition@380000 { -+ label = "fip"; -+ reg = <0x380000 0x0200000>; -+ }; -+ -+ partition@580000 { -+ label = "config"; -+ reg = <0x580000 0x200000>; -+ }; -+ -+ partition@780000 { -+ label = "config2"; -+ reg = <0x780000 0x200000>; -+ }; -+ -+ partition@980000 { -+ label = "ubi"; -+ reg = <0x980000 0x7680000>; -+ compatible = "linux,ubi"; -+ }; -+ }; -+ }; -+}; -+ -+&uart0 { -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/nokia_ea0326gmp_env -@@ -0,0 +1,55 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootargs=root=/dev/fit0 rootwait -+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-nokia_ea0326gmp-initramfs-recovery.itb -+bootfile_bl2=openwrt-mediatek-filogic-nokia_ea0326gmp-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-nokia_ea0326gmp-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-nokia_ea0326gmp-squashfs-sysupgrade.itb -+bootled_pwr=green:power -+bootled_rec=green:power -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu -+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever -+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off -+boot_recovery=led $bootled_rec on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off -+boot_ubi=run boot_production ; run boot_recovery ; run boot_tftp_forever -+boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run ubi_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2 -+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800 -+mtd_write_fip=mtd erase fip && mtd write fip $loadaddr -+mtd_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x100000 dynamic 0 || run ubi_format ; ubi check ubootenv2 || ubi create ubootenv2 0x100000 dynamic 1 || run ubi_format -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/boot/uboot-mediatek/patches/452-add-xiaomi-redmi-ax6s.patch b/lede/package/boot/uboot-mediatek/patches/452-add-xiaomi-redmi-ax6s.patch deleted file mode 100644 index 28cc5d73d7..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/452-add-xiaomi-redmi-ax6s.patch +++ /dev/null @@ -1,320 +0,0 @@ -From 57dc777bddf0baf3c27177576c40b5113309ce54 Mon Sep 17 00:00:00 2001 -From: Chuanhong Guo -Date: Sat, 2 Mar 2024 20:30:16 +0800 -Subject: [PATCH] add xiaomi redmi ax6s - ---- - arch/arm/dts/Makefile | 1 + - .../dts/mt7622-xiaomi-redmi-router-ax6s.dts | 166 ++++++++++++++++++ - ...omi_redmi-router-ax6s-ubi-loader_defconfig | 98 +++++++++++ - xiaomi-redmi-router-ax6s-ubi-loader_env | 22 +++ - 4 files changed, 287 insertions(+) - create mode 100644 arch/arm/dts/mt7622-xiaomi-redmi-router-ax6s.dts - create mode 100644 configs/mt7622_xiaomi_redmi-router-ax6s-ubi-loader_defconfig - create mode 100644 xiaomi-redmi-router-ax6s-ubi-loader_env - ---- a/arch/arm/dts/Makefile -+++ b/arch/arm/dts/Makefile -@@ -1425,6 +1425,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ - mt7622-linksys-e8450-ubi.dtb \ - mt7622-ubnt-unifi-6-lr.dtb \ - mt7622-ubnt-unifi-6-lr-v3.dtb \ -+ mt7622-xiaomi-redmi-router-ax6s.dtb \ - mt7623n-bananapi-bpi-r2.dtb \ - mt7629-rfb.dtb \ - mt7981-rfb.dtb \ ---- /dev/null -+++ b/arch/arm/dts/mt7622-xiaomi-redmi-router-ax6s.dts -@@ -0,0 +1,166 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT -+ -+/dts-v1/; -+#include -+#include -+#include "mt7622.dtsi" -+#include "mt7622-u-boot.dtsi" -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "Xiaomi Redmi Router AX6S"; -+ compatible = "xiaomi,redmi-router-ax6s", "mediatek,mt7622"; -+ -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ aliases { -+ spi0 = &snand; -+ ethernet0 = ð -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x8000000>; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_power_blue: power_blue { -+ function = LED_FUNCTION_POWER; -+ color = ; -+ gpios = <&gpio 18 GPIO_ACTIVE_LOW>; -+ }; -+ -+ led_power_amber: power_amber { -+ function = LED_FUNCTION_POWER; -+ color = ; -+ gpios = <&gpio 17 GPIO_ACTIVE_LOW>; -+ }; -+ -+ led_net_blue: net_blue { -+ label = "blue:net"; -+ gpios = <&gpio 1 GPIO_ACTIVE_LOW>; -+ }; -+ -+ led_net_amber: net_amber { -+ label = "amber:net"; -+ gpios = <&gpio 16 GPIO_ACTIVE_LOW>; -+ }; -+ -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ -+ reset { -+ label = "reset"; -+ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ }; -+ -+ mesh { -+ label = "mesh"; -+ gpios = <&gpio 102 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ linux,input-type = ; -+ }; -+ }; -+ -+ reg_1p8v: regulator-1p8v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-1.8V"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ reg_3p3v: regulator-3p3v { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-3.3V"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+}; -+ -+&pcie { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pcie0_pins>; -+ status = "okay"; -+ -+ pcie@0,0 { -+ status = "okay"; -+ }; -+}; -+ -+&pinctrl { -+ pcie0_pins: pcie0-pins { -+ mux { -+ function = "pcie"; -+ groups = "pcie0_pad_perst", -+ "pcie0_1_waken", -+ "pcie0_1_clkreq"; -+ }; -+ }; -+ -+ snfi_pins: snfi-pins { -+ mux { -+ function = "flash"; -+ groups = "snfi"; -+ }; -+ }; -+ -+ uart0_pins: uart0 { -+ mux { -+ function = "uart"; -+ groups = "uart0_0_tx_rx" ; -+ }; -+ }; -+ -+ watchdog_pins: watchdog-default { -+ mux { -+ function = "watchdog"; -+ groups = "watchdog"; -+ }; -+ }; -+}; -+ -+&snand { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&snfi_pins>; -+ quad-spi; -+ status = "okay"; -+}; -+ -+&uart0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart0_pins>; -+ mediatek,force-highspeed; -+ status = "okay"; -+}; -+ -+&watchdog { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&watchdog_pins>; -+ status = "okay"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <0>; -+ phy-mode = "2500base-x"; -+ mediatek,switch = "mt7531"; -+ reset-gpios = <&gpio 54 GPIO_ACTIVE_HIGH>; -+ -+ fixed-link { -+ speed = <2500>; -+ full-duplex; -+ }; -+}; ---- /dev/null -+++ b/configs/mt7622_xiaomi_redmi-router-ax6s-ubi-loader_defconfig -@@ -0,0 +1,98 @@ -+CONFIG_ARM=y -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_ARCH_MEDIATEK=y -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_DEFAULT_DEVICE_TREE="mt7622-xiaomi-redmi-router-ax6s" -+CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=25000000 -+CONFIG_SYS_LOAD_ADDR=0x40080000 -+CONFIG_PCI=y -+CONFIG_DEBUG_UART=y -+CONFIG_FIT=y -+CONFIG_BOOTDELAY=30 -+CONFIG_AUTOBOOT_KEYED=y -+CONFIG_DEFAULT_FDT_FILE="mediatek/mt7622-xiaomi-redmi-router-ax6s" -+CONFIG_LOGLEVEL=7 -+CONFIG_PRE_CONSOLE_BUFFER=y -+CONFIG_LOG=y -+CONFIG_BOARD_LATE_INIT=y -+CONFIG_LAST_STAGE_INIT=y -+CONFIG_HUSH_PARSER=y -+# CONFIG_AUTO_COMPLETE is not set -+CONFIG_SYS_PROMPT="MT7622> " -+CONFIG_CMD_LICENSE=y -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_ENV_FLAGS=y -+# CONFIG_CMD_UNLZ4 is not set -+# CONFIG_CMD_UNZIP is not set -+CONFIG_CMD_GPIO=y -+CONFIG_CMD_MTD=y -+# CONFIG_CMD_BOOTP is not set -+CONFIG_CMD_TFTPSRV=y -+CONFIG_CMD_PING=y -+CONFIG_CMD_HASH=y -+CONFIG_CMD_SMC=y -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+CONFIG_CMD_MTDPARTS=y -+CONFIG_MTDPARTS_DEFAULT="mtdparts=spi-nand0:512k(preloader),2816k(reserved),117248k(ubi)" -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_DOS_PARTITION=y -+CONFIG_EFI_PARTITION=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_DEFAULT_ENV_FILE="xiaomi-redmi-router-ax6s-ubi-loader_env" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+CONFIG_VERSION_VARIABLE=y -+CONFIG_PROT_UDP=y -+CONFIG_BOOTP_SEND_HOSTNAME=y -+CONFIG_NET_RANDOM_ETHADDR=y -+CONFIG_NETCONSOLE=y -+CONFIG_USE_IPADDR=y -+CONFIG_IPADDR="192.168.1.1" -+CONFIG_USE_SERVERIP=y -+CONFIG_SERVERIP="192.168.1.254" -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+CONFIG_BUTTON=y -+CONFIG_BUTTON_GPIO=y -+CONFIG_CLK=y -+CONFIG_GPIO_HOG=y -+CONFIG_LED=y -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+# CONFIG_MMC is not set -+CONFIG_MTD=y -+CONFIG_DM_MTD=y -+CONFIG_MTK_SPI_NAND=y -+CONFIG_MTK_SPI_NAND_MTD=y -+CONFIG_UBI_SILENCE_MSG=y -+CONFIG_MTD_UBI_FASTMAP=y -+CONFIG_PHY_FIXED=y -+CONFIG_MEDIATEK_ETH=y -+CONFIG_PCIE_MEDIATEK=y -+CONFIG_PHY=y -+CONFIG_PINCTRL=y -+CONFIG_PINCONF=y -+CONFIG_PINCTRL_MT7622=y -+CONFIG_POWER_DOMAIN=y -+CONFIG_MTK_POWER_DOMAIN=y -+CONFIG_DM_REGULATOR=y -+CONFIG_DM_REGULATOR_FIXED=y -+CONFIG_DM_REGULATOR_GPIO=y -+CONFIG_RAM=y -+CONFIG_DM_SERIAL=y -+CONFIG_MTK_SERIAL=y -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_UBIFS_SILENCE_MSG=y -+CONFIG_LZ4=y -+CONFIG_ZSTD=y -+CONFIG_HEXDUMP=y ---- /dev/null -+++ b/xiaomi-redmi-router-ax6s-ubi-loader_env -@@ -0,0 +1,22 @@ -+ipaddr=192.168.1.1 -+serverip=192.168.1.254 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootled_pwr=power_blue -+bootled_rec=power_amber -+bootcmd=run boot_or_recovery -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-mt7622-xiaomi_redmi-router-ax6s-initramfs-recovery.itb -+bootfile_upg=openwrt-mediatek-mt7622-xiaomi_redmi-router-ax6s-squashfs-sysupgrade.itb -+boot_or_recovery=run boot_production ; led $bootled_pwr off ; led $bootled_rec on ; if ubi check fit ; then run boot_tftp_forever ; else run tftp_production ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_forever=while true ; do run boot_tftp ; sleep 1 ; done -+boot_production=run ubi_read_production && bootm $loadaddr#$bootconf -+ubi_format=ubi detach ; mtd erase ubi && ubi part ubi -+ubi_init=ubi part ubi || run ubi_format -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize -+ubi_read_production=run ubi_init && ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+tftp_production=tftpboot $loadaddr $bootfile_upg && iminfo $loadaddr && run ubi_write_production && reset diff --git a/lede/package/boot/uboot-mediatek/patches/453-add-openwrt-one.patch b/lede/package/boot/uboot-mediatek/patches/453-add-openwrt-one.patch deleted file mode 100644 index 25d2733d1c..0000000000 --- a/lede/package/boot/uboot-mediatek/patches/453-add-openwrt-one.patch +++ /dev/null @@ -1,3949 +0,0 @@ ---- /dev/null -+++ b/arch/arm/dts/openwrt-one.dts -@@ -0,0 +1,203 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2024 John Crispin -+ */ -+ -+/dts-v1/; -+#include "mt7981.dtsi" -+#include -+#include -+ -+/ { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ model = "OpenWrt One"; -+ compatible = "openwrt,one", "mediatek,mt7981"; -+ chosen { -+ stdout-path = &uart0; -+ tick-timer = &timer0; -+ }; -+ -+ memory@40000000 { -+ device_type = "memory"; -+ reg = <0x40000000 0x10000000>; -+ }; -+ -+ keys { -+ compatible = "gpio-keys"; -+ -+ user { -+ label = "front"; -+ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ }; -+ -+ reset { -+ label = "back"; -+ gpios = <&gpio 1 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ red { -+ label = "red"; -+ gpios = <&gpio 9 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ white { -+ label = "white"; -+ gpios = <&gpio 13 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ green { -+ label = "green"; -+ gpios = <&gpio 15 GPIO_ACTIVE_HIGH>; -+ }; -+ }; -+}; -+ -+&uart0 { -+ status = "okay"; -+}; -+ -+ð { -+ status = "okay"; -+ mediatek,gmac-id = <1>; -+ phy-mode = "gmii"; -+ phy-handle = <&phy0>; -+ -+ phy0: eth-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; -+ -+&pinctrl { -+ spi_flash_pins: spi0-pins-func-1 { -+ mux { -+ function = "flash"; -+ groups = "spi0", "spi0_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; -+ drive-strength = ; -+ bias-pull-up = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+ -+ spi2_flash_pins: spi2-spi2-pins { -+ mux { -+ function = "spi"; -+ groups = "spi2", "spi2_wp_hold"; -+ }; -+ -+ conf-pu { -+ pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ -+ conf-pd { -+ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; -+ drive-strength = ; -+ bias-pull-down = ; -+ }; -+ }; -+}; -+ -+&spi0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ support_quad; -+ tick_dly = <2>; -+ sample_sel = <0>; -+ -+ spi_nand@0 { -+ compatible = "spi-nand"; -+ reg = <0>; -+ spi-max-frequency = <52000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0 0x100000>; -+ }; -+ -+ partition@200000 { -+ label = "ubi"; -+ reg = <0x100000 0x7f00000>; -+ }; -+ }; -+ }; -+}; -+ -+&spi2 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi2_flash_pins>; -+ status = "okay"; -+ must_tx; -+ enhance_timing; -+ dma_ext; -+ ipm_design; -+ tick_dly = <2>; -+ sample_sel = <0>; -+ -+ spi_nor@0 { -+ compatible = "jedec,spi-nor"; -+ reg = <0>; -+ spi-max-frequency = <5000000>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@00000 { -+ label = "bl2-nor"; -+ reg = <0x00000 0x0040000>; -+ }; -+ -+ partition@40000 { -+ label = "factory"; -+ reg = <0x40000 0x00C0000>; -+ }; -+ -+ partition@100000 { -+ label = "fip-nor"; -+ reg = <0x100000 0x0080000>; -+ }; -+ -+ partition@180000 { -+ label = "recovery"; -+ reg = <0x180000 0xc80000>; -+ }; -+ }; -+ }; -+}; -+ -+&watchdog { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/configs/mt7981_openwrt-one-nor_defconfig -@@ -0,0 +1,1811 @@ -+# -+# Automatically generated file; DO NOT EDIT. -+# U-Boot 2024.01 Configuration -+# -+ -+# -+# Compiler: aarch64-openwrt-linux-musl-gcc (OpenWrt GCC 13.2.0 r26144+12-219018185e) 13.2.0 -+# -+CONFIG_CREATE_ARCH_SYMLINK=y -+CONFIG_SYS_CACHE_SHIFT_6=y -+CONFIG_SYS_CACHELINE_SIZE=64 -+CONFIG_LINKER_LIST_ALIGN=8 -+# CONFIG_ARC is not set -+CONFIG_ARM=y -+# CONFIG_M68K is not set -+# CONFIG_MICROBLAZE is not set -+# CONFIG_MIPS is not set -+# CONFIG_NIOS2 is not set -+# CONFIG_PPC is not set -+# CONFIG_RISCV is not set -+# CONFIG_SANDBOX is not set -+# CONFIG_SH is not set -+# CONFIG_X86 is not set -+# CONFIG_XTENSA is not set -+CONFIG_SYS_ARCH="arm" -+CONFIG_SYS_CPU="armv8" -+CONFIG_SYS_SOC="mediatek" -+CONFIG_SYS_VENDOR="mediatek" -+CONFIG_SYS_BOARD="mt7981" -+CONFIG_SYS_CONFIG_NAME="mt7981" -+ -+# -+# Skipping low level initialization functions -+# -+# CONFIG_SKIP_LOWLEVEL_INIT is not set -+# CONFIG_SKIP_LOWLEVEL_INIT_ONLY is not set -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_SYS_NONCACHED_MEMORY=0x100000 -+# CONFIG_SYS_ICACHE_OFF is not set -+# CONFIG_SYS_DCACHE_OFF is not set -+ -+# -+# ARM architecture -+# -+CONFIG_ARM64=y -+CONFIG_ARM64_CRC32=y -+CONFIG_COUNTER_FREQUENCY=0 -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_INIT_SP_RELATIVE=y -+CONFIG_SYS_INIT_SP_BSS_OFFSET=524288 -+# CONFIG_GIC_V3_ITS is not set -+CONFIG_STATIC_RELA=y -+CONFIG_DMA_ADDR_T_64BIT=y -+CONFIG_GPIO_EXTRA_HEADER=y -+CONFIG_ARM_ASM_UNIFIED=y -+# CONFIG_SYS_ARM_CACHE_CP15 is not set -+# CONFIG_SYS_ARM_MMU is not set -+# CONFIG_SYS_ARM_MPU is not set -+CONFIG_SYS_ARM_ARCH=8 -+CONFIG_SYS_ARM_CACHE_WRITEBACK=y -+# CONFIG_SYS_ARM_CACHE_WRITETHROUGH is not set -+# CONFIG_SYS_ARM_CACHE_WRITEALLOC is not set -+# CONFIG_ARCH_CPU_INIT is not set -+CONFIG_SYS_ARCH_TIMER=y -+CONFIG_ARM_SMCCC=y -+# CONFIG_SYS_L2_PL310 is not set -+# CONFIG_SPL_SYS_L2_PL310 is not set -+# CONFIG_SYS_L2CACHE_OFF is not set -+# CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK is not set -+# CONFIG_USE_ARCH_MEMCPY is not set -+# CONFIG_USE_ARCH_MEMSET is not set -+CONFIG_ARM64_SUPPORT_AARCH32=y -+# CONFIG_ARCH_AT91 is not set -+# CONFIG_ARCH_DAVINCI is not set -+# CONFIG_ARCH_HISTB is not set -+# CONFIG_ARCH_KIRKWOOD is not set -+# CONFIG_ARCH_MVEBU is not set -+# CONFIG_ARCH_ORION5X is not set -+# CONFIG_TARGET_STV0991 is not set -+# CONFIG_ARCH_BCM283X is not set -+# CONFIG_ARCH_BCMSTB is not set -+# CONFIG_ARCH_BCMBCA is not set -+# CONFIG_TARGET_VEXPRESS_CA9X4 is not set -+# CONFIG_TARGET_BCMNS is not set -+# CONFIG_TARGET_BCMNS2 is not set -+# CONFIG_TARGET_BCMNS3 is not set -+# CONFIG_ARCH_EXYNOS is not set -+# CONFIG_ARCH_S5PC1XX is not set -+# CONFIG_ARCH_HIGHBANK is not set -+# CONFIG_ARCH_INTEGRATOR is not set -+# CONFIG_ARCH_IPQ40XX is not set -+# CONFIG_ARCH_KEYSTONE is not set -+# CONFIG_ARCH_K3 is not set -+# CONFIG_ARCH_OMAP2PLUS is not set -+# CONFIG_ARCH_MESON is not set -+CONFIG_ARCH_MEDIATEK=y -+# CONFIG_ARCH_LPC32XX is not set -+# CONFIG_ARCH_IMX8 is not set -+# CONFIG_ARCH_IMX8M is not set -+# CONFIG_ARCH_IMX8ULP is not set -+# CONFIG_ARCH_IMX9 is not set -+# CONFIG_ARCH_IMXRT is not set -+# CONFIG_ARCH_MX23 is not set -+# CONFIG_ARCH_MX28 is not set -+# CONFIG_ARCH_MX31 is not set -+# CONFIG_ARCH_MX7ULP is not set -+# CONFIG_ARCH_MX7 is not set -+# CONFIG_ARCH_MX6 is not set -+# CONFIG_ARCH_MX5 is not set -+# CONFIG_ARCH_NEXELL is not set -+# CONFIG_ARCH_NPCM is not set -+# CONFIG_ARCH_APPLE is not set -+# CONFIG_ARCH_OWL is not set -+# CONFIG_ARCH_QEMU is not set -+# CONFIG_ARCH_RMOBILE is not set -+# CONFIG_ARCH_SNAPDRAGON is not set -+# CONFIG_ARCH_SOCFPGA is not set -+# CONFIG_ARCH_SUNXI is not set -+# CONFIG_ARCH_U8500 is not set -+# CONFIG_ARCH_VERSAL is not set -+# CONFIG_ARCH_VERSAL_NET is not set -+# CONFIG_ARCH_VF610 is not set -+# CONFIG_ARCH_ZYNQ is not set -+# CONFIG_ARCH_ZYNQMP_R5 is not set -+# CONFIG_ARCH_ZYNQMP is not set -+# CONFIG_ARCH_TEGRA is not set -+# CONFIG_ARCH_VEXPRESS64 is not set -+# CONFIG_TARGET_CORSTONE1000 is not set -+# CONFIG_TARGET_TOTAL_COMPUTE is not set -+# CONFIG_TARGET_LS2080A_EMU is not set -+# CONFIG_TARGET_LS1088AQDS is not set -+# CONFIG_TARGET_LS2080AQDS is not set -+# CONFIG_TARGET_LS2080ARDB is not set -+# CONFIG_TARGET_LS2081ARDB is not set -+# CONFIG_TARGET_LX2160ARDB is not set -+# CONFIG_TARGET_LX2160AQDS is not set -+# CONFIG_TARGET_LX2162AQDS is not set -+# CONFIG_TARGET_HIKEY is not set -+# CONFIG_TARGET_HIKEY960 is not set -+# CONFIG_TARGET_POPLAR is not set -+# CONFIG_TARGET_LS1012AQDS is not set -+# CONFIG_TARGET_LS1012ARDB is not set -+# CONFIG_TARGET_LS1012A2G5RDB is not set -+# CONFIG_TARGET_LS1012AFRWY is not set -+# CONFIG_TARGET_LS1012AFRDM is not set -+# CONFIG_TARGET_LS1028AQDS is not set -+# CONFIG_TARGET_LS1028ARDB is not set -+# CONFIG_TARGET_LS1088ARDB is not set -+# CONFIG_TARGET_LS1021AQDS is not set -+# CONFIG_TARGET_LS1021ATWR is not set -+# CONFIG_TARGET_PG_WCOM_SELI8 is not set -+# CONFIG_TARGET_PG_WCOM_EXPU1 is not set -+# CONFIG_TARGET_LS1021ATSN is not set -+# CONFIG_TARGET_LS1021AIOT is not set -+# CONFIG_TARGET_LS1043AQDS is not set -+# CONFIG_TARGET_LS1043ARDB is not set -+# CONFIG_TARGET_LS1046AQDS is not set -+# CONFIG_TARGET_LS1046ARDB is not set -+# CONFIG_TARGET_LS1046AFRWY is not set -+# CONFIG_TARGET_SL28 is not set -+# CONFIG_TARGET_TEN64 is not set -+# CONFIG_ARCH_UNIPHIER is not set -+# CONFIG_ARCH_SYNQUACER is not set -+# CONFIG_ARCH_STM32 is not set -+# CONFIG_ARCH_STI is not set -+# CONFIG_ARCH_STM32MP is not set -+# CONFIG_ARCH_ROCKCHIP is not set -+# CONFIG_ARCH_OCTEONTX is not set -+# CONFIG_ARCH_OCTEONTX2 is not set -+# CONFIG_TARGET_THUNDERX_88XX is not set -+# CONFIG_ARCH_ASPEED is not set -+# CONFIG_TARGET_DURIAN is not set -+# CONFIG_TARGET_POMELO is not set -+# CONFIG_TARGET_PRESIDIO_ASIC is not set -+# CONFIG_TARGET_XENGUEST_ARM64 is not set -+# CONFIG_ARCH_GXP is not set -+# CONFIG_STATIC_MACH_TYPE is not set -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_LEN=0x400000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_ENV_SOURCE_FILE="" -+CONFIG_SF_DEFAULT_SPEED=1000000 -+CONFIG_SF_DEFAULT_MODE=0x0 -+CONFIG_ENV_SIZE=0x8000 -+CONFIG_DM_GPIO=y -+CONFIG_DEFAULT_DEVICE_TREE="openwrt-one" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_MULTI_DTB_FIT_UNCOMPRESS_SZ=0x8000 -+CONFIG_DM_RESET=y -+CONFIG_SYS_MONITOR_LEN=0 -+# CONFIG_MT8512 is not set -+# CONFIG_TARGET_MT7622 is not set -+# CONFIG_TARGET_MT7623 is not set -+# CONFIG_TARGET_MT7629 is not set -+CONFIG_TARGET_MT7981=y -+# CONFIG_TARGET_MT7986 is not set -+# CONFIG_TARGET_MT7988 is not set -+# CONFIG_TARGET_MT8183 is not set -+# CONFIG_TARGET_MT8512 is not set -+# CONFIG_TARGET_MT8516 is not set -+# CONFIG_TARGET_MT8518 is not set -+CONFIG_MTK_BROM_HEADER_INFO="media=snand;nandinfo=2k+64" -+CONFIG_RESET_BUTTON_LABEL="back" -+CONFIG_RESET_BUTTON_SETTLE_DELAY=0 -+CONFIG_ERR_PTR_OFFSET=0x0 -+# CONFIG_SPL is not set -+CONFIG_BOOTSTAGE_STASH_ADDR=0x0 -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+# CONFIG_DEBUG_UART_BOARD_INIT is not set -+CONFIG_IDENT_STRING="" -+CONFIG_SYS_CLK_FREQ=0 -+# CONFIG_CHIP_DIP_SCAN is not set -+# CONFIG_CMO_BY_VA_ONLY is not set -+# CONFIG_ARMV8_MULTIENTRY is not set -+# CONFIG_ARMV8_SET_SMPEN is not set -+# CONFIG_ARMV8_SWITCH_TO_EL1 is not set -+ -+# -+# ARMv8 secure monitor firmware -+# -+# CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT is not set -+CONFIG_PSCI_RESET=y -+# CONFIG_ARMV8_PSCI is not set -+# CONFIG_ARMV8_EA_EL3_FIRST is not set -+# CONFIG_ARMV8_CRYPTO is not set -+# CONFIG_CMD_DEKBLOB is not set -+# CONFIG_IMX_CAAM_DEK_ENCAP is not set -+# CONFIG_IMX_OPTEE_DEK_ENCAP is not set -+# CONFIG_IMX_SECO_DEK_ENCAP is not set -+# CONFIG_IMX_ELE_DEK_ENCAP is not set -+# CONFIG_CMD_HDMIDETECT is not set -+CONFIG_IMX_DCD_ADDR=0x00910000 -+CONFIG_SYS_MEM_TOP_HIDE=0x0 -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+ -+# -+# ARM debug -+# -+CONFIG_BUILD_TARGET="" -+# CONFIG_PCI is not set -+CONFIG_FWU_NUM_BANKS=2 -+CONFIG_FWU_NUM_IMAGES_PER_BANK=2 -+CONFIG_DEBUG_UART=y -+# CONFIG_AHCI is not set -+# CONFIG_OF_BOARD_FIXUP is not set -+ -+# -+# Functionality shared between NXP SoCs -+# -+# CONFIG_NXP_ESBC is not set -+ -+# -+# General setup -+# -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_CC_IS_GCC=y -+CONFIG_GCC_VERSION=130200 -+CONFIG_CLANG_VERSION=0 -+CONFIG_CC_OPTIMIZE_FOR_SIZE=y -+# CONFIG_CC_OPTIMIZE_FOR_SPEED is not set -+# CONFIG_CC_OPTIMIZE_FOR_DEBUG is not set -+# CONFIG_OPTIMIZE_INLINING is not set -+CONFIG_ARCH_SUPPORTS_LTO=y -+# CONFIG_LTO is not set -+CONFIG_CC_HAS_ASM_INLINE=y -+# CONFIG_XEN is not set -+# CONFIG_ENV_VARS_UBOOT_CONFIG is not set -+# CONFIG_SYS_BOOT_GET_CMDLINE is not set -+# CONFIG_SYS_BOOT_GET_KBD is not set -+CONFIG_SYS_MALLOC_F=y -+# CONFIG_VALGRIND is not set -+CONFIG_EXPERT=y -+CONFIG_SYS_MALLOC_CLEAR_ON_INIT=y -+# CONFIG_SYS_MALLOC_DEFAULT_TO_INIT is not set -+# CONFIG_TOOLS_DEBUG is not set -+CONFIG_PHYS_64BIT=y -+CONFIG_FDT_64BIT=y -+# CONFIG_REMAKE_ELF is not set -+# CONFIG_HAS_BOARD_SIZE_LIMIT is not set -+# CONFIG_SYS_CUSTOM_LDSCRIPT is not set -+CONFIG_PLATFORM_ELFENTRY="_start" -+CONFIG_STACK_SIZE=0x1000000 -+CONFIG_SYS_SRAM_BASE=0x0 -+CONFIG_SYS_SRAM_SIZE=0x0 -+# CONFIG_MP is not set -+CONFIG_HAVE_TEXT_BASE=y -+# CONFIG_HAVE_SYS_UBOOT_START is not set -+CONFIG_SYS_UBOOT_START=0x41e00000 -+# CONFIG_DYNAMIC_SYS_CLK_FREQ is not set -+# CONFIG_API is not set -+ -+# -+# Boot options -+# -+ -+# -+# Boot images -+# -+# CONFIG_ANDROID_BOOT_IMAGE is not set -+# CONFIG_TIMESTAMP is not set -+CONFIG_FIT=y -+CONFIG_FIT_EXTERNAL_OFFSET=0x0 -+CONFIG_FIT_FULL_CHECK=y -+# CONFIG_FIT_SIGNATURE is not set -+# CONFIG_FIT_CIPHER is not set -+# CONFIG_FIT_VERBOSE is not set -+# CONFIG_FIT_BEST_MATCH is not set -+CONFIG_FIT_PRINT=y -+# CONFIG_SPL_LOAD_FIT_FULL is not set -+CONFIG_PXE_UTILS=y -+CONFIG_BOOTSTD=y -+# CONFIG_BOOTSTD_FULL is not set -+# CONFIG_BOOTSTD_DEFAULTS is not set -+CONFIG_BOOTSTD_BOOTCOMMAND=y -+CONFIG_BOOTMETH_GLOBAL=y -+# CONFIG_BOOTMETH_CROS is not set -+CONFIG_BOOTMETH_EXTLINUX=y -+CONFIG_BOOTMETH_EXTLINUX_PXE=y -+CONFIG_BOOTMETH_EFILOADER=y -+CONFIG_BOOTMETH_VBE=y -+CONFIG_BOOTMETH_VBE_REQUEST=y -+CONFIG_BOOTMETH_VBE_SIMPLE=y -+CONFIG_BOOTMETH_VBE_SIMPLE_OS=y -+# CONFIG_BOOTMETH_SCRIPT is not set -+CONFIG_LEGACY_IMAGE_FORMAT=y -+# CONFIG_SUPPORT_RAW_INITRD is not set -+# CONFIG_CHROMEOS is not set -+# CONFIG_CHROMEOS_VBOOT is not set -+# CONFIG_RAMBOOT_PBL is not set -+CONFIG_SYS_BOOT_RAMDISK_HIGH=y -+# CONFIG_DISTRO_DEFAULTS is not set -+ -+# -+# Boot timing -+# -+# CONFIG_BOOTSTAGE is not set -+CONFIG_BOOTSTAGE_STASH_SIZE=0x1000 -+# CONFIG_SHOW_BOOT_PROGRESS is not set -+ -+# -+# Boot media -+# -+CONFIG_NAND_BOOT=y -+# CONFIG_ONENAND_BOOT is not set -+# CONFIG_QSPI_BOOT is not set -+# CONFIG_SATA_BOOT is not set -+# CONFIG_SD_BOOT is not set -+# CONFIG_SD_BOOT_QSPI is not set -+CONFIG_SPI_BOOT=y -+ -+# -+# Autoboot options -+# -+CONFIG_AUTOBOOT=y -+CONFIG_BOOTDELAY=2 -+# CONFIG_AUTOBOOT_KEYED is not set -+# CONFIG_AUTOBOOT_USE_MENUKEY is not set -+CONFIG_AUTOBOOT_MENU_SHOW=y -+# CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE is not set -+# CONFIG_BOOT_RETRY is not set -+ -+# -+# Image support -+# -+# CONFIG_IMAGE_PRE_LOAD is not set -+ -+# -+# Devicetree fixup -+# -+# CONFIG_OF_BOARD_SETUP is not set -+# CONFIG_OF_SYSTEM_SETUP is not set -+# CONFIG_OF_STDOUT_VIA_ALIAS is not set -+# CONFIG_FDT_FIXUP_PARTITIONS is not set -+# CONFIG_FDT_SIMPLEFB is not set -+CONFIG_ARCH_FIXUP_FDT_MEMORY=y -+# CONFIG_USE_BOOTARGS is not set -+# CONFIG_BOOTARGS_SUBST is not set -+# CONFIG_USE_BOOTCOMMAND is not set -+CONFIG_USE_PREBOOT=y -+CONFIG_DEFAULT_FDT_FILE="openwrt-one" -+# CONFIG_SAVE_PREV_BL_FDT_ADDR is not set -+# CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR is not set -+ -+# -+# Configuration editor -+# -+# CONFIG_CEDIT is not set -+ -+# -+# Console -+# -+CONFIG_MENU=y -+# CONFIG_CONSOLE_RECORD is not set -+# CONFIG_DISABLE_CONSOLE is not set -+CONFIG_LOGLEVEL=7 -+# CONFIG_SILENT_CONSOLE is not set -+# CONFIG_SPL_SILENT_CONSOLE is not set -+# CONFIG_TPL_SILENT_CONSOLE is not set -+# CONFIG_PRE_CONSOLE_BUFFER is not set -+CONFIG_CONSOLE_FLUSH_SUPPORT=y -+# CONFIG_CONSOLE_FLUSH_ON_NEWLINE is not set -+# CONFIG_CONSOLE_MUX is not set -+# CONFIG_SYS_CONSOLE_IS_IN_ENV is not set -+# CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE is not set -+# CONFIG_SYS_CONSOLE_INFO_QUIET is not set -+# CONFIG_SYS_STDIO_DEREGISTER is not set -+# CONFIG_SPL_SYS_STDIO_DEREGISTER is not set -+# CONFIG_SYS_DEVICE_NULLDEV is not set -+ -+# -+# Logging -+# -+CONFIG_LOG=y -+CONFIG_LOG_MAX_LEVEL=6 -+CONFIG_LOG_DEFAULT_LEVEL=6 -+CONFIG_LOG_CONSOLE=y -+# CONFIG_LOGF_FILE is not set -+# CONFIG_LOGF_LINE is not set -+# CONFIG_LOGF_FUNC is not set -+CONFIG_LOGF_FUNC_PAD=20 -+# CONFIG_LOG_SYSLOG is not set -+# CONFIG_LOG_ERROR_RETURN is not set -+ -+# -+# Init options -+# -+# CONFIG_BOARD_TYPES is not set -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DISPLAY_BOARDINFO=y -+# CONFIG_DISPLAY_BOARDINFO_LATE is not set -+ -+# -+# Start-up hooks -+# -+# CONFIG_CYCLIC is not set -+CONFIG_EVENT=y -+CONFIG_EVENT_DYNAMIC=y -+# CONFIG_EVENT_DEBUG is not set -+# CONFIG_ARCH_MISC_INIT is not set -+# CONFIG_BOARD_EARLY_INIT_F is not set -+# CONFIG_BOARD_EARLY_INIT_R is not set -+# CONFIG_BOARD_POSTCLK_INIT is not set -+CONFIG_BOARD_LATE_INIT=y -+# CONFIG_CLOCKS is not set -+# CONFIG_HWCONFIG is not set -+CONFIG_LAST_STAGE_INIT=y -+# CONFIG_MISC_INIT_R is not set -+# CONFIG_SYS_MALLOC_BOOTPARAMS is not set -+# CONFIG_ID_EEPROM is not set -+# CONFIG_RESET_PHY_R is not set -+ -+# -+# Security support -+# -+CONFIG_HASH=y -+# CONFIG_STACKPROTECTOR is not set -+# CONFIG_BOARD_RNG_SEED is not set -+ -+# -+# Update support -+# -+# CONFIG_UPDATE_TFTP is not set -+# CONFIG_ANDROID_AB is not set -+ -+# -+# Blob list -+# -+# CONFIG_BLOBLIST is not set -+CONFIG_SUPPORT_SPL=y -+# CONFIG_VPL is not set -+ -+# -+# Command line interface -+# -+CONFIG_CMDLINE=y -+CONFIG_HUSH_PARSER=y -+CONFIG_CMDLINE_EDITING=y -+# CONFIG_CMDLINE_PS_SUPPORT is not set -+CONFIG_AUTO_COMPLETE=y -+CONFIG_SYS_LONGHELP=y -+CONFIG_SYS_PROMPT="OpenWrt One> " -+CONFIG_SYS_PROMPT_HUSH_PS2="> " -+CONFIG_SYS_MAXARGS=16 -+CONFIG_SYS_CBSIZE=512 -+CONFIG_SYS_PBSIZE=1049 -+CONFIG_SYS_XTRACE=y -+CONFIG_BUILD_BIN2C=y -+ -+# -+# Commands -+# -+ -+# -+# Info commands -+# -+CONFIG_CMD_BDI=y -+# CONFIG_CMD_BDINFO_EXTRA is not set -+# CONFIG_CMD_CONFIG is not set -+CONFIG_CMD_CONSOLE=y -+CONFIG_CMD_CPU=y -+# CONFIG_CMD_HISTORY is not set -+CONFIG_CMD_LICENSE=y -+# CONFIG_CMD_PMC is not set -+ -+# -+# Boot commands -+# -+CONFIG_CMD_BOOTD=y -+CONFIG_CMD_BOOTM=y -+# CONFIG_CMD_BOOTDEV is not set -+CONFIG_CMD_BOOTFLOW=y -+# CONFIG_CMD_BOOTMETH is not set -+CONFIG_BOOTM_EFI=y -+# CONFIG_CMD_BOOTZ is not set -+CONFIG_CMD_BOOTI=y -+CONFIG_BOOTM_LINUX=y -+# CONFIG_BOOTM_NETBSD is not set -+# CONFIG_BOOTM_OPENRTOS is not set -+# CONFIG_BOOTM_OSE is not set -+# CONFIG_BOOTM_PLAN9 is not set -+# CONFIG_BOOTM_RTEMS is not set -+# CONFIG_CMD_VBE is not set -+# CONFIG_BOOTM_VXWORKS is not set -+CONFIG_SYS_BOOTM_LEN=0x4000000 -+CONFIG_CMD_BOOTEFI=y -+CONFIG_CMD_BOOTEFI_HELLO_COMPILE=y -+# CONFIG_CMD_BOOTEFI_HELLO is not set -+# CONFIG_CMD_BOOTEFI_SELFTEST is not set -+CONFIG_CMD_BOOTMENU=y -+# CONFIG_CMD_ADTIMG is not set -+CONFIG_CMD_ELF=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_GO=y -+CONFIG_CMD_RUN=y -+CONFIG_CMD_IMI=y -+# CONFIG_CMD_IMLS is not set -+CONFIG_CMD_XIMG=y -+# CONFIG_CMD_ZBOOT is not set -+ -+# -+# Environment commands -+# -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_EXPORTENV=y -+CONFIG_CMD_IMPORTENV=y -+CONFIG_CMD_EDITENV=y -+# CONFIG_CMD_GREPENV is not set -+CONFIG_CMD_SAVEENV=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_ENV_EXISTS=y -+CONFIG_CMD_ENV_READMEM=y -+# CONFIG_CMD_ENV_CALLBACK is not set -+CONFIG_CMD_ENV_FLAGS=y -+# CONFIG_CMD_NVEDIT_EFI is not set -+# CONFIG_CMD_NVEDIT_INDIRECT is not set -+# CONFIG_CMD_NVEDIT_INFO is not set -+# CONFIG_CMD_NVEDIT_LOAD is not set -+# CONFIG_CMD_NVEDIT_SELECT is not set -+ -+# -+# Memory commands -+# -+# CONFIG_CMD_BINOP is not set -+# CONFIG_CMD_BLOBLIST is not set -+CONFIG_CMD_CRC32=y -+# CONFIG_CRC32_VERIFY is not set -+# CONFIG_CMD_EEPROM is not set -+# CONFIG_LOOPW is not set -+# CONFIG_CMD_MD5SUM is not set -+# CONFIG_CMD_MEMINFO is not set -+CONFIG_CMD_MEMORY=y -+# CONFIG_CMD_MEM_SEARCH is not set -+# CONFIG_CMD_MX_CYCLIC is not set -+CONFIG_CMD_RANDOM=y -+# CONFIG_CMD_MEMTEST is not set -+# CONFIG_CMD_SHA1SUM is not set -+CONFIG_CMD_STRINGS=y -+ -+# -+# Compression commands -+# -+CONFIG_CMD_LZMADEC=y -+# CONFIG_CMD_UNLZ4 is not set -+# CONFIG_CMD_UNZIP is not set -+# CONFIG_CMD_ZIP is not set -+ -+# -+# Device access commands -+# -+# CONFIG_CMD_ARMFLASH is not set -+# CONFIG_CMD_BIND is not set -+# CONFIG_CMD_CLK is not set -+# CONFIG_CMD_DEMO is not set -+# CONFIG_CMD_DFU is not set -+CONFIG_CMD_DM=y -+CONFIG_CMD_FLASH=y -+# CONFIG_CMD_FPGAD is not set -+# CONFIG_CMD_FUSE is not set -+CONFIG_CMD_GPIO=y -+# CONFIG_CMD_GPIO_READ is not set -+CONFIG_CMD_PWM=y -+# CONFIG_CMD_GPT is not set -+# CONFIG_RANDOM_UUID is not set -+# CONFIG_CMD_IDE is not set -+# CONFIG_CMD_IO is not set -+# CONFIG_CMD_IOTRACE is not set -+# CONFIG_CMD_I2C is not set -+CONFIG_CMD_LOADB=y -+# CONFIG_CMD_LOADM is not set -+CONFIG_CMD_LOADS=y -+# CONFIG_LOADS_ECHO is not set -+# CONFIG_CMD_SAVES is not set -+# CONFIG_SYS_LOADS_BAUD_CHANGE is not set -+CONFIG_CMD_LOADXY_TIMEOUT=90 -+# CONFIG_CMD_LSBLK is not set -+# CONFIG_CMD_MBR is not set -+# CONFIG_CMD_CLONE is not set -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND_EXT=y -+# CONFIG_CMD_ONENAND is not set -+# CONFIG_CMD_OSD is not set -+# CONFIG_CMD_PART is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PINMUX=y -+# CONFIG_CMD_POWEROFF is not set -+# CONFIG_CMD_READ is not set -+# CONFIG_CMD_SATA is not set -+# CONFIG_CMD_SDRAM is not set -+CONFIG_CMD_SF=y -+CONFIG_CMD_SF_TEST=y -+# CONFIG_CMD_SPI is not set -+# CONFIG_CMD_TSI148 is not set -+# CONFIG_CMD_UNIVERSE is not set -+CONFIG_CMD_USB=y -+# CONFIG_CMD_USB_SDP is not set -+# CONFIG_CMD_RKMTD is not set -+# CONFIG_CMD_WRITE is not set -+ -+# -+# Shell scripting commands -+# -+# CONFIG_CMD_CAT is not set -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_SETEXPR=y -+# CONFIG_CMD_SETEXPR_FMT is not set -+# CONFIG_CMD_XXD is not set -+ -+# -+# Android support commands -+# -+CONFIG_CMD_NET=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_DHCP=y -+# CONFIG_BOOTP_MAY_FAIL is not set -+CONFIG_BOOTP_BOOTPATH=y -+# CONFIG_BOOTP_VENDOREX is not set -+# CONFIG_BOOTP_BOOTFILESIZE is not set -+CONFIG_BOOTP_DNS=y -+# CONFIG_BOOTP_DNS2 is not set -+CONFIG_BOOTP_GATEWAY=y -+CONFIG_BOOTP_HOSTNAME=y -+# CONFIG_BOOTP_PREFER_SERVERIP is not set -+CONFIG_BOOTP_SUBNETMASK=y -+# CONFIG_BOOTP_NISDOMAIN is not set -+# CONFIG_BOOTP_NTPSERVER is not set -+# CONFIG_BOOTP_TIMEOFFSET is not set -+# CONFIG_CMD_PCAP is not set -+CONFIG_BOOTP_PXE=y -+CONFIG_BOOTP_PXE_CLIENTARCH=0x16 -+# CONFIG_BOOTP_PXE_DHCP_OPTION is not set -+CONFIG_BOOTP_VCI_STRING="U-Boot.armv8" -+CONFIG_CMD_TFTPBOOT=y -+# CONFIG_CMD_TFTPPUT is not set -+CONFIG_CMD_TFTPSRV=y -+CONFIG_NET_TFTP_VARS=y -+CONFIG_CMD_RARP=y -+# CONFIG_CMD_NFS is not set -+# CONFIG_SYS_DISABLE_AUTOLOAD is not set -+# CONFIG_CMD_WGET is not set -+# CONFIG_CMD_MII is not set -+# CONFIG_CMD_MDIO is not set -+CONFIG_CMD_PING=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_ETHSW is not set -+CONFIG_CMD_PXE=y -+# CONFIG_CMD_WOL is not set -+ -+# -+# Misc commands -+# -+# CONFIG_CMD_2048 is not set -+# CONFIG_CMD_BSP is not set -+CONFIG_CMD_BLOCK_CACHE=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+# CONFIG_CMD_CONITRACE is not set -+# CONFIG_CMD_CLS is not set -+# CONFIG_CMD_EFIDEBUG is not set -+CONFIG_CMD_EFICONFIG=y -+# CONFIG_CMD_EXCEPTION is not set -+CONFIG_CMD_LED=y -+# CONFIG_CMD_INI is not set -+# CONFIG_CMD_DATE is not set -+# CONFIG_CMD_TIME is not set -+# CONFIG_CMD_GETTIME is not set -+# CONFIG_CMD_PAUSE is not set -+CONFIG_CMD_SLEEP=y -+# CONFIG_CMD_TIMER is not set -+# CONFIG_CMD_SYSBOOT is not set -+# CONFIG_CMD_QFW is not set -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_PSTORE_MEM_SIZE=0x10000 -+CONFIG_CMD_PSTORE_RECORD_SIZE=0x1000 -+CONFIG_CMD_PSTORE_CONSOLE_SIZE=0x1000 -+CONFIG_CMD_PSTORE_FTRACE_SIZE=0x1000 -+CONFIG_CMD_PSTORE_PMSG_SIZE=0x1000 -+CONFIG_CMD_PSTORE_ECC_SIZE=0 -+# CONFIG_CMD_TERMINAL is not set -+CONFIG_CMD_UUID=y -+ -+# -+# TI specific command line interface -+# -+ -+# -+# Power commands -+# -+ -+# -+# Security commands -+# -+# CONFIG_CMD_AES is not set -+# CONFIG_CMD_BLOB is not set -+CONFIG_CMD_HASH=y -+# CONFIG_CMD_HVC is not set -+CONFIG_CMD_SMC=y -+# CONFIG_HASH_VERIFY is not set -+ -+# -+# Firmware commands -+# -+ -+# -+# Filesystem commands -+# -+# CONFIG_CMD_BTRFS is not set -+# CONFIG_CMD_EROFS is not set -+# CONFIG_CMD_EXT2 is not set -+# CONFIG_CMD_EXT4 is not set -+CONFIG_CMD_FAT=y -+# CONFIG_CMD_SQUASHFS is not set -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+# CONFIG_CMD_JFFS2 is not set -+# CONFIG_CMD_MTDPARTS is not set -+CONFIG_MTDIDS_DEFAULT="" -+CONFIG_MTDPARTS_DEFAULT="" -+# CONFIG_CMD_REISER is not set -+# CONFIG_CMD_ZFS is not set -+ -+# -+# Debug commands -+# -+# CONFIG_CMD_DIAG is not set -+# CONFIG_CMD_EVENT is not set -+# CONFIG_CMD_LOG is not set -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+ -+# -+# Partition Types -+# -+CONFIG_PARTITIONS=y -+# CONFIG_MAC_PARTITION is not set -+CONFIG_DOS_PARTITION=y -+# CONFIG_ISO_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+CONFIG_PARTITION_UUIDS=y -+CONFIG_SUPPORT_OF_CONTROL=y -+ -+# -+# Device Tree Control -+# -+CONFIG_OF_CONTROL=y -+CONFIG_OF_REAL=y -+# CONFIG_OF_LIVE is not set -+CONFIG_OF_SEPARATE=y -+# CONFIG_OF_EMBED is not set -+# CONFIG_OF_BOARD is not set -+# CONFIG_OF_OMIT_DTB is not set -+CONFIG_DEVICE_TREE_INCLUDES="" -+CONFIG_OF_LIST="openwrt-one" -+# CONFIG_MULTI_DTB_FIT is not set -+CONFIG_OF_TAG_MIGRATE=y -+# CONFIG_OF_DTB_PROPS_REMOVE is not set -+ -+# -+# Environment -+# -+CONFIG_ENV_SUPPORT=y -+CONFIG_SAVEENV=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_MIN_ENTRIES=64 -+CONFIG_ENV_MAX_ENTRIES=512 -+CONFIG_ENV_IS_DEFAULT=y -+CONFIG_ENV_IS_NOWHERE=y -+# CONFIG_ENV_IS_IN_EEPROM is not set -+# CONFIG_ENV_IS_IN_FAT is not set -+# CONFIG_ENV_IS_IN_EXT4 is not set -+# CONFIG_ENV_IS_IN_FLASH is not set -+# CONFIG_ENV_IS_IN_MTD is not set -+# CONFIG_ENV_IS_IN_NAND is not set -+# CONFIG_ENV_IS_IN_NVRAM is not set -+# CONFIG_ENV_IS_IN_ONENAND is not set -+# CONFIG_ENV_IS_IN_REMOTE is not set -+# CONFIG_ENV_IS_IN_SPI_FLASH is not set -+# CONFIG_ENV_IS_IN_UBI is not set -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_DEFAULT_ENV_FILE="openwrt-one-nor_env" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+# CONFIG_ENV_IMPORT_FDT is not set -+# CONFIG_ENV_APPEND is not set -+# CONFIG_ENV_WRITEABLE_LIST is not set -+# CONFIG_ENV_ACCESS_IGNORE_FORCE is not set -+# CONFIG_USE_BOOTFILE is not set -+# CONFIG_USE_ETHPRIME is not set -+# CONFIG_USE_HOSTNAME is not set -+# CONFIG_VERSION_VARIABLE is not set -+CONFIG_NET=y -+CONFIG_ARP_TIMEOUT=5000 -+CONFIG_NET_RETRY_COUNT=5 -+CONFIG_PROT_UDP=y -+CONFIG_BOOTDEV_ETH=y -+# CONFIG_BOOTP_SEND_HOSTNAME is not set -+CONFIG_NET_RANDOM_ETHADDR=y -+# CONFIG_NETCONSOLE is not set -+# CONFIG_IP_DEFRAG is not set -+# CONFIG_SYS_FAULT_ECHO_LINK_DOWN is not set -+CONFIG_TFTP_BLOCKSIZE=1468 -+# CONFIG_TFTP_PORT is not set -+CONFIG_TFTP_WINDOWSIZE=1 -+# CONFIG_TFTP_TSIZE is not set -+# CONFIG_SERVERIP_FROM_PROXYDHCP is not set -+CONFIG_SERVERIP_FROM_PROXYDHCP_DELAY_MS=100 -+# CONFIG_KEEP_SERVERADDR is not set -+# CONFIG_UDP_CHECKSUM is not set -+# CONFIG_BOOTP_SERVERIP is not set -+CONFIG_BOOTP_MAX_ROOT_PATH_LEN=64 -+# CONFIG_USE_GATEWAYIP is not set -+# CONFIG_USE_IPADDR is not set -+# CONFIG_USE_NETMASK is not set -+# CONFIG_USE_ROOTPATH is not set -+# CONFIG_USE_SERVERIP is not set -+# CONFIG_PROT_TCP is not set -+# CONFIG_IPV6 is not set -+CONFIG_SYS_RX_ETH_BUFFER=4 -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_DM=y -+# CONFIG_DM_WARN is not set -+# CONFIG_DM_DEBUG is not set -+# CONFIG_DM_STATS is not set -+CONFIG_DM_DEVICE_REMOVE=y -+CONFIG_DM_EVENT=y -+CONFIG_DM_STDIO=y -+CONFIG_DM_SEQ_ALIAS=y -+# CONFIG_DM_DMA is not set -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+# CONFIG_DEVRES is not set -+CONFIG_SIMPLE_BUS=y -+# CONFIG_SIMPLE_BUS_CORRECT_RANGE is not set -+# CONFIG_SIMPLE_PM_BUS is not set -+CONFIG_OF_TRANSLATE=y -+# CONFIG_TRANSLATION_OFFSET is not set -+CONFIG_DM_DEV_READ_INLINE=y -+# CONFIG_OFNODE_MULTI_TREE is not set -+# CONFIG_BOUNCE_BUFFER is not set -+# CONFIG_ADC is not set -+# CONFIG_ADC_EXYNOS is not set -+# CONFIG_ADC_SANDBOX is not set -+# CONFIG_SARADC_MESON is not set -+# CONFIG_SARADC_ROCKCHIP is not set -+# CONFIG_SATA is not set -+# CONFIG_SCSI_AHCI is not set -+ -+# -+# SATA/SCSI device support -+# -+# CONFIG_AXI is not set -+ -+# -+# Bus devices -+# -+CONFIG_BLK=y -+CONFIG_BLOCK_CACHE=y -+# CONFIG_BLKMAP is not set -+# CONFIG_EFI_MEDIA is not set -+# CONFIG_IDE is not set -+# CONFIG_LBA48 is not set -+# CONFIG_SYS_64BIT_LBA is not set -+# CONFIG_RKMTD is not set -+# CONFIG_BOOTCOUNT_LIMIT is not set -+ -+# -+# Button Support -+# -+CONFIG_BUTTON=y -+# CONFIG_BUTTON_ADC is not set -+CONFIG_BUTTON_GPIO=y -+ -+# -+# Cache Controller drivers -+# -+# CONFIG_CACHE is not set -+# CONFIG_L2X0_CACHE is not set -+# CONFIG_V5L2_CACHE is not set -+# CONFIG_NCORE_CACHE is not set -+# CONFIG_SIFIVE_CCACHE is not set -+ -+# -+# Clock -+# -+CONFIG_CLK=y -+# CONFIG_CLK_CCF is not set -+# CONFIG_CLK_GPIO is not set -+# CONFIG_CLK_CDCE9XX is not set -+# CONFIG_CLK_ICS8N3QV01 is not set -+# CONFIG_CLK_K210 is not set -+# CONFIG_CLK_MPC83XX is not set -+# CONFIG_CLK_XLNX_CLKWZRD is not set -+# CONFIG_CLK_AT91 is not set -+# CONFIG_CLK_RCAR is not set -+# CONFIG_CLK_RCAR_CPG_LIB is not set -+# CONFIG_CLK_SIFIVE is not set -+# CONFIG_CLK_TI_AM3_DPLL is not set -+# CONFIG_CLK_TI_CTRL is not set -+# CONFIG_CLK_TI_GATE is not set -+# CONFIG_CLK_K3 is not set -+CONFIG_CPU=y -+# CONFIG_CPU_IMX is not set -+ -+# -+# Hardware crypto devices -+# -+# CONFIG_DM_HASH is not set -+# CONFIG_FSL_CAAM is not set -+CONFIG_CAAM_64BIT=y -+# CONFIG_SYS_FSL_SEC_BE is not set -+# CONFIG_SYS_FSL_SEC_LE is not set -+# CONFIG_NPCM_AES is not set -+# CONFIG_NPCM_SHA is not set -+# CONFIG_DDR_SPD is not set -+# CONFIG_IMX_SNPS_DDR_PHY is not set -+ -+# -+# Demo for driver model -+# -+# CONFIG_DM_DEMO is not set -+ -+# -+# DFU support -+# -+ -+# -+# DMA Support -+# -+# CONFIG_DMA is not set -+# CONFIG_DMA_LPC32XX is not set -+# CONFIG_TI_EDMA3 is not set -+# CONFIG_DMA_LEGACY is not set -+ -+# -+# Extcon Support -+# -+# CONFIG_EXTCON is not set -+ -+# -+# Fastboot support -+# -+# CONFIG_UDP_FUNCTION_FASTBOOT is not set -+# CONFIG_TCP_FUNCTION_FASTBOOT is not set -+CONFIG_FIRMWARE=y -+CONFIG_ARM_PSCI_FW=y -+# CONFIG_ZYNQMP_FIRMWARE is not set -+# CONFIG_ARM_SMCCC_FEATURES is not set -+# CONFIG_ARM_FFA_TRANSPORT is not set -+# CONFIG_SCMI_FIRMWARE is not set -+# CONFIG_DM_FUZZING_ENGINE is not set -+ -+# -+# FPGA support -+# -+# CONFIG_FPGA_ALTERA is not set -+# CONFIG_FPGA_SOCFPGA is not set -+# CONFIG_FPGA_LATTICE is not set -+# CONFIG_FPGA_XILINX is not set -+# CONFIG_DM_FPGA is not set -+# CONFIG_FWU_MDATA is not set -+CONFIG_GPIO=y -+CONFIG_GPIO_HOG=y -+# CONFIG_DM_GPIO_LOOKUP_LABEL is not set -+# CONFIG_ALTERA_PIO is not set -+# CONFIG_BCM2835_GPIO is not set -+# CONFIG_DWAPB_GPIO is not set -+# CONFIG_AT91_GPIO is not set -+# CONFIG_ATMEL_PIO4 is not set -+# CONFIG_ASPEED_GPIO is not set -+# CONFIG_DA8XX_GPIO is not set -+# CONFIG_HIKEY_GPIO is not set -+# CONFIG_INTEL_BROADWELL_GPIO is not set -+# CONFIG_INTEL_GPIO is not set -+# CONFIG_INTEL_ICH6_GPIO is not set -+# CONFIG_IMX_RGPIO2P is not set -+# CONFIG_IPROC_GPIO is not set -+# CONFIG_HSDK_CREG_GPIO is not set -+# CONFIG_KIRKWOOD_GPIO is not set -+# CONFIG_LPC32XX_GPIO is not set -+# CONFIG_MCP230XX_GPIO is not set -+# CONFIG_MSM_GPIO is not set -+# CONFIG_MXC_GPIO is not set -+# CONFIG_MXS_GPIO is not set -+# CONFIG_NPCM_GPIO is not set -+# CONFIG_CMD_PCA953X is not set -+# CONFIG_ROCKCHIP_GPIO is not set -+# CONFIG_XILINX_GPIO is not set -+# CONFIG_TCA642X is not set -+# CONFIG_TEGRA_GPIO is not set -+# CONFIG_TEGRA186_GPIO is not set -+# CONFIG_VYBRID_GPIO is not set -+# CONFIG_SIFIVE_GPIO is not set -+# CONFIG_ZYNQ_GPIO is not set -+# CONFIG_DM_74X164 is not set -+# CONFIG_PCA953X is not set -+# CONFIG_MPC8XXX_GPIO is not set -+# CONFIG_MPC8XX_GPIO is not set -+# CONFIG_NX_GPIO is not set -+# CONFIG_NOMADIK_GPIO is not set -+# CONFIG_ZYNQMP_GPIO_MODEPIN is not set -+# CONFIG_SLG7XL45106_I2C_GPO is not set -+# CONFIG_TURRIS_OMNIA_MCU is not set -+# CONFIG_FTGPIO010 is not set -+ -+# -+# Hardware Spinlock Support -+# -+# CONFIG_DM_HWSPINLOCK is not set -+CONFIG_I2C=y -+# CONFIG_DM_I2C is not set -+# CONFIG_SYS_I2C_LEGACY is not set -+# CONFIG_SPL_SYS_I2C_LEGACY is not set -+# CONFIG_SYS_I2C_FSL is not set -+# CONFIG_SYS_I2C_DW is not set -+# CONFIG_SYS_I2C_IMX_LPI2C is not set -+# CONFIG_SYS_I2C_MTK is not set -+# CONFIG_SYS_I2C_MICROCHIP is not set -+# CONFIG_SYS_I2C_MXC is not set -+# CONFIG_SYS_I2C_NPCM is not set -+# CONFIG_SYS_I2C_SOFT is not set -+# CONFIG_SYS_I2C_MV is not set -+# CONFIG_SYS_I2C_MVTWSI is not set -+CONFIG_INPUT=y -+# CONFIG_DM_KEYBOARD is not set -+# CONFIG_CROS_EC_KEYB is not set -+# CONFIG_TEGRA_KEYBOARD is not set -+# CONFIG_TWL4030_INPUT is not set -+ -+# -+# IOMMU device drivers -+# -+# CONFIG_IOMMU is not set -+ -+# -+# LED Support -+# -+CONFIG_LED=y -+# CONFIG_LED_PWM is not set -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+# CONFIG_LED_STATUS is not set -+ -+# -+# Mailbox Controller Support -+# -+# CONFIG_DM_MAILBOX is not set -+ -+# -+# Memory Controller drivers -+# -+# CONFIG_MEMORY is not set -+# CONFIG_ATMEL_EBI is not set -+# CONFIG_MFD_ATMEL_SMC is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MISC is not set -+# CONFIG_NVMEM is not set -+# CONFIG_SPL_NVMEM is not set -+# CONFIG_SMSC_LPC47M is not set -+# CONFIG_SMSC_SIO1007 is not set -+# CONFIG_CROS_EC is not set -+# CONFIG_DS4510 is not set -+# CONFIG_FSL_SEC_MON is not set -+# CONFIG_IRQ is not set -+# CONFIG_NPCM_HOST is not set -+# CONFIG_NUVOTON_NCT6102D is not set -+# CONFIG_PWRSEQ is not set -+# CONFIG_PCA9551_LED is not set -+# CONFIG_TEST_DRV is not set -+# CONFIG_USB_HUB_USB251XB is not set -+# CONFIG_TWL4030_LED is not set -+# CONFIG_WINBOND_W83627 is not set -+# CONFIG_FS_LOADER is not set -+ -+# -+# MMC Host controller Support -+# -+# CONFIG_MMC is not set -+# CONFIG_MMC_BROKEN_CD is not set -+# CONFIG_DM_MMC is not set -+# CONFIG_FSL_ESDHC is not set -+# CONFIG_FSL_ESDHC_IMX is not set -+ -+# -+# MTD Support -+# -+CONFIG_MTD_PARTITIONS=y -+CONFIG_MTD=y -+CONFIG_DM_MTD=y -+# CONFIG_MTD_NOR_FLASH is not set -+# CONFIG_MTD_CONCAT is not set -+# CONFIG_SYS_MTDPARTS_RUNTIME is not set -+# CONFIG_FLASH_CFI_DRIVER is not set -+# CONFIG_CFI_FLASH is not set -+# CONFIG_ALTERA_QSPI is not set -+# CONFIG_HBMC_AM654 is not set -+# CONFIG_SAMSUNG_ONENAND is not set -+# CONFIG_USE_SYS_MAX_FLASH_BANKS is not set -+CONFIG_MTD_NAND_CORE=y -+# CONFIG_MTD_RAW_NAND is not set -+CONFIG_MTD_SPI_NAND=y -+ -+# -+# SPI Flash Support -+# -+CONFIG_DM_SPI_FLASH=y -+CONFIG_SPI_FLASH=y -+CONFIG_SF_DEFAULT_BUS=0 -+CONFIG_SF_DEFAULT_CS=0 -+# CONFIG_BOOTDEV_SPI_FLASH is not set -+CONFIG_SPI_FLASH_SFDP_SUPPORT=y -+CONFIG_SPI_FLASH_SMART_HWCAPS=y -+# CONFIG_SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT is not set -+# CONFIG_SPI_FLASH_SOFT_RESET is not set -+# CONFIG_SPI_FLASH_BAR is not set -+CONFIG_SPI_FLASH_LOCK=y -+CONFIG_SPI_FLASH_UNLOCK_ALL=y -+# CONFIG_SPI_FLASH_ATMEL is not set -+CONFIG_SPI_FLASH_EON=y -+CONFIG_SPI_FLASH_GIGADEVICE=y -+CONFIG_SPI_FLASH_ISSI=y -+CONFIG_SPI_FLASH_MACRONIX=y -+CONFIG_SPI_FLASH_SPANSION=y -+# CONFIG_SPI_FLASH_S28HX_T is not set -+CONFIG_SPI_FLASH_STMICRO=y -+# CONFIG_SPI_FLASH_MT35XU is not set -+# CONFIG_SPI_FLASH_SST is not set -+CONFIG_SPI_FLASH_WINBOND=y -+CONFIG_SPI_FLASH_XMC=y -+CONFIG_SPI_FLASH_XTX=y -+# CONFIG_SPI_FLASH_ZBIT is not set -+CONFIG_SPI_FLASH_USE_4K_SECTORS=y -+# CONFIG_SPI_FLASH_DATAFLASH is not set -+CONFIG_SPI_FLASH_MTD=y -+ -+# -+# UBI support -+# -+CONFIG_UBI_SILENCE_MSG=y -+CONFIG_MTD_UBI=y -+CONFIG_MTD_UBI_MODULE=y -+CONFIG_MTD_UBI_WL_THRESHOLD=4096 -+CONFIG_MTD_UBI_BEB_LIMIT=20 -+# CONFIG_MTD_UBI_FASTMAP is not set -+# CONFIG_NVMXIP is not set -+# CONFIG_NVMXIP_QSPI is not set -+# CONFIG_NMBM is not set -+ -+# -+# Multiplexer drivers -+# -+# CONFIG_MULTIPLEXER is not set -+# CONFIG_BITBANGMII is not set -+# CONFIG_MV88E6352_SWITCH is not set -+CONFIG_PHYLIB=y -+# CONFIG_PHY_ADDR_ENABLE is not set -+# CONFIG_B53_SWITCH is not set -+# CONFIG_MV88E61XX_SWITCH is not set -+# CONFIG_PHYLIB_10G is not set -+# CONFIG_PHY_ADIN is not set -+# CONFIG_PHY_AIROHA is not set -+# CONFIG_PHY_AQUANTIA is not set -+# CONFIG_PHY_ATHEROS is not set -+# CONFIG_SPL_PHY_ATHEROS is not set -+# CONFIG_PHY_BROADCOM is not set -+# CONFIG_PHY_CORTINA is not set -+# CONFIG_PHY_DAVICOM is not set -+# CONFIG_PHY_ET1011C is not set -+# CONFIG_PHY_LXT is not set -+# CONFIG_PHY_MARVELL is not set -+# CONFIG_PHY_MARVELL_10G is not set -+# CONFIG_PHY_MESON_GXL is not set -+# CONFIG_PHY_MICREL is not set -+# CONFIG_PHY_MOTORCOMM is not set -+# CONFIG_PHY_MSCC is not set -+# CONFIG_PHY_NATSEMI is not set -+# CONFIG_PHY_NXP_C45_TJA11XX is not set -+# CONFIG_PHY_NXP_TJA11XX is not set -+# CONFIG_PHY_REALTEK is not set -+# CONFIG_PHY_SMSC is not set -+# CONFIG_PHY_TERANETICS is not set -+# CONFIG_PHY_TI is not set -+# CONFIG_PHY_TI_DP83867 is not set -+# CONFIG_PHY_TI_DP83869 is not set -+# CONFIG_PHY_TI_GENERIC is not set -+# CONFIG_PHY_VITESSE is not set -+# CONFIG_PHY_XILINX is not set -+# CONFIG_PHY_XILINX_GMII2RGMII is not set -+# CONFIG_PHY_XWAY is not set -+# CONFIG_PHY_ETHERNET_ID is not set -+CONFIG_PHY_FIXED=y -+# CONFIG_PHY_NCSI is not set -+# CONFIG_FSL_MEMAC is not set -+CONFIG_PHY_RESET_DELAY=0 -+# CONFIG_FSL_PFE is not set -+CONFIG_ETH=y -+CONFIG_DM_ETH=y -+# CONFIG_DM_MDIO is not set -+# CONFIG_DM_ETH_PHY is not set -+CONFIG_NETDEVICES=y -+# CONFIG_PHY_GIGE is not set -+# CONFIG_ALTERA_TSE is not set -+# CONFIG_BCM_SF2_ETH is not set -+# CONFIG_BCMGENET is not set -+# CONFIG_BNXT_ETH is not set -+# CONFIG_CALXEDA_XGMAC is not set -+# CONFIG_DRIVER_DM9000 is not set -+# CONFIG_DWC_ETH_QOS is not set -+# CONFIG_EEPRO100 is not set -+# CONFIG_ETH_DESIGNWARE is not set -+# CONFIG_ETH_DESIGNWARE_MESON8B is not set -+# CONFIG_ETHOC is not set -+# CONFIG_FMAN_ENET is not set -+# CONFIG_FTMAC100 is not set -+# CONFIG_FTGMAC100 is not set -+# CONFIG_MCFFEC is not set -+# CONFIG_FSLDMAFEC is not set -+# CONFIG_KS8851_MLL is not set -+# CONFIG_LITEETH is not set -+# CONFIG_MACB is not set -+# CONFIG_NET_NPCM750 is not set -+# CONFIG_PCH_GBE is not set -+# CONFIG_RGMII is not set -+# CONFIG_MII is not set -+# CONFIG_RMII is not set -+# CONFIG_PCNET is not set -+# CONFIG_QE_UEC is not set -+# CONFIG_RTL8139 is not set -+# CONFIG_SMC911X is not set -+# CONFIG_SUN7I_GMAC is not set -+# CONFIG_SUN4I_EMAC is not set -+# CONFIG_SUN8I_EMAC is not set -+# CONFIG_SH_ETHER is not set -+# CONFIG_DRIVER_TI_CPSW is not set -+# CONFIG_DRIVER_TI_EMAC is not set -+# CONFIG_DRIVER_TI_KEYSTONE_NET is not set -+# CONFIG_TULIP is not set -+# CONFIG_XILINX_AXIEMAC is not set -+# CONFIG_VSC7385_ENET is not set -+# CONFIG_XILINX_EMACLITE is not set -+# CONFIG_ZYNQ_GEM is not set -+# CONFIG_SYS_DPAA_QBMAN is not set -+# CONFIG_TSEC_ENET is not set -+CONFIG_MEDIATEK_ETH=y -+# CONFIG_HIFEMAC_ETH is not set -+# CONFIG_HIGMACV300_ETH is not set -+# CONFIG_NVME is not set -+# CONFIG_NVME_APPLE is not set -+ -+# -+# PCI Endpoint -+# -+# CONFIG_PCI_ENDPOINT is not set -+# CONFIG_X86_PCH7 is not set -+# CONFIG_X86_PCH9 is not set -+ -+# -+# PHY Subsystem -+# -+CONFIG_PHY=y -+# CONFIG_NOP_PHY is not set -+# CONFIG_MIPI_DPHY_HELPERS is not set -+# CONFIG_BCM_SR_PCIE_PHY is not set -+# CONFIG_OMAP_USB2_PHY is not set -+CONFIG_PHY_MTK_TPHY=y -+ -+# -+# Rockchip PHY driver -+# -+# CONFIG_PHY_CADENCE_SIERRA is not set -+# CONFIG_PHY_CADENCE_TORRENT is not set -+# CONFIG_MSM8916_USB_PHY is not set -+# CONFIG_MVEBU_COMPHY_SUPPORT is not set -+ -+# -+# Pin controllers -+# -+CONFIG_PINCTRL=y -+CONFIG_PINCTRL_FULL=y -+CONFIG_PINCTRL_GENERIC=y -+CONFIG_PINMUX=y -+CONFIG_PINCONF=y -+CONFIG_PINCONF_RECURSIVE=y -+# CONFIG_PINCTRL_AT91 is not set -+# CONFIG_PINCTRL_AT91PIO4 is not set -+# CONFIG_PINCTRL_INTEL is not set -+# CONFIG_PINCTRL_QE is not set -+# CONFIG_PINCTRL_ROCKCHIP_RV1108 is not set -+# CONFIG_PINCTRL_SINGLE is not set -+# CONFIG_PINCTRL_STM32 is not set -+# CONFIG_PINCTRL_STMFX is not set -+# CONFIG_PINCTRL_K210 is not set -+CONFIG_PINCTRL_MTK=y -+# CONFIG_PINCTRL_MT7622 is not set -+# CONFIG_PINCTRL_MT7623 is not set -+# CONFIG_PINCTRL_MT7629 is not set -+CONFIG_PINCTRL_MT7981=y -+# CONFIG_PINCTRL_MT7986 is not set -+# CONFIG_PINCTRL_MT7988 is not set -+# CONFIG_PINCTRL_MT8512 is not set -+# CONFIG_PINCTRL_MT8516 is not set -+# CONFIG_PINCTRL_MT8518 is not set -+CONFIG_POWER=y -+# CONFIG_POWER_LEGACY is not set -+# CONFIG_ACPI_PMC is not set -+ -+# -+# Power Domain Support -+# -+CONFIG_POWER_DOMAIN=y -+# CONFIG_APPLE_PMGR_POWER_DOMAIN is not set -+CONFIG_MTK_POWER_DOMAIN=y -+# CONFIG_DM_PMIC is not set -+# CONFIG_PMIC_TPS65217 is not set -+# CONFIG_POWER_TPS65218 is not set -+# CONFIG_POWER_TPS62362 is not set -+# CONFIG_DM_REGULATOR is not set -+# CONFIG_TPS6586X_POWER is not set -+# CONFIG_POWER_MT6323 is not set -+CONFIG_DM_PWM=y -+# CONFIG_PWM_ASPEED is not set -+# CONFIG_PWM_CADENCE_TTC is not set -+# CONFIG_PWM_CROS_EC is not set -+# CONFIG_PWM_EXYNOS is not set -+# CONFIG_PWM_IMX is not set -+# CONFIG_PWM_MESON is not set -+CONFIG_PWM_MTK=y -+# CONFIG_PWM_ROCKCHIP is not set -+# CONFIG_PWM_SANDBOX is not set -+# CONFIG_PWM_SIFIVE is not set -+# CONFIG_PWM_TEGRA is not set -+# CONFIG_PWM_SUNXI is not set -+# CONFIG_U_QE is not set -+# CONFIG_RAM is not set -+ -+# -+# Reboot Mode Support -+# -+# CONFIG_DM_REBOOT_MODE is not set -+ -+# -+# Remote Processor drivers -+# -+ -+# -+# Reset Controller Support -+# -+# CONFIG_RESET_AST2500 is not set -+# CONFIG_RESET_AST2600 is not set -+CONFIG_RESET_MEDIATEK=y -+# CONFIG_RESET_HISILICON is not set -+# CONFIG_RESET_SYSCON is not set -+# CONFIG_RESET_SCMI is not set -+# CONFIG_RESET_DRA7 is not set -+# CONFIG_DM_RNG is not set -+ -+# -+# Real Time Clock -+# -+# CONFIG_DM_RTC is not set -+# CONFIG_RTC_ENABLE_32KHZ_OUTPUT is not set -+# CONFIG_RTC_DS1337 is not set -+# CONFIG_RTC_DS1338 is not set -+# CONFIG_RTC_DS1374 is not set -+# CONFIG_RTC_DS3231 is not set -+# CONFIG_RTC_PCF8563 is not set -+# CONFIG_RTC_PT7C4338 is not set -+# CONFIG_RTC_PL031 is not set -+# CONFIG_RTC_S35392A is not set -+# CONFIG_RTC_MC13XXX is not set -+# CONFIG_RTC_MC146818 is not set -+# CONFIG_RTC_M41T62 is not set -+# CONFIG_SCSI is not set -+# CONFIG_DM_SCSI is not set -+CONFIG_SERIAL=y -+CONFIG_BAUDRATE=115200 -+# CONFIG_DEFAULT_ENV_IS_RW is not set -+CONFIG_REQUIRE_SERIAL_CONSOLE=y -+# CONFIG_SPECIFY_CONSOLE_INDEX is not set -+CONFIG_SERIAL_PRESENT=y -+CONFIG_DM_SERIAL=y -+# CONFIG_SERIAL_RX_BUFFER is not set -+# CONFIG_SERIAL_PUTS is not set -+# CONFIG_SERIAL_SEARCH_ALL is not set -+# CONFIG_SERIAL_PROBE_ALL is not set -+# CONFIG_VPL_DM_SERIAL is not set -+CONFIG_DEBUG_UART_MTK=y -+CONFIG_DEBUG_UART_SHIFT=0 -+# CONFIG_DEBUG_UART_ANNOUNCE is not set -+# CONFIG_DEBUG_UART_SKIP_INIT is not set -+# CONFIG_ALTERA_JTAG_UART is not set -+# CONFIG_ALTERA_UART is not set -+# CONFIG_ARC_SERIAL is not set -+# CONFIG_ARM_DCC is not set -+# CONFIG_ATMEL_USART is not set -+# CONFIG_BCM6345_SERIAL is not set -+# CONFIG_COREBOOT_SERIAL is not set -+# CONFIG_CORTINA_UART is not set -+# CONFIG_FSL_LINFLEXUART is not set -+# CONFIG_FSL_LPUART is not set -+# CONFIG_MVEBU_A3700_UART is not set -+# CONFIG_MCFUART is not set -+# CONFIG_NULLDEV_SERIAL is not set -+# CONFIG_SYS_NS16550 is not set -+# CONFIG_PL01X_SERIAL is not set -+# CONFIG_ROCKCHIP_SERIAL is not set -+# CONFIG_XILINX_UARTLITE is not set -+# CONFIG_MSM_SERIAL is not set -+# CONFIG_MSM_GENI_SERIAL is not set -+# CONFIG_MXS_AUART_SERIAL is not set -+# CONFIG_OMAP_SERIAL is not set -+# CONFIG_SIFIVE_SERIAL is not set -+# CONFIG_ZYNQ_SERIAL is not set -+CONFIG_MTK_SERIAL=y -+# CONFIG_MT7620_SERIAL is not set -+# CONFIG_NPCM_SERIAL is not set -+# CONFIG_SM is not set -+# CONFIG_MESON_SM is not set -+# CONFIG_SMEM is not set -+ -+# -+# Sound support -+# -+# CONFIG_SOUND is not set -+ -+# -+# SOC (System On Chip) specific Drivers -+# -+# CONFIG_SOC_DEVICE is not set -+# CONFIG_SOC_TI is not set -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_SPI_MEM=y -+# CONFIG_SPI_DIRMAP is not set -+# CONFIG_ALTERA_SPI is not set -+# CONFIG_APPLE_SPI is not set -+# CONFIG_ATCSPI200_SPI is not set -+# CONFIG_ATMEL_SPI is not set -+# CONFIG_BCMSTB_SPI is not set -+# CONFIG_CORTINA_SFLASH is not set -+# CONFIG_CADENCE_QSPI is not set -+# CONFIG_CF_SPI is not set -+# CONFIG_DESIGNWARE_SPI is not set -+# CONFIG_EXYNOS_SPI is not set -+# CONFIG_FSL_DSPI is not set -+# CONFIG_FSL_QSPI is not set -+# CONFIG_GXP_SPI is not set -+# CONFIG_ICH_SPI is not set -+# CONFIG_IPROC_QSPI is not set -+# CONFIG_KIRKWOOD_SPI is not set -+# CONFIG_MICROCHIP_COREQSPI is not set -+# CONFIG_MPC8XXX_SPI is not set -+# CONFIG_MTK_SNOR is not set -+# CONFIG_MTK_SNFI_SPI is not set -+CONFIG_MTK_SPIM=y -+# CONFIG_MVEBU_A3700_SPI is not set -+# CONFIG_MXS_SPI is not set -+# CONFIG_SPI_MXIC is not set -+# CONFIG_NPCM_FIU_SPI is not set -+# CONFIG_NPCM_PSPI is not set -+# CONFIG_NXP_FSPI is not set -+# CONFIG_OMAP3_SPI is not set -+# CONFIG_PL022_SPI is not set -+# CONFIG_ROCKCHIP_SFC is not set -+# CONFIG_ROCKCHIP_SPI is not set -+# CONFIG_SPI_ASPEED_SMC is not set -+# CONFIG_SPI_SIFIVE is not set -+# CONFIG_SOFT_SPI is not set -+# CONFIG_SPI_SN_F_OSPI is not set -+# CONFIG_SPI_SUNXI is not set -+# CONFIG_TEGRA114_SPI is not set -+# CONFIG_TEGRA20_SFLASH is not set -+# CONFIG_TEGRA20_SLINK is not set -+# CONFIG_TEGRA210_QSPI is not set -+# CONFIG_TI_QSPI is not set -+# CONFIG_XILINX_SPI is not set -+# CONFIG_ZYNQ_SPI is not set -+# CONFIG_ZYNQ_QSPI is not set -+# CONFIG_ZYNQMP_GQSPI is not set -+# CONFIG_SH_QSPI is not set -+# CONFIG_MXC_SPI is not set -+ -+# -+# SPMI support -+# -+# CONFIG_SPMI is not set -+# CONFIG_SYSINFO is not set -+ -+# -+# System reset device drivers -+# -+# CONFIG_SYSRESET is not set -+# CONFIG_TEE is not set -+# CONFIG_DM_THERMAL is not set -+ -+# -+# Timer Support -+# -+# CONFIG_TIMER is not set -+ -+# -+# TPM support -+# -+CONFIG_USB=y -+CONFIG_DM_USB=y -+# CONFIG_DM_USB_GADGET is not set -+ -+# -+# USB Host Controller Drivers -+# -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+# CONFIG_USB_XHCI_DWC3 is not set -+# CONFIG_USB_XHCI_DWC3_OF_SIMPLE is not set -+CONFIG_USB_XHCI_MTK=y -+# CONFIG_USB_XHCI_FSL is not set -+# CONFIG_USB_XHCI_BRCM is not set -+# CONFIG_USB_EHCI_HCD is not set -+# CONFIG_USB_OHCI_HCD is not set -+# CONFIG_USB_UHCI_HCD is not set -+# CONFIG_USB_DWC2 is not set -+# CONFIG_USB_R8A66597_HCD is not set -+# CONFIG_USB_ISP1760 is not set -+# CONFIG_USB_CDNS3 is not set -+# CONFIG_USB_DWC3 is not set -+# CONFIG_USB_MTU3 is not set -+ -+# -+# Legacy MUSB Support -+# -+# CONFIG_USB_MUSB_HCD is not set -+# CONFIG_USB_MUSB_UDC is not set -+ -+# -+# MUSB Controller Driver -+# -+# CONFIG_USB_MUSB_HOST is not set -+# CONFIG_USB_MUSB_PIO_ONLY is not set -+ -+# -+# USB Phy -+# -+# CONFIG_TWL4030_USB is not set -+# CONFIG_ROCKCHIP_USB2_PHY is not set -+ -+# -+# ULPI drivers -+# -+ -+# -+# USB peripherals -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_KEYBOARD is not set -+# CONFIG_USB_ONBOARD_HUB is not set -+CONFIG_USB_HUB_DEBOUNCE_TIMEOUT=1000 -+# CONFIG_USB_HOST_ETHER is not set -+# CONFIG_USB_GADGET is not set -+# CONFIG_SPL_USB_GADGET is not set -+ -+# -+# UFS Host Controller Support -+# -+# CONFIG_TI_J721E_UFS is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VIDEO is not set -+ -+# -+# VirtIO Drivers -+# -+# CONFIG_VIRTIO_MMIO is not set -+ -+# -+# 1-Wire support -+# -+# CONFIG_W1 is not set -+ -+# -+# 1-wire EEPROM support -+# -+# CONFIG_W1_EEPROM is not set -+ -+# -+# Watchdog Timer Support -+# -+# CONFIG_WATCHDOG is not set -+CONFIG_WATCHDOG_TIMEOUT_MSECS=60000 -+# CONFIG_IMX_WATCHDOG is not set -+# CONFIG_ULP_WATCHDOG is not set -+# CONFIG_WDT is not set -+# CONFIG_PHYS_TO_BUS is not set -+ -+# -+# File systems -+# -+# CONFIG_FS_BTRFS is not set -+# CONFIG_FS_CBFS is not set -+# CONFIG_FS_EXT4 is not set -+CONFIG_FS_FAT=y -+CONFIG_FAT_WRITE=y -+CONFIG_FS_FAT_MAX_CLUSTSIZE=65536 -+# CONFIG_FS_JFFS2 is not set -+CONFIG_UBIFS_SILENCE_MSG=y -+CONFIG_UBIFS_SILENCE_DEBUG_DUMP=y -+# CONFIG_FS_CRAMFS is not set -+# CONFIG_YAFFS2 is not set -+# CONFIG_FS_SQUASHFS is not set -+# CONFIG_FS_EROFS is not set -+ -+# -+# Library routines -+# -+# CONFIG_ADDR_MAP is not set -+# CONFIG_SYS_TIMER_COUNTS_DOWN is not set -+# CONFIG_PHYSMEM is not set -+# CONFIG_BCH is not set -+# CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED is not set -+CONFIG_CHARSET=y -+# CONFIG_DYNAMIC_CRC_TABLE is not set -+CONFIG_LIB_UUID=y -+# CONFIG_SEMIHOSTING is not set -+CONFIG_PRINTF=y -+CONFIG_SPRINTF=y -+CONFIG_STRTO=y -+CONFIG_SYS_HZ=1000 -+# CONFIG_PANIC_HANG is not set -+CONFIG_REGEX=y -+CONFIG_LIB_RAND=y -+# CONFIG_LIB_HW_RAND is not set -+CONFIG_SUPPORT_ACPI=y -+# CONFIG_ACPI is not set -+CONFIG_RBTREE=y -+# CONFIG_BITREVERSE is not set -+# CONFIG_TRACE is not set -+# CONFIG_CIRCBUF is not set -+# CONFIG_CMD_DHRYSTONE is not set -+ -+# -+# Security support -+# -+# CONFIG_AES is not set -+# CONFIG_ECDSA is not set -+# CONFIG_RSA is not set -+# CONFIG_TPM is not set -+ -+# -+# Android Verified Boot -+# -+ -+# -+# Hashing Support -+# -+# CONFIG_BLAKE2 is not set -+CONFIG_SHA1=y -+CONFIG_SHA256=y -+# CONFIG_SHA512 is not set -+# CONFIG_SHA384 is not set -+# CONFIG_SHA_HW_ACCEL is not set -+CONFIG_MD5=y -+CONFIG_CRC8=y -+CONFIG_CRC32=y -+ -+# -+# Compression Support -+# -+# CONFIG_LZ4 is not set -+CONFIG_LZMA=y -+CONFIG_LZO=y -+CONFIG_GZIP=y -+# CONFIG_ZLIB_UNCOMPRESS is not set -+# CONFIG_BZIP2 is not set -+CONFIG_ZLIB=y -+# CONFIG_ZSTD is not set -+CONFIG_VPL_LZMA=y -+# CONFIG_SPL_GZIP is not set -+# CONFIG_ERRNO_STR is not set -+CONFIG_HEXDUMP=y -+# CONFIG_GETOPT is not set -+CONFIG_OF_LIBFDT=y -+CONFIG_OF_LIBFDT_ASSUME_MASK=0x0 -+CONFIG_SYS_FDT_PAD=0x3000 -+ -+# -+# System tables -+# -+CONFIG_GENERATE_SMBIOS_TABLE=y -+# CONFIG_LIB_RATIONAL is not set -+CONFIG_SMBIOS=y -+# CONFIG_SMBIOS_PARSER is not set -+CONFIG_EFI_LOADER=y -+CONFIG_CMD_BOOTEFI_BOOTMGR=y -+CONFIG_EFI_VARIABLE_FILE_STORE=y -+# CONFIG_EFI_VARIABLE_NO_STORE is not set -+# CONFIG_EFI_VARIABLES_PRESEED is not set -+CONFIG_EFI_VAR_BUF_SIZE=131072 -+# CONFIG_EFI_SCROLL_ON_CLEAR_SCREEN is not set -+# CONFIG_EFI_RUNTIME_UPDATE_CAPSULE is not set -+CONFIG_EFI_CAPSULE_MAX=15 -+CONFIG_EFI_DEVICE_PATH_TO_TEXT=y -+CONFIG_EFI_DEVICE_PATH_UTIL=y -+CONFIG_EFI_DT_FIXUP=y -+CONFIG_EFI_LOADER_HII=y -+CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2=y -+CONFIG_EFI_UNICODE_CAPITALIZATION=y -+# CONFIG_EFI_LOADER_BOUNCE_BUFFER is not set -+CONFIG_EFI_PLATFORM_LANG_CODES="en-US" -+CONFIG_EFI_HAVE_RUNTIME_RESET=y -+CONFIG_EFI_LOAD_FILE2_INITRD=y -+CONFIG_EFI_ECPT=y -+CONFIG_EFI_EBBR_2_1_CONFORMANCE=y -+# CONFIG_OPTEE_LIB is not set -+# CONFIG_OPTEE_IMAGE is not set -+# CONFIG_BOOTM_OPTEE is not set -+# CONFIG_TEST_FDTDEC is not set -+CONFIG_LIB_ELF=y -+CONFIG_LMB=y -+CONFIG_LMB_USE_MAX_REGIONS=y -+CONFIG_LMB_MAX_REGIONS=64 -+# CONFIG_PHANDLE_CHECK_SEQ is not set -+ -+# -+# Testing -+# -+# CONFIG_UNIT_TEST is not set -+# CONFIG_POST is not set -+ -+# -+# Tools options -+# -+CONFIG_MKIMAGE_DTC_PATH="dtc" -+CONFIG_TOOLS_CRC32=y -+# CONFIG_TOOLS_LIBCRYPTO is not set -+CONFIG_TOOLS_FIT=y -+CONFIG_TOOLS_FIT_FULL_CHECK=y -+CONFIG_TOOLS_FIT_PRINT=y -+CONFIG_TOOLS_FIT_RSASSA_PSS=y -+CONFIG_TOOLS_FIT_SIGNATURE=y -+CONFIG_TOOLS_FIT_SIGNATURE_MAX_SIZE=0x10000000 -+CONFIG_TOOLS_FIT_VERBOSE=y -+CONFIG_TOOLS_MD5=y -+CONFIG_TOOLS_OF_LIBFDT=y -+CONFIG_TOOLS_SHA1=y -+CONFIG_TOOLS_SHA256=y -+CONFIG_TOOLS_SHA384=y -+CONFIG_TOOLS_SHA512=y -+# CONFIG_TOOLS_MKEFICAPSULE is not set -+# CONFIG_FSPI_CONF_HEADER is not set -+# CONFIG_TOOLS_MKFWUMDATA is not set ---- /dev/null -+++ b/configs/mt7981_openwrt-one-spi-nand_defconfig -@@ -0,0 +1,1815 @@ -+# -+# Automatically generated file; DO NOT EDIT. -+# U-Boot 2024.01 Configuration -+# -+ -+# -+# Compiler: aarch64-openwrt-linux-musl-gcc (OpenWrt GCC 12.3.0 r25206+8-d5e2177a6b) 12.3.0 -+# -+CONFIG_CREATE_ARCH_SYMLINK=y -+CONFIG_SYS_CACHE_SHIFT_6=y -+CONFIG_SYS_CACHELINE_SIZE=64 -+CONFIG_LINKER_LIST_ALIGN=8 -+# CONFIG_ARC is not set -+CONFIG_ARM=y -+# CONFIG_M68K is not set -+# CONFIG_MICROBLAZE is not set -+# CONFIG_MIPS is not set -+# CONFIG_NIOS2 is not set -+# CONFIG_PPC is not set -+# CONFIG_RISCV is not set -+# CONFIG_SANDBOX is not set -+# CONFIG_SH is not set -+# CONFIG_X86 is not set -+# CONFIG_XTENSA is not set -+CONFIG_SYS_ARCH="arm" -+CONFIG_SYS_CPU="armv8" -+CONFIG_SYS_SOC="mediatek" -+CONFIG_SYS_VENDOR="mediatek" -+CONFIG_SYS_BOARD="mt7981" -+CONFIG_SYS_CONFIG_NAME="mt7981" -+ -+# -+# Skipping low level initialization functions -+# -+# CONFIG_SKIP_LOWLEVEL_INIT is not set -+# CONFIG_SKIP_LOWLEVEL_INIT_ONLY is not set -+CONFIG_SYS_HAS_NONCACHED_MEMORY=y -+CONFIG_SYS_NONCACHED_MEMORY=0x100000 -+# CONFIG_SYS_ICACHE_OFF is not set -+# CONFIG_SYS_DCACHE_OFF is not set -+ -+# -+# ARM architecture -+# -+CONFIG_ARM64=y -+CONFIG_ARM64_CRC32=y -+CONFIG_COUNTER_FREQUENCY=0 -+CONFIG_POSITION_INDEPENDENT=y -+CONFIG_INIT_SP_RELATIVE=y -+CONFIG_SYS_INIT_SP_BSS_OFFSET=524288 -+# CONFIG_GIC_V3_ITS is not set -+CONFIG_STATIC_RELA=y -+CONFIG_DMA_ADDR_T_64BIT=y -+CONFIG_GPIO_EXTRA_HEADER=y -+CONFIG_ARM_ASM_UNIFIED=y -+# CONFIG_SYS_ARM_CACHE_CP15 is not set -+# CONFIG_SYS_ARM_MMU is not set -+# CONFIG_SYS_ARM_MPU is not set -+CONFIG_SYS_ARM_ARCH=8 -+CONFIG_SYS_ARM_CACHE_WRITEBACK=y -+# CONFIG_SYS_ARM_CACHE_WRITETHROUGH is not set -+# CONFIG_SYS_ARM_CACHE_WRITEALLOC is not set -+# CONFIG_ARCH_CPU_INIT is not set -+CONFIG_SYS_ARCH_TIMER=y -+CONFIG_ARM_SMCCC=y -+# CONFIG_SYS_L2_PL310 is not set -+# CONFIG_SPL_SYS_L2_PL310 is not set -+# CONFIG_SYS_L2CACHE_OFF is not set -+# CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK is not set -+# CONFIG_USE_ARCH_MEMCPY is not set -+# CONFIG_USE_ARCH_MEMSET is not set -+CONFIG_ARM64_SUPPORT_AARCH32=y -+# CONFIG_ARCH_AT91 is not set -+# CONFIG_ARCH_DAVINCI is not set -+# CONFIG_ARCH_HISTB is not set -+# CONFIG_ARCH_KIRKWOOD is not set -+# CONFIG_ARCH_MVEBU is not set -+# CONFIG_ARCH_ORION5X is not set -+# CONFIG_TARGET_STV0991 is not set -+# CONFIG_ARCH_BCM283X is not set -+# CONFIG_ARCH_BCMSTB is not set -+# CONFIG_ARCH_BCMBCA is not set -+# CONFIG_TARGET_VEXPRESS_CA9X4 is not set -+# CONFIG_TARGET_BCMNS is not set -+# CONFIG_TARGET_BCMNS2 is not set -+# CONFIG_TARGET_BCMNS3 is not set -+# CONFIG_ARCH_EXYNOS is not set -+# CONFIG_ARCH_S5PC1XX is not set -+# CONFIG_ARCH_HIGHBANK is not set -+# CONFIG_ARCH_INTEGRATOR is not set -+# CONFIG_ARCH_IPQ40XX is not set -+# CONFIG_ARCH_KEYSTONE is not set -+# CONFIG_ARCH_K3 is not set -+# CONFIG_ARCH_OMAP2PLUS is not set -+# CONFIG_ARCH_MESON is not set -+CONFIG_ARCH_MEDIATEK=y -+# CONFIG_ARCH_LPC32XX is not set -+# CONFIG_ARCH_IMX8 is not set -+# CONFIG_ARCH_IMX8M is not set -+# CONFIG_ARCH_IMX8ULP is not set -+# CONFIG_ARCH_IMX9 is not set -+# CONFIG_ARCH_IMXRT is not set -+# CONFIG_ARCH_MX23 is not set -+# CONFIG_ARCH_MX28 is not set -+# CONFIG_ARCH_MX31 is not set -+# CONFIG_ARCH_MX7ULP is not set -+# CONFIG_ARCH_MX7 is not set -+# CONFIG_ARCH_MX6 is not set -+# CONFIG_ARCH_MX5 is not set -+# CONFIG_ARCH_NEXELL is not set -+# CONFIG_ARCH_NPCM is not set -+# CONFIG_ARCH_APPLE is not set -+# CONFIG_ARCH_OWL is not set -+# CONFIG_ARCH_QEMU is not set -+# CONFIG_ARCH_RMOBILE is not set -+# CONFIG_ARCH_SNAPDRAGON is not set -+# CONFIG_ARCH_SOCFPGA is not set -+# CONFIG_ARCH_SUNXI is not set -+# CONFIG_ARCH_U8500 is not set -+# CONFIG_ARCH_VERSAL is not set -+# CONFIG_ARCH_VERSAL_NET is not set -+# CONFIG_ARCH_VF610 is not set -+# CONFIG_ARCH_ZYNQ is not set -+# CONFIG_ARCH_ZYNQMP_R5 is not set -+# CONFIG_ARCH_ZYNQMP is not set -+# CONFIG_ARCH_TEGRA is not set -+# CONFIG_ARCH_VEXPRESS64 is not set -+# CONFIG_TARGET_CORSTONE1000 is not set -+# CONFIG_TARGET_TOTAL_COMPUTE is not set -+# CONFIG_TARGET_LS2080A_EMU is not set -+# CONFIG_TARGET_LS1088AQDS is not set -+# CONFIG_TARGET_LS2080AQDS is not set -+# CONFIG_TARGET_LS2080ARDB is not set -+# CONFIG_TARGET_LS2081ARDB is not set -+# CONFIG_TARGET_LX2160ARDB is not set -+# CONFIG_TARGET_LX2160AQDS is not set -+# CONFIG_TARGET_LX2162AQDS is not set -+# CONFIG_TARGET_HIKEY is not set -+# CONFIG_TARGET_HIKEY960 is not set -+# CONFIG_TARGET_POPLAR is not set -+# CONFIG_TARGET_LS1012AQDS is not set -+# CONFIG_TARGET_LS1012ARDB is not set -+# CONFIG_TARGET_LS1012A2G5RDB is not set -+# CONFIG_TARGET_LS1012AFRWY is not set -+# CONFIG_TARGET_LS1012AFRDM is not set -+# CONFIG_TARGET_LS1028AQDS is not set -+# CONFIG_TARGET_LS1028ARDB is not set -+# CONFIG_TARGET_LS1088ARDB is not set -+# CONFIG_TARGET_LS1021AQDS is not set -+# CONFIG_TARGET_LS1021ATWR is not set -+# CONFIG_TARGET_PG_WCOM_SELI8 is not set -+# CONFIG_TARGET_PG_WCOM_EXPU1 is not set -+# CONFIG_TARGET_LS1021ATSN is not set -+# CONFIG_TARGET_LS1021AIOT is not set -+# CONFIG_TARGET_LS1043AQDS is not set -+# CONFIG_TARGET_LS1043ARDB is not set -+# CONFIG_TARGET_LS1046AQDS is not set -+# CONFIG_TARGET_LS1046ARDB is not set -+# CONFIG_TARGET_LS1046AFRWY is not set -+# CONFIG_TARGET_SL28 is not set -+# CONFIG_TARGET_TEN64 is not set -+# CONFIG_ARCH_UNIPHIER is not set -+# CONFIG_ARCH_SYNQUACER is not set -+# CONFIG_ARCH_STM32 is not set -+# CONFIG_ARCH_STI is not set -+# CONFIG_ARCH_STM32MP is not set -+# CONFIG_ARCH_ROCKCHIP is not set -+# CONFIG_ARCH_OCTEONTX is not set -+# CONFIG_ARCH_OCTEONTX2 is not set -+# CONFIG_TARGET_THUNDERX_88XX is not set -+# CONFIG_ARCH_ASPEED is not set -+# CONFIG_TARGET_DURIAN is not set -+# CONFIG_TARGET_POMELO is not set -+# CONFIG_TARGET_PRESIDIO_ASIC is not set -+# CONFIG_TARGET_XENGUEST_ARM64 is not set -+# CONFIG_ARCH_GXP is not set -+# CONFIG_STATIC_MACH_TYPE is not set -+CONFIG_TEXT_BASE=0x41e00000 -+CONFIG_SYS_MALLOC_LEN=0x400000 -+CONFIG_SYS_MALLOC_F_LEN=0x4000 -+CONFIG_NR_DRAM_BANKS=1 -+CONFIG_ENV_SOURCE_FILE="" -+CONFIG_SF_DEFAULT_SPEED=1000000 -+CONFIG_SF_DEFAULT_MODE=0x0 -+CONFIG_ENV_SIZE=0x1f000 -+CONFIG_DM_GPIO=y -+CONFIG_DEFAULT_DEVICE_TREE="openwrt-one" -+CONFIG_OF_LIBFDT_OVERLAY=y -+CONFIG_MULTI_DTB_FIT_UNCOMPRESS_SZ=0x8000 -+CONFIG_DM_RESET=y -+CONFIG_SYS_MONITOR_LEN=0 -+# CONFIG_MT8512 is not set -+# CONFIG_TARGET_MT7622 is not set -+# CONFIG_TARGET_MT7623 is not set -+# CONFIG_TARGET_MT7629 is not set -+CONFIG_TARGET_MT7981=y -+# CONFIG_TARGET_MT7986 is not set -+# CONFIG_TARGET_MT7988 is not set -+# CONFIG_TARGET_MT8183 is not set -+# CONFIG_TARGET_MT8512 is not set -+# CONFIG_TARGET_MT8516 is not set -+# CONFIG_TARGET_MT8518 is not set -+CONFIG_MTK_BROM_HEADER_INFO="media=snand;nandinfo=2k+64" -+CONFIG_RESET_BUTTON_LABEL="back" -+CONFIG_RESET_BUTTON_SETTLE_DELAY=0 -+CONFIG_ERR_PTR_OFFSET=0x0 -+# CONFIG_SPL is not set -+CONFIG_BOOTSTAGE_STASH_ADDR=0x0 -+CONFIG_DEBUG_UART_BASE=0x11002000 -+CONFIG_DEBUG_UART_CLOCK=40000000 -+# CONFIG_DEBUG_UART_BOARD_INIT is not set -+CONFIG_IDENT_STRING="" -+CONFIG_SYS_CLK_FREQ=0 -+# CONFIG_CHIP_DIP_SCAN is not set -+# CONFIG_CMO_BY_VA_ONLY is not set -+# CONFIG_ARMV8_MULTIENTRY is not set -+# CONFIG_ARMV8_SET_SMPEN is not set -+# CONFIG_ARMV8_SWITCH_TO_EL1 is not set -+ -+# -+# ARMv8 secure monitor firmware -+# -+# CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT is not set -+CONFIG_PSCI_RESET=y -+# CONFIG_ARMV8_PSCI is not set -+# CONFIG_ARMV8_EA_EL3_FIRST is not set -+# CONFIG_ARMV8_CRYPTO is not set -+# CONFIG_CMD_DEKBLOB is not set -+# CONFIG_IMX_CAAM_DEK_ENCAP is not set -+# CONFIG_IMX_OPTEE_DEK_ENCAP is not set -+# CONFIG_IMX_SECO_DEK_ENCAP is not set -+# CONFIG_IMX_ELE_DEK_ENCAP is not set -+# CONFIG_CMD_HDMIDETECT is not set -+CONFIG_IMX_DCD_ADDR=0x00910000 -+CONFIG_SYS_MEM_TOP_HIDE=0x0 -+CONFIG_SYS_LOAD_ADDR=0x46000000 -+ -+# -+# ARM debug -+# -+CONFIG_BUILD_TARGET="" -+# CONFIG_PCI is not set -+CONFIG_FWU_NUM_BANKS=2 -+CONFIG_FWU_NUM_IMAGES_PER_BANK=2 -+CONFIG_DEBUG_UART=y -+# CONFIG_AHCI is not set -+# CONFIG_OF_BOARD_FIXUP is not set -+ -+# -+# Functionality shared between NXP SoCs -+# -+# CONFIG_NXP_ESBC is not set -+ -+# -+# General setup -+# -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_CC_IS_GCC=y -+CONFIG_GCC_VERSION=120300 -+CONFIG_CLANG_VERSION=0 -+CONFIG_CC_OPTIMIZE_FOR_SIZE=y -+# CONFIG_CC_OPTIMIZE_FOR_SPEED is not set -+# CONFIG_CC_OPTIMIZE_FOR_DEBUG is not set -+# CONFIG_OPTIMIZE_INLINING is not set -+CONFIG_ARCH_SUPPORTS_LTO=y -+# CONFIG_LTO is not set -+CONFIG_CC_HAS_ASM_INLINE=y -+# CONFIG_XEN is not set -+# CONFIG_ENV_VARS_UBOOT_CONFIG is not set -+# CONFIG_SYS_BOOT_GET_CMDLINE is not set -+# CONFIG_SYS_BOOT_GET_KBD is not set -+CONFIG_SYS_MALLOC_F=y -+# CONFIG_VALGRIND is not set -+CONFIG_EXPERT=y -+CONFIG_SYS_MALLOC_CLEAR_ON_INIT=y -+# CONFIG_SYS_MALLOC_DEFAULT_TO_INIT is not set -+# CONFIG_TOOLS_DEBUG is not set -+CONFIG_PHYS_64BIT=y -+CONFIG_FDT_64BIT=y -+# CONFIG_REMAKE_ELF is not set -+# CONFIG_HAS_BOARD_SIZE_LIMIT is not set -+# CONFIG_SYS_CUSTOM_LDSCRIPT is not set -+CONFIG_PLATFORM_ELFENTRY="_start" -+CONFIG_STACK_SIZE=0x1000000 -+CONFIG_SYS_SRAM_BASE=0x0 -+CONFIG_SYS_SRAM_SIZE=0x0 -+# CONFIG_MP is not set -+CONFIG_HAVE_TEXT_BASE=y -+# CONFIG_HAVE_SYS_UBOOT_START is not set -+CONFIG_SYS_UBOOT_START=0x41e00000 -+# CONFIG_DYNAMIC_SYS_CLK_FREQ is not set -+# CONFIG_API is not set -+ -+# -+# Boot options -+# -+ -+# -+# Boot images -+# -+# CONFIG_ANDROID_BOOT_IMAGE is not set -+# CONFIG_TIMESTAMP is not set -+CONFIG_FIT=y -+CONFIG_FIT_EXTERNAL_OFFSET=0x0 -+CONFIG_FIT_FULL_CHECK=y -+# CONFIG_FIT_SIGNATURE is not set -+# CONFIG_FIT_CIPHER is not set -+# CONFIG_FIT_VERBOSE is not set -+# CONFIG_FIT_BEST_MATCH is not set -+CONFIG_FIT_PRINT=y -+# CONFIG_SPL_LOAD_FIT_FULL is not set -+CONFIG_PXE_UTILS=y -+CONFIG_BOOTSTD=y -+# CONFIG_BOOTSTD_FULL is not set -+# CONFIG_BOOTSTD_DEFAULTS is not set -+CONFIG_BOOTSTD_BOOTCOMMAND=y -+CONFIG_BOOTMETH_GLOBAL=y -+# CONFIG_BOOTMETH_CROS is not set -+CONFIG_BOOTMETH_EXTLINUX=y -+CONFIG_BOOTMETH_EXTLINUX_PXE=y -+CONFIG_BOOTMETH_EFILOADER=y -+CONFIG_BOOTMETH_VBE=y -+CONFIG_BOOTMETH_VBE_REQUEST=y -+CONFIG_BOOTMETH_VBE_SIMPLE=y -+CONFIG_BOOTMETH_VBE_SIMPLE_OS=y -+# CONFIG_BOOTMETH_SCRIPT is not set -+CONFIG_LEGACY_IMAGE_FORMAT=y -+# CONFIG_SUPPORT_RAW_INITRD is not set -+# CONFIG_CHROMEOS is not set -+# CONFIG_CHROMEOS_VBOOT is not set -+# CONFIG_RAMBOOT_PBL is not set -+CONFIG_SYS_BOOT_RAMDISK_HIGH=y -+# CONFIG_DISTRO_DEFAULTS is not set -+ -+# -+# Boot timing -+# -+# CONFIG_BOOTSTAGE is not set -+CONFIG_BOOTSTAGE_STASH_SIZE=0x1000 -+# CONFIG_SHOW_BOOT_PROGRESS is not set -+ -+# -+# Boot media -+# -+CONFIG_NAND_BOOT=y -+# CONFIG_ONENAND_BOOT is not set -+# CONFIG_QSPI_BOOT is not set -+# CONFIG_SATA_BOOT is not set -+# CONFIG_SD_BOOT is not set -+# CONFIG_SD_BOOT_QSPI is not set -+CONFIG_SPI_BOOT=y -+ -+# -+# Autoboot options -+# -+CONFIG_AUTOBOOT=y -+CONFIG_BOOTDELAY=2 -+# CONFIG_AUTOBOOT_KEYED is not set -+# CONFIG_AUTOBOOT_USE_MENUKEY is not set -+CONFIG_AUTOBOOT_MENU_SHOW=y -+# CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE is not set -+# CONFIG_BOOT_RETRY is not set -+ -+# -+# Image support -+# -+# CONFIG_IMAGE_PRE_LOAD is not set -+ -+# -+# Devicetree fixup -+# -+# CONFIG_OF_BOARD_SETUP is not set -+# CONFIG_OF_SYSTEM_SETUP is not set -+# CONFIG_OF_STDOUT_VIA_ALIAS is not set -+# CONFIG_FDT_FIXUP_PARTITIONS is not set -+# CONFIG_FDT_SIMPLEFB is not set -+CONFIG_ARCH_FIXUP_FDT_MEMORY=y -+# CONFIG_USE_BOOTARGS is not set -+# CONFIG_BOOTARGS_SUBST is not set -+# CONFIG_USE_BOOTCOMMAND is not set -+CONFIG_USE_PREBOOT=y -+CONFIG_DEFAULT_FDT_FILE="openwrt-one" -+# CONFIG_SAVE_PREV_BL_FDT_ADDR is not set -+# CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR is not set -+ -+# -+# Configuration editor -+# -+# CONFIG_CEDIT is not set -+ -+# -+# Console -+# -+CONFIG_MENU=y -+# CONFIG_CONSOLE_RECORD is not set -+# CONFIG_DISABLE_CONSOLE is not set -+CONFIG_LOGLEVEL=7 -+# CONFIG_SILENT_CONSOLE is not set -+# CONFIG_SPL_SILENT_CONSOLE is not set -+# CONFIG_TPL_SILENT_CONSOLE is not set -+# CONFIG_PRE_CONSOLE_BUFFER is not set -+CONFIG_CONSOLE_FLUSH_SUPPORT=y -+# CONFIG_CONSOLE_FLUSH_ON_NEWLINE is not set -+# CONFIG_CONSOLE_MUX is not set -+# CONFIG_SYS_CONSOLE_IS_IN_ENV is not set -+# CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE is not set -+# CONFIG_SYS_CONSOLE_INFO_QUIET is not set -+# CONFIG_SYS_STDIO_DEREGISTER is not set -+# CONFIG_SPL_SYS_STDIO_DEREGISTER is not set -+# CONFIG_SYS_DEVICE_NULLDEV is not set -+ -+# -+# Logging -+# -+CONFIG_LOG=y -+CONFIG_LOG_MAX_LEVEL=6 -+CONFIG_LOG_DEFAULT_LEVEL=6 -+CONFIG_LOG_CONSOLE=y -+# CONFIG_LOGF_FILE is not set -+# CONFIG_LOGF_LINE is not set -+# CONFIG_LOGF_FUNC is not set -+CONFIG_LOGF_FUNC_PAD=20 -+# CONFIG_LOG_SYSLOG is not set -+# CONFIG_LOG_ERROR_RETURN is not set -+ -+# -+# Init options -+# -+# CONFIG_BOARD_TYPES is not set -+CONFIG_DISPLAY_CPUINFO=y -+CONFIG_DISPLAY_BOARDINFO=y -+# CONFIG_DISPLAY_BOARDINFO_LATE is not set -+ -+# -+# Start-up hooks -+# -+# CONFIG_CYCLIC is not set -+CONFIG_EVENT=y -+CONFIG_EVENT_DYNAMIC=y -+# CONFIG_EVENT_DEBUG is not set -+# CONFIG_ARCH_MISC_INIT is not set -+# CONFIG_BOARD_EARLY_INIT_F is not set -+# CONFIG_BOARD_EARLY_INIT_R is not set -+# CONFIG_BOARD_POSTCLK_INIT is not set -+CONFIG_BOARD_LATE_INIT=y -+# CONFIG_CLOCKS is not set -+# CONFIG_HWCONFIG is not set -+CONFIG_LAST_STAGE_INIT=y -+# CONFIG_MISC_INIT_R is not set -+# CONFIG_SYS_MALLOC_BOOTPARAMS is not set -+# CONFIG_ID_EEPROM is not set -+# CONFIG_RESET_PHY_R is not set -+ -+# -+# Security support -+# -+CONFIG_HASH=y -+# CONFIG_STACKPROTECTOR is not set -+# CONFIG_BOARD_RNG_SEED is not set -+ -+# -+# Update support -+# -+# CONFIG_UPDATE_TFTP is not set -+# CONFIG_ANDROID_AB is not set -+ -+# -+# Blob list -+# -+# CONFIG_BLOBLIST is not set -+CONFIG_SUPPORT_SPL=y -+# CONFIG_VPL is not set -+ -+# -+# Command line interface -+# -+CONFIG_CMDLINE=y -+CONFIG_HUSH_PARSER=y -+CONFIG_CMDLINE_EDITING=y -+# CONFIG_CMDLINE_PS_SUPPORT is not set -+CONFIG_AUTO_COMPLETE=y -+CONFIG_SYS_LONGHELP=y -+CONFIG_SYS_PROMPT="OpenWrt One> " -+CONFIG_SYS_PROMPT_HUSH_PS2="> " -+CONFIG_SYS_MAXARGS=16 -+CONFIG_SYS_CBSIZE=512 -+CONFIG_SYS_PBSIZE=1049 -+CONFIG_SYS_XTRACE=y -+CONFIG_BUILD_BIN2C=y -+ -+# -+# Commands -+# -+ -+# -+# Info commands -+# -+CONFIG_CMD_BDI=y -+# CONFIG_CMD_BDINFO_EXTRA is not set -+# CONFIG_CMD_CONFIG is not set -+CONFIG_CMD_CONSOLE=y -+CONFIG_CMD_CPU=y -+# CONFIG_CMD_HISTORY is not set -+CONFIG_CMD_LICENSE=y -+# CONFIG_CMD_PMC is not set -+ -+# -+# Boot commands -+# -+CONFIG_CMD_BOOTD=y -+CONFIG_CMD_BOOTM=y -+# CONFIG_CMD_BOOTDEV is not set -+CONFIG_CMD_BOOTFLOW=y -+# CONFIG_CMD_BOOTMETH is not set -+CONFIG_BOOTM_EFI=y -+# CONFIG_CMD_BOOTZ is not set -+CONFIG_CMD_BOOTI=y -+CONFIG_BOOTM_LINUX=y -+# CONFIG_BOOTM_NETBSD is not set -+# CONFIG_BOOTM_OPENRTOS is not set -+# CONFIG_BOOTM_OSE is not set -+# CONFIG_BOOTM_PLAN9 is not set -+# CONFIG_BOOTM_RTEMS is not set -+# CONFIG_CMD_VBE is not set -+# CONFIG_BOOTM_VXWORKS is not set -+CONFIG_SYS_BOOTM_LEN=0x4000000 -+CONFIG_CMD_BOOTEFI=y -+CONFIG_CMD_BOOTEFI_HELLO_COMPILE=y -+# CONFIG_CMD_BOOTEFI_HELLO is not set -+# CONFIG_CMD_BOOTEFI_SELFTEST is not set -+CONFIG_CMD_BOOTMENU=y -+# CONFIG_CMD_ADTIMG is not set -+CONFIG_CMD_ELF=y -+CONFIG_CMD_FDT=y -+CONFIG_CMD_GO=y -+CONFIG_CMD_RUN=y -+CONFIG_CMD_IMI=y -+# CONFIG_CMD_IMLS is not set -+CONFIG_CMD_XIMG=y -+# CONFIG_CMD_ZBOOT is not set -+ -+# -+# Environment commands -+# -+CONFIG_CMD_ASKENV=y -+CONFIG_CMD_EXPORTENV=y -+CONFIG_CMD_IMPORTENV=y -+CONFIG_CMD_EDITENV=y -+# CONFIG_CMD_GREPENV is not set -+CONFIG_CMD_SAVEENV=y -+CONFIG_CMD_ERASEENV=y -+CONFIG_CMD_ENV_EXISTS=y -+CONFIG_CMD_ENV_READMEM=y -+# CONFIG_CMD_ENV_CALLBACK is not set -+CONFIG_CMD_ENV_FLAGS=y -+# CONFIG_CMD_NVEDIT_EFI is not set -+# CONFIG_CMD_NVEDIT_INDIRECT is not set -+# CONFIG_CMD_NVEDIT_INFO is not set -+# CONFIG_CMD_NVEDIT_LOAD is not set -+# CONFIG_CMD_NVEDIT_SELECT is not set -+ -+# -+# Memory commands -+# -+# CONFIG_CMD_BINOP is not set -+# CONFIG_CMD_BLOBLIST is not set -+CONFIG_CMD_CRC32=y -+# CONFIG_CRC32_VERIFY is not set -+# CONFIG_CMD_EEPROM is not set -+# CONFIG_LOOPW is not set -+# CONFIG_CMD_MD5SUM is not set -+# CONFIG_CMD_MEMINFO is not set -+CONFIG_CMD_MEMORY=y -+# CONFIG_CMD_MEM_SEARCH is not set -+# CONFIG_CMD_MX_CYCLIC is not set -+CONFIG_CMD_RANDOM=y -+# CONFIG_CMD_MEMTEST is not set -+# CONFIG_CMD_SHA1SUM is not set -+CONFIG_CMD_STRINGS=y -+ -+# -+# Compression commands -+# -+CONFIG_CMD_LZMADEC=y -+# CONFIG_CMD_UNLZ4 is not set -+# CONFIG_CMD_UNZIP is not set -+# CONFIG_CMD_ZIP is not set -+ -+# -+# Device access commands -+# -+# CONFIG_CMD_ARMFLASH is not set -+# CONFIG_CMD_BIND is not set -+# CONFIG_CMD_CLK is not set -+# CONFIG_CMD_DEMO is not set -+# CONFIG_CMD_DFU is not set -+CONFIG_CMD_DM=y -+CONFIG_CMD_FLASH=y -+# CONFIG_CMD_FPGAD is not set -+# CONFIG_CMD_FUSE is not set -+CONFIG_CMD_GPIO=y -+# CONFIG_CMD_GPIO_READ is not set -+CONFIG_CMD_PWM=y -+# CONFIG_CMD_GPT is not set -+# CONFIG_RANDOM_UUID is not set -+# CONFIG_CMD_IDE is not set -+# CONFIG_CMD_IO is not set -+# CONFIG_CMD_IOTRACE is not set -+# CONFIG_CMD_I2C is not set -+CONFIG_CMD_LOADB=y -+# CONFIG_CMD_LOADM is not set -+CONFIG_CMD_LOADS=y -+# CONFIG_LOADS_ECHO is not set -+# CONFIG_CMD_SAVES is not set -+# CONFIG_SYS_LOADS_BAUD_CHANGE is not set -+CONFIG_CMD_LOADXY_TIMEOUT=90 -+# CONFIG_CMD_LSBLK is not set -+# CONFIG_CMD_MBR is not set -+# CONFIG_CMD_CLONE is not set -+CONFIG_CMD_MTD=y -+CONFIG_CMD_NAND_EXT=y -+# CONFIG_CMD_ONENAND is not set -+# CONFIG_CMD_OSD is not set -+# CONFIG_CMD_PART is not set -+CONFIG_CMD_PCI=y -+CONFIG_CMD_PINMUX=y -+# CONFIG_CMD_POWEROFF is not set -+# CONFIG_CMD_READ is not set -+# CONFIG_CMD_SATA is not set -+# CONFIG_CMD_SDRAM is not set -+CONFIG_CMD_SF=y -+CONFIG_CMD_SF_TEST=y -+# CONFIG_CMD_SPI is not set -+# CONFIG_CMD_TSI148 is not set -+# CONFIG_CMD_UNIVERSE is not set -+CONFIG_CMD_USB=y -+# CONFIG_CMD_USB_SDP is not set -+# CONFIG_CMD_RKMTD is not set -+# CONFIG_CMD_WRITE is not set -+ -+# -+# Shell scripting commands -+# -+# CONFIG_CMD_CAT is not set -+CONFIG_CMD_ECHO=y -+CONFIG_CMD_ITEST=y -+CONFIG_CMD_SOURCE=y -+CONFIG_CMD_SETEXPR=y -+# CONFIG_CMD_SETEXPR_FMT is not set -+# CONFIG_CMD_XXD is not set -+ -+# -+# Android support commands -+# -+CONFIG_CMD_NET=y -+CONFIG_CMD_BOOTP=y -+CONFIG_CMD_DHCP=y -+# CONFIG_BOOTP_MAY_FAIL is not set -+CONFIG_BOOTP_BOOTPATH=y -+# CONFIG_BOOTP_VENDOREX is not set -+# CONFIG_BOOTP_BOOTFILESIZE is not set -+CONFIG_BOOTP_DNS=y -+# CONFIG_BOOTP_DNS2 is not set -+CONFIG_BOOTP_GATEWAY=y -+CONFIG_BOOTP_HOSTNAME=y -+# CONFIG_BOOTP_PREFER_SERVERIP is not set -+CONFIG_BOOTP_SUBNETMASK=y -+# CONFIG_BOOTP_NISDOMAIN is not set -+# CONFIG_BOOTP_NTPSERVER is not set -+# CONFIG_BOOTP_TIMEOFFSET is not set -+# CONFIG_CMD_PCAP is not set -+CONFIG_BOOTP_PXE=y -+CONFIG_BOOTP_PXE_CLIENTARCH=0x16 -+# CONFIG_BOOTP_PXE_DHCP_OPTION is not set -+CONFIG_BOOTP_VCI_STRING="U-Boot.armv8" -+CONFIG_CMD_TFTPBOOT=y -+# CONFIG_CMD_TFTPPUT is not set -+CONFIG_CMD_TFTPSRV=y -+CONFIG_NET_TFTP_VARS=y -+CONFIG_CMD_RARP=y -+# CONFIG_CMD_NFS is not set -+# CONFIG_SYS_DISABLE_AUTOLOAD is not set -+# CONFIG_CMD_WGET is not set -+# CONFIG_CMD_MII is not set -+# CONFIG_CMD_MDIO is not set -+CONFIG_CMD_PING=y -+CONFIG_CMD_CDP=y -+CONFIG_CMD_SNTP=y -+CONFIG_CMD_DNS=y -+CONFIG_CMD_LINK_LOCAL=y -+# CONFIG_CMD_ETHSW is not set -+CONFIG_CMD_PXE=y -+# CONFIG_CMD_WOL is not set -+ -+# -+# Misc commands -+# -+# CONFIG_CMD_2048 is not set -+# CONFIG_CMD_BSP is not set -+CONFIG_CMD_BLOCK_CACHE=y -+CONFIG_CMD_BUTTON=y -+CONFIG_CMD_CACHE=y -+# CONFIG_CMD_CONITRACE is not set -+# CONFIG_CMD_CLS is not set -+# CONFIG_CMD_EFIDEBUG is not set -+CONFIG_CMD_EFICONFIG=y -+# CONFIG_CMD_EXCEPTION is not set -+CONFIG_CMD_LED=y -+# CONFIG_CMD_INI is not set -+# CONFIG_CMD_DATE is not set -+# CONFIG_CMD_TIME is not set -+# CONFIG_CMD_GETTIME is not set -+# CONFIG_CMD_PAUSE is not set -+CONFIG_CMD_SLEEP=y -+# CONFIG_CMD_TIMER is not set -+# CONFIG_CMD_SYSBOOT is not set -+# CONFIG_CMD_QFW is not set -+CONFIG_CMD_PSTORE=y -+CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 -+CONFIG_CMD_PSTORE_MEM_SIZE=0x10000 -+CONFIG_CMD_PSTORE_RECORD_SIZE=0x1000 -+CONFIG_CMD_PSTORE_CONSOLE_SIZE=0x1000 -+CONFIG_CMD_PSTORE_FTRACE_SIZE=0x1000 -+CONFIG_CMD_PSTORE_PMSG_SIZE=0x1000 -+CONFIG_CMD_PSTORE_ECC_SIZE=0 -+# CONFIG_CMD_TERMINAL is not set -+CONFIG_CMD_UUID=y -+ -+# -+# TI specific command line interface -+# -+ -+# -+# Power commands -+# -+ -+# -+# Security commands -+# -+# CONFIG_CMD_AES is not set -+# CONFIG_CMD_BLOB is not set -+CONFIG_CMD_HASH=y -+# CONFIG_CMD_HVC is not set -+CONFIG_CMD_SMC=y -+# CONFIG_HASH_VERIFY is not set -+ -+# -+# Firmware commands -+# -+ -+# -+# Filesystem commands -+# -+# CONFIG_CMD_BTRFS is not set -+# CONFIG_CMD_EROFS is not set -+# CONFIG_CMD_EXT2 is not set -+# CONFIG_CMD_EXT4 is not set -+CONFIG_CMD_FAT=y -+# CONFIG_CMD_SQUASHFS is not set -+CONFIG_CMD_FS_GENERIC=y -+CONFIG_CMD_FS_UUID=y -+# CONFIG_CMD_JFFS2 is not set -+# CONFIG_CMD_MTDPARTS is not set -+CONFIG_MTDIDS_DEFAULT="" -+CONFIG_MTDPARTS_DEFAULT="" -+# CONFIG_CMD_REISER is not set -+# CONFIG_CMD_ZFS is not set -+ -+# -+# Debug commands -+# -+# CONFIG_CMD_DIAG is not set -+# CONFIG_CMD_EVENT is not set -+# CONFIG_CMD_LOG is not set -+CONFIG_CMD_UBI=y -+CONFIG_CMD_UBI_RENAME=y -+CONFIG_CMD_UBIFS=y -+ -+# -+# Partition Types -+# -+CONFIG_PARTITIONS=y -+# CONFIG_MAC_PARTITION is not set -+CONFIG_DOS_PARTITION=y -+# CONFIG_ISO_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+CONFIG_PARTITION_UUIDS=y -+CONFIG_SUPPORT_OF_CONTROL=y -+ -+# -+# Device Tree Control -+# -+CONFIG_OF_CONTROL=y -+CONFIG_OF_REAL=y -+# CONFIG_OF_LIVE is not set -+CONFIG_OF_SEPARATE=y -+# CONFIG_OF_EMBED is not set -+# CONFIG_OF_BOARD is not set -+# CONFIG_OF_OMIT_DTB is not set -+CONFIG_DEVICE_TREE_INCLUDES="" -+CONFIG_OF_LIST="openwrt-one" -+# CONFIG_MULTI_DTB_FIT is not set -+CONFIG_OF_TAG_MIGRATE=y -+# CONFIG_OF_DTB_PROPS_REMOVE is not set -+ -+# -+# Environment -+# -+CONFIG_ENV_SUPPORT=y -+CONFIG_SAVEENV=y -+CONFIG_ENV_OVERWRITE=y -+CONFIG_ENV_MIN_ENTRIES=64 -+CONFIG_ENV_MAX_ENTRIES=512 -+# CONFIG_ENV_IS_NOWHERE is not set -+# CONFIG_ENV_IS_IN_EEPROM is not set -+# CONFIG_ENV_IS_IN_FAT is not set -+# CONFIG_ENV_IS_IN_EXT4 is not set -+# CONFIG_ENV_IS_IN_FLASH is not set -+# CONFIG_ENV_IS_IN_MTD is not set -+# CONFIG_ENV_IS_IN_NAND is not set -+# CONFIG_ENV_IS_IN_NVRAM is not set -+# CONFIG_ENV_IS_IN_ONENAND is not set -+# CONFIG_ENV_IS_IN_REMOTE is not set -+# CONFIG_ENV_IS_IN_SPI_FLASH is not set -+CONFIG_ENV_IS_IN_UBI=y -+CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -+CONFIG_ENV_UBI_PART="ubi" -+CONFIG_ENV_UBI_VOLUME="ubootenv" -+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" -+# CONFIG_ENV_UBI_VOLUME_CREATE is not set -+CONFIG_ENV_UBI_VID_OFFSET=0 -+CONFIG_SYS_RELOC_GD_ENV_ADDR=y -+CONFIG_USE_DEFAULT_ENV_FILE=y -+CONFIG_DEFAULT_ENV_FILE="openwrt-one-spi-nand_env" -+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -+# CONFIG_ENV_IMPORT_FDT is not set -+# CONFIG_ENV_APPEND is not set -+# CONFIG_ENV_WRITEABLE_LIST is not set -+# CONFIG_ENV_ACCESS_IGNORE_FORCE is not set -+# CONFIG_USE_BOOTFILE is not set -+# CONFIG_USE_ETHPRIME is not set -+# CONFIG_USE_HOSTNAME is not set -+# CONFIG_VERSION_VARIABLE is not set -+CONFIG_NET=y -+CONFIG_ARP_TIMEOUT=5000 -+CONFIG_NET_RETRY_COUNT=5 -+CONFIG_PROT_UDP=y -+CONFIG_BOOTDEV_ETH=y -+# CONFIG_BOOTP_SEND_HOSTNAME is not set -+CONFIG_NET_RANDOM_ETHADDR=y -+# CONFIG_NETCONSOLE is not set -+# CONFIG_IP_DEFRAG is not set -+# CONFIG_SYS_FAULT_ECHO_LINK_DOWN is not set -+CONFIG_TFTP_BLOCKSIZE=1468 -+# CONFIG_TFTP_PORT is not set -+CONFIG_TFTP_WINDOWSIZE=1 -+# CONFIG_TFTP_TSIZE is not set -+# CONFIG_SERVERIP_FROM_PROXYDHCP is not set -+CONFIG_SERVERIP_FROM_PROXYDHCP_DELAY_MS=100 -+# CONFIG_KEEP_SERVERADDR is not set -+# CONFIG_UDP_CHECKSUM is not set -+# CONFIG_BOOTP_SERVERIP is not set -+CONFIG_BOOTP_MAX_ROOT_PATH_LEN=64 -+# CONFIG_USE_GATEWAYIP is not set -+# CONFIG_USE_IPADDR is not set -+# CONFIG_USE_NETMASK is not set -+# CONFIG_USE_ROOTPATH is not set -+# CONFIG_USE_SERVERIP is not set -+# CONFIG_PROT_TCP is not set -+# CONFIG_IPV6 is not set -+CONFIG_SYS_RX_ETH_BUFFER=4 -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_DM=y -+# CONFIG_DM_WARN is not set -+# CONFIG_DM_DEBUG is not set -+# CONFIG_DM_STATS is not set -+CONFIG_DM_DEVICE_REMOVE=y -+CONFIG_DM_EVENT=y -+CONFIG_DM_STDIO=y -+CONFIG_DM_SEQ_ALIAS=y -+# CONFIG_DM_DMA is not set -+CONFIG_REGMAP=y -+CONFIG_SYSCON=y -+# CONFIG_DEVRES is not set -+CONFIG_SIMPLE_BUS=y -+# CONFIG_SIMPLE_BUS_CORRECT_RANGE is not set -+# CONFIG_SIMPLE_PM_BUS is not set -+CONFIG_OF_TRANSLATE=y -+# CONFIG_TRANSLATION_OFFSET is not set -+CONFIG_DM_DEV_READ_INLINE=y -+# CONFIG_OFNODE_MULTI_TREE is not set -+# CONFIG_BOUNCE_BUFFER is not set -+# CONFIG_ADC is not set -+# CONFIG_ADC_EXYNOS is not set -+# CONFIG_ADC_SANDBOX is not set -+# CONFIG_SARADC_MESON is not set -+# CONFIG_SARADC_ROCKCHIP is not set -+# CONFIG_SATA is not set -+# CONFIG_SCSI_AHCI is not set -+ -+# -+# SATA/SCSI device support -+# -+# CONFIG_AXI is not set -+ -+# -+# Bus devices -+# -+CONFIG_BLK=y -+CONFIG_BLOCK_CACHE=y -+# CONFIG_BLKMAP is not set -+# CONFIG_EFI_MEDIA is not set -+# CONFIG_IDE is not set -+# CONFIG_LBA48 is not set -+# CONFIG_SYS_64BIT_LBA is not set -+# CONFIG_RKMTD is not set -+# CONFIG_BOOTCOUNT_LIMIT is not set -+ -+# -+# Button Support -+# -+CONFIG_BUTTON=y -+# CONFIG_BUTTON_ADC is not set -+CONFIG_BUTTON_GPIO=y -+ -+# -+# Cache Controller drivers -+# -+# CONFIG_CACHE is not set -+# CONFIG_L2X0_CACHE is not set -+# CONFIG_V5L2_CACHE is not set -+# CONFIG_NCORE_CACHE is not set -+# CONFIG_SIFIVE_CCACHE is not set -+ -+# -+# Clock -+# -+CONFIG_CLK=y -+# CONFIG_CLK_CCF is not set -+# CONFIG_CLK_GPIO is not set -+# CONFIG_CLK_CDCE9XX is not set -+# CONFIG_CLK_ICS8N3QV01 is not set -+# CONFIG_CLK_K210 is not set -+# CONFIG_CLK_MPC83XX is not set -+# CONFIG_CLK_XLNX_CLKWZRD is not set -+# CONFIG_CLK_AT91 is not set -+# CONFIG_CLK_RCAR is not set -+# CONFIG_CLK_RCAR_CPG_LIB is not set -+# CONFIG_CLK_SIFIVE is not set -+# CONFIG_CLK_TI_AM3_DPLL is not set -+# CONFIG_CLK_TI_CTRL is not set -+# CONFIG_CLK_TI_GATE is not set -+# CONFIG_CLK_K3 is not set -+CONFIG_CPU=y -+# CONFIG_CPU_IMX is not set -+ -+# -+# Hardware crypto devices -+# -+# CONFIG_DM_HASH is not set -+# CONFIG_FSL_CAAM is not set -+CONFIG_CAAM_64BIT=y -+# CONFIG_SYS_FSL_SEC_BE is not set -+# CONFIG_SYS_FSL_SEC_LE is not set -+# CONFIG_NPCM_AES is not set -+# CONFIG_NPCM_SHA is not set -+# CONFIG_DDR_SPD is not set -+# CONFIG_IMX_SNPS_DDR_PHY is not set -+ -+# -+# Demo for driver model -+# -+# CONFIG_DM_DEMO is not set -+ -+# -+# DFU support -+# -+ -+# -+# DMA Support -+# -+# CONFIG_DMA is not set -+# CONFIG_DMA_LPC32XX is not set -+# CONFIG_TI_EDMA3 is not set -+# CONFIG_DMA_LEGACY is not set -+ -+# -+# Extcon Support -+# -+# CONFIG_EXTCON is not set -+ -+# -+# Fastboot support -+# -+# CONFIG_UDP_FUNCTION_FASTBOOT is not set -+# CONFIG_TCP_FUNCTION_FASTBOOT is not set -+CONFIG_FIRMWARE=y -+CONFIG_ARM_PSCI_FW=y -+# CONFIG_ZYNQMP_FIRMWARE is not set -+# CONFIG_ARM_SMCCC_FEATURES is not set -+# CONFIG_ARM_FFA_TRANSPORT is not set -+# CONFIG_SCMI_FIRMWARE is not set -+# CONFIG_DM_FUZZING_ENGINE is not set -+ -+# -+# FPGA support -+# -+# CONFIG_FPGA_ALTERA is not set -+# CONFIG_FPGA_SOCFPGA is not set -+# CONFIG_FPGA_LATTICE is not set -+# CONFIG_FPGA_XILINX is not set -+# CONFIG_DM_FPGA is not set -+# CONFIG_FWU_MDATA is not set -+CONFIG_GPIO=y -+CONFIG_GPIO_HOG=y -+# CONFIG_DM_GPIO_LOOKUP_LABEL is not set -+# CONFIG_ALTERA_PIO is not set -+# CONFIG_BCM2835_GPIO is not set -+# CONFIG_DWAPB_GPIO is not set -+# CONFIG_AT91_GPIO is not set -+# CONFIG_ATMEL_PIO4 is not set -+# CONFIG_ASPEED_GPIO is not set -+# CONFIG_DA8XX_GPIO is not set -+# CONFIG_HIKEY_GPIO is not set -+# CONFIG_INTEL_BROADWELL_GPIO is not set -+# CONFIG_INTEL_GPIO is not set -+# CONFIG_INTEL_ICH6_GPIO is not set -+# CONFIG_IMX_RGPIO2P is not set -+# CONFIG_IPROC_GPIO is not set -+# CONFIG_HSDK_CREG_GPIO is not set -+# CONFIG_KIRKWOOD_GPIO is not set -+# CONFIG_LPC32XX_GPIO is not set -+# CONFIG_MCP230XX_GPIO is not set -+# CONFIG_MSM_GPIO is not set -+# CONFIG_MXC_GPIO is not set -+# CONFIG_MXS_GPIO is not set -+# CONFIG_NPCM_GPIO is not set -+# CONFIG_CMD_PCA953X is not set -+# CONFIG_ROCKCHIP_GPIO is not set -+# CONFIG_XILINX_GPIO is not set -+# CONFIG_TCA642X is not set -+# CONFIG_TEGRA_GPIO is not set -+# CONFIG_TEGRA186_GPIO is not set -+# CONFIG_VYBRID_GPIO is not set -+# CONFIG_SIFIVE_GPIO is not set -+# CONFIG_ZYNQ_GPIO is not set -+# CONFIG_DM_74X164 is not set -+# CONFIG_PCA953X is not set -+# CONFIG_MPC8XXX_GPIO is not set -+# CONFIG_MPC8XX_GPIO is not set -+# CONFIG_NX_GPIO is not set -+# CONFIG_NOMADIK_GPIO is not set -+# CONFIG_ZYNQMP_GPIO_MODEPIN is not set -+# CONFIG_SLG7XL45106_I2C_GPO is not set -+# CONFIG_TURRIS_OMNIA_MCU is not set -+# CONFIG_FTGPIO010 is not set -+ -+# -+# Hardware Spinlock Support -+# -+# CONFIG_DM_HWSPINLOCK is not set -+CONFIG_I2C=y -+# CONFIG_DM_I2C is not set -+# CONFIG_SYS_I2C_LEGACY is not set -+# CONFIG_SPL_SYS_I2C_LEGACY is not set -+# CONFIG_SYS_I2C_FSL is not set -+# CONFIG_SYS_I2C_DW is not set -+# CONFIG_SYS_I2C_IMX_LPI2C is not set -+# CONFIG_SYS_I2C_MTK is not set -+# CONFIG_SYS_I2C_MICROCHIP is not set -+# CONFIG_SYS_I2C_MXC is not set -+# CONFIG_SYS_I2C_NPCM is not set -+# CONFIG_SYS_I2C_SOFT is not set -+# CONFIG_SYS_I2C_MV is not set -+# CONFIG_SYS_I2C_MVTWSI is not set -+CONFIG_INPUT=y -+# CONFIG_DM_KEYBOARD is not set -+# CONFIG_CROS_EC_KEYB is not set -+# CONFIG_TEGRA_KEYBOARD is not set -+# CONFIG_TWL4030_INPUT is not set -+ -+# -+# IOMMU device drivers -+# -+# CONFIG_IOMMU is not set -+ -+# -+# LED Support -+# -+CONFIG_LED=y -+# CONFIG_LED_PWM is not set -+CONFIG_LED_BLINK=y -+CONFIG_LED_GPIO=y -+# CONFIG_LED_STATUS is not set -+ -+# -+# Mailbox Controller Support -+# -+# CONFIG_DM_MAILBOX is not set -+ -+# -+# Memory Controller drivers -+# -+# CONFIG_MEMORY is not set -+# CONFIG_ATMEL_EBI is not set -+# CONFIG_MFD_ATMEL_SMC is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MISC is not set -+# CONFIG_NVMEM is not set -+# CONFIG_SPL_NVMEM is not set -+# CONFIG_SMSC_LPC47M is not set -+# CONFIG_SMSC_SIO1007 is not set -+# CONFIG_CROS_EC is not set -+# CONFIG_DS4510 is not set -+# CONFIG_FSL_SEC_MON is not set -+# CONFIG_IRQ is not set -+# CONFIG_NPCM_HOST is not set -+# CONFIG_NUVOTON_NCT6102D is not set -+# CONFIG_PWRSEQ is not set -+# CONFIG_PCA9551_LED is not set -+# CONFIG_TEST_DRV is not set -+# CONFIG_USB_HUB_USB251XB is not set -+# CONFIG_TWL4030_LED is not set -+# CONFIG_WINBOND_W83627 is not set -+# CONFIG_FS_LOADER is not set -+ -+# -+# MMC Host controller Support -+# -+# CONFIG_MMC is not set -+# CONFIG_MMC_BROKEN_CD is not set -+# CONFIG_DM_MMC is not set -+# CONFIG_FSL_ESDHC is not set -+# CONFIG_FSL_ESDHC_IMX is not set -+ -+# -+# MTD Support -+# -+CONFIG_MTD_PARTITIONS=y -+CONFIG_MTD=y -+CONFIG_DM_MTD=y -+# CONFIG_MTD_NOR_FLASH is not set -+# CONFIG_MTD_CONCAT is not set -+# CONFIG_SYS_MTDPARTS_RUNTIME is not set -+# CONFIG_FLASH_CFI_DRIVER is not set -+# CONFIG_CFI_FLASH is not set -+# CONFIG_ALTERA_QSPI is not set -+# CONFIG_HBMC_AM654 is not set -+# CONFIG_SAMSUNG_ONENAND is not set -+# CONFIG_USE_SYS_MAX_FLASH_BANKS is not set -+CONFIG_MTD_NAND_CORE=y -+# CONFIG_MTD_RAW_NAND is not set -+CONFIG_MTD_SPI_NAND=y -+ -+# -+# SPI Flash Support -+# -+CONFIG_DM_SPI_FLASH=y -+CONFIG_SPI_FLASH=y -+CONFIG_SF_DEFAULT_BUS=0 -+CONFIG_SF_DEFAULT_CS=0 -+# CONFIG_BOOTDEV_SPI_FLASH is not set -+CONFIG_SPI_FLASH_SFDP_SUPPORT=y -+CONFIG_SPI_FLASH_SMART_HWCAPS=y -+# CONFIG_SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT is not set -+# CONFIG_SPI_FLASH_SOFT_RESET is not set -+# CONFIG_SPI_FLASH_BAR is not set -+CONFIG_SPI_FLASH_LOCK=y -+CONFIG_SPI_FLASH_UNLOCK_ALL=y -+# CONFIG_SPI_FLASH_ATMEL is not set -+CONFIG_SPI_FLASH_EON=y -+CONFIG_SPI_FLASH_GIGADEVICE=y -+CONFIG_SPI_FLASH_ISSI=y -+CONFIG_SPI_FLASH_MACRONIX=y -+CONFIG_SPI_FLASH_SPANSION=y -+# CONFIG_SPI_FLASH_S28HX_T is not set -+CONFIG_SPI_FLASH_STMICRO=y -+# CONFIG_SPI_FLASH_MT35XU is not set -+# CONFIG_SPI_FLASH_SST is not set -+CONFIG_SPI_FLASH_WINBOND=y -+CONFIG_SPI_FLASH_XMC=y -+CONFIG_SPI_FLASH_XTX=y -+# CONFIG_SPI_FLASH_ZBIT is not set -+CONFIG_SPI_FLASH_USE_4K_SECTORS=y -+# CONFIG_SPI_FLASH_DATAFLASH is not set -+CONFIG_SPI_FLASH_MTD=y -+ -+# -+# UBI support -+# -+CONFIG_UBI_SILENCE_MSG=y -+CONFIG_MTD_UBI=y -+CONFIG_MTD_UBI_MODULE=y -+CONFIG_MTD_UBI_WL_THRESHOLD=4096 -+CONFIG_MTD_UBI_BEB_LIMIT=20 -+# CONFIG_MTD_UBI_FASTMAP is not set -+# CONFIG_NVMXIP is not set -+# CONFIG_NVMXIP_QSPI is not set -+# CONFIG_NMBM is not set -+ -+# -+# Multiplexer drivers -+# -+# CONFIG_MULTIPLEXER is not set -+# CONFIG_BITBANGMII is not set -+# CONFIG_MV88E6352_SWITCH is not set -+CONFIG_PHYLIB=y -+# CONFIG_PHY_ADDR_ENABLE is not set -+# CONFIG_B53_SWITCH is not set -+# CONFIG_MV88E61XX_SWITCH is not set -+# CONFIG_PHYLIB_10G is not set -+# CONFIG_PHY_ADIN is not set -+# CONFIG_PHY_AIROHA is not set -+# CONFIG_PHY_AQUANTIA is not set -+# CONFIG_PHY_ATHEROS is not set -+# CONFIG_SPL_PHY_ATHEROS is not set -+# CONFIG_PHY_BROADCOM is not set -+# CONFIG_PHY_CORTINA is not set -+# CONFIG_PHY_DAVICOM is not set -+# CONFIG_PHY_ET1011C is not set -+# CONFIG_PHY_LXT is not set -+# CONFIG_PHY_MARVELL is not set -+# CONFIG_PHY_MARVELL_10G is not set -+# CONFIG_PHY_MESON_GXL is not set -+# CONFIG_PHY_MICREL is not set -+# CONFIG_PHY_MOTORCOMM is not set -+# CONFIG_PHY_MSCC is not set -+# CONFIG_PHY_NATSEMI is not set -+# CONFIG_PHY_NXP_C45_TJA11XX is not set -+# CONFIG_PHY_NXP_TJA11XX is not set -+# CONFIG_PHY_REALTEK is not set -+# CONFIG_PHY_SMSC is not set -+# CONFIG_PHY_TERANETICS is not set -+# CONFIG_PHY_TI is not set -+# CONFIG_PHY_TI_DP83867 is not set -+# CONFIG_PHY_TI_DP83869 is not set -+# CONFIG_PHY_TI_GENERIC is not set -+# CONFIG_PHY_VITESSE is not set -+# CONFIG_PHY_XILINX is not set -+# CONFIG_PHY_XILINX_GMII2RGMII is not set -+# CONFIG_PHY_XWAY is not set -+# CONFIG_PHY_ETHERNET_ID is not set -+CONFIG_PHY_FIXED=y -+# CONFIG_PHY_NCSI is not set -+# CONFIG_FSL_MEMAC is not set -+CONFIG_PHY_RESET_DELAY=0 -+# CONFIG_FSL_PFE is not set -+CONFIG_ETH=y -+CONFIG_DM_ETH=y -+# CONFIG_DM_MDIO is not set -+# CONFIG_DM_ETH_PHY is not set -+CONFIG_NETDEVICES=y -+# CONFIG_PHY_GIGE is not set -+# CONFIG_ALTERA_TSE is not set -+# CONFIG_BCM_SF2_ETH is not set -+# CONFIG_BCMGENET is not set -+# CONFIG_BNXT_ETH is not set -+# CONFIG_CALXEDA_XGMAC is not set -+# CONFIG_DRIVER_DM9000 is not set -+# CONFIG_DWC_ETH_QOS is not set -+# CONFIG_EEPRO100 is not set -+# CONFIG_ETH_DESIGNWARE is not set -+# CONFIG_ETH_DESIGNWARE_MESON8B is not set -+# CONFIG_ETHOC is not set -+# CONFIG_FMAN_ENET is not set -+# CONFIG_FTMAC100 is not set -+# CONFIG_FTGMAC100 is not set -+# CONFIG_MCFFEC is not set -+# CONFIG_FSLDMAFEC is not set -+# CONFIG_KS8851_MLL is not set -+# CONFIG_LITEETH is not set -+# CONFIG_MACB is not set -+# CONFIG_NET_NPCM750 is not set -+# CONFIG_PCH_GBE is not set -+# CONFIG_RGMII is not set -+# CONFIG_MII is not set -+# CONFIG_RMII is not set -+# CONFIG_PCNET is not set -+# CONFIG_QE_UEC is not set -+# CONFIG_RTL8139 is not set -+# CONFIG_SMC911X is not set -+# CONFIG_SUN7I_GMAC is not set -+# CONFIG_SUN4I_EMAC is not set -+# CONFIG_SUN8I_EMAC is not set -+# CONFIG_SH_ETHER is not set -+# CONFIG_DRIVER_TI_CPSW is not set -+# CONFIG_DRIVER_TI_EMAC is not set -+# CONFIG_DRIVER_TI_KEYSTONE_NET is not set -+# CONFIG_TULIP is not set -+# CONFIG_XILINX_AXIEMAC is not set -+# CONFIG_VSC7385_ENET is not set -+# CONFIG_XILINX_EMACLITE is not set -+# CONFIG_ZYNQ_GEM is not set -+# CONFIG_SYS_DPAA_QBMAN is not set -+# CONFIG_TSEC_ENET is not set -+CONFIG_MEDIATEK_ETH=y -+# CONFIG_HIFEMAC_ETH is not set -+# CONFIG_HIGMACV300_ETH is not set -+# CONFIG_NVME is not set -+# CONFIG_NVME_APPLE is not set -+ -+# -+# PCI Endpoint -+# -+# CONFIG_PCI_ENDPOINT is not set -+# CONFIG_X86_PCH7 is not set -+# CONFIG_X86_PCH9 is not set -+ -+# -+# PHY Subsystem -+# -+CONFIG_PHY=y -+# CONFIG_NOP_PHY is not set -+# CONFIG_MIPI_DPHY_HELPERS is not set -+# CONFIG_BCM_SR_PCIE_PHY is not set -+# CONFIG_OMAP_USB2_PHY is not set -+CONFIG_PHY_MTK_TPHY=y -+ -+# -+# Rockchip PHY driver -+# -+# CONFIG_PHY_CADENCE_SIERRA is not set -+# CONFIG_PHY_CADENCE_TORRENT is not set -+# CONFIG_MSM8916_USB_PHY is not set -+# CONFIG_MVEBU_COMPHY_SUPPORT is not set -+ -+# -+# Pin controllers -+# -+CONFIG_PINCTRL=y -+CONFIG_PINCTRL_FULL=y -+CONFIG_PINCTRL_GENERIC=y -+CONFIG_PINMUX=y -+CONFIG_PINCONF=y -+CONFIG_PINCONF_RECURSIVE=y -+# CONFIG_PINCTRL_AT91 is not set -+# CONFIG_PINCTRL_AT91PIO4 is not set -+# CONFIG_PINCTRL_INTEL is not set -+# CONFIG_PINCTRL_QE is not set -+# CONFIG_PINCTRL_ROCKCHIP_RV1108 is not set -+# CONFIG_PINCTRL_SINGLE is not set -+# CONFIG_PINCTRL_STM32 is not set -+# CONFIG_PINCTRL_STMFX is not set -+# CONFIG_PINCTRL_K210 is not set -+CONFIG_PINCTRL_MTK=y -+# CONFIG_PINCTRL_MT7622 is not set -+# CONFIG_PINCTRL_MT7623 is not set -+# CONFIG_PINCTRL_MT7629 is not set -+CONFIG_PINCTRL_MT7981=y -+# CONFIG_PINCTRL_MT7986 is not set -+# CONFIG_PINCTRL_MT7988 is not set -+# CONFIG_PINCTRL_MT8512 is not set -+# CONFIG_PINCTRL_MT8516 is not set -+# CONFIG_PINCTRL_MT8518 is not set -+CONFIG_POWER=y -+# CONFIG_POWER_LEGACY is not set -+# CONFIG_ACPI_PMC is not set -+ -+# -+# Power Domain Support -+# -+CONFIG_POWER_DOMAIN=y -+# CONFIG_APPLE_PMGR_POWER_DOMAIN is not set -+CONFIG_MTK_POWER_DOMAIN=y -+# CONFIG_DM_PMIC is not set -+# CONFIG_PMIC_TPS65217 is not set -+# CONFIG_POWER_TPS65218 is not set -+# CONFIG_POWER_TPS62362 is not set -+# CONFIG_DM_REGULATOR is not set -+# CONFIG_TPS6586X_POWER is not set -+# CONFIG_POWER_MT6323 is not set -+CONFIG_DM_PWM=y -+# CONFIG_PWM_ASPEED is not set -+# CONFIG_PWM_CADENCE_TTC is not set -+# CONFIG_PWM_CROS_EC is not set -+# CONFIG_PWM_EXYNOS is not set -+# CONFIG_PWM_IMX is not set -+# CONFIG_PWM_MESON is not set -+CONFIG_PWM_MTK=y -+# CONFIG_PWM_ROCKCHIP is not set -+# CONFIG_PWM_SANDBOX is not set -+# CONFIG_PWM_SIFIVE is not set -+# CONFIG_PWM_TEGRA is not set -+# CONFIG_PWM_SUNXI is not set -+# CONFIG_U_QE is not set -+# CONFIG_RAM is not set -+ -+# -+# Reboot Mode Support -+# -+# CONFIG_DM_REBOOT_MODE is not set -+ -+# -+# Remote Processor drivers -+# -+ -+# -+# Reset Controller Support -+# -+# CONFIG_RESET_AST2500 is not set -+# CONFIG_RESET_AST2600 is not set -+CONFIG_RESET_MEDIATEK=y -+# CONFIG_RESET_HISILICON is not set -+# CONFIG_RESET_SYSCON is not set -+# CONFIG_RESET_SCMI is not set -+# CONFIG_RESET_DRA7 is not set -+# CONFIG_DM_RNG is not set -+ -+# -+# Real Time Clock -+# -+# CONFIG_DM_RTC is not set -+# CONFIG_RTC_ENABLE_32KHZ_OUTPUT is not set -+# CONFIG_RTC_DS1337 is not set -+# CONFIG_RTC_DS1338 is not set -+# CONFIG_RTC_DS1374 is not set -+# CONFIG_RTC_DS3231 is not set -+# CONFIG_RTC_PCF8563 is not set -+# CONFIG_RTC_PT7C4338 is not set -+# CONFIG_RTC_PL031 is not set -+# CONFIG_RTC_S35392A is not set -+# CONFIG_RTC_MC13XXX is not set -+# CONFIG_RTC_MC146818 is not set -+# CONFIG_RTC_M41T62 is not set -+# CONFIG_SCSI is not set -+# CONFIG_DM_SCSI is not set -+CONFIG_SERIAL=y -+CONFIG_BAUDRATE=115200 -+# CONFIG_DEFAULT_ENV_IS_RW is not set -+CONFIG_REQUIRE_SERIAL_CONSOLE=y -+# CONFIG_SPECIFY_CONSOLE_INDEX is not set -+CONFIG_SERIAL_PRESENT=y -+CONFIG_DM_SERIAL=y -+# CONFIG_SERIAL_RX_BUFFER is not set -+# CONFIG_SERIAL_PUTS is not set -+# CONFIG_SERIAL_SEARCH_ALL is not set -+# CONFIG_SERIAL_PROBE_ALL is not set -+# CONFIG_VPL_DM_SERIAL is not set -+CONFIG_DEBUG_UART_MTK=y -+CONFIG_DEBUG_UART_SHIFT=0 -+# CONFIG_DEBUG_UART_ANNOUNCE is not set -+# CONFIG_DEBUG_UART_SKIP_INIT is not set -+# CONFIG_ALTERA_JTAG_UART is not set -+# CONFIG_ALTERA_UART is not set -+# CONFIG_ARC_SERIAL is not set -+# CONFIG_ARM_DCC is not set -+# CONFIG_ATMEL_USART is not set -+# CONFIG_BCM6345_SERIAL is not set -+# CONFIG_COREBOOT_SERIAL is not set -+# CONFIG_CORTINA_UART is not set -+# CONFIG_FSL_LINFLEXUART is not set -+# CONFIG_FSL_LPUART is not set -+# CONFIG_MVEBU_A3700_UART is not set -+# CONFIG_MCFUART is not set -+# CONFIG_NULLDEV_SERIAL is not set -+# CONFIG_SYS_NS16550 is not set -+# CONFIG_PL01X_SERIAL is not set -+# CONFIG_ROCKCHIP_SERIAL is not set -+# CONFIG_XILINX_UARTLITE is not set -+# CONFIG_MSM_SERIAL is not set -+# CONFIG_MSM_GENI_SERIAL is not set -+# CONFIG_MXS_AUART_SERIAL is not set -+# CONFIG_OMAP_SERIAL is not set -+# CONFIG_SIFIVE_SERIAL is not set -+# CONFIG_ZYNQ_SERIAL is not set -+CONFIG_MTK_SERIAL=y -+# CONFIG_MT7620_SERIAL is not set -+# CONFIG_NPCM_SERIAL is not set -+# CONFIG_SM is not set -+# CONFIG_MESON_SM is not set -+# CONFIG_SMEM is not set -+ -+# -+# Sound support -+# -+# CONFIG_SOUND is not set -+ -+# -+# SOC (System On Chip) specific Drivers -+# -+# CONFIG_SOC_DEVICE is not set -+# CONFIG_SOC_TI is not set -+CONFIG_SPI=y -+CONFIG_DM_SPI=y -+CONFIG_SPI_MEM=y -+# CONFIG_SPI_DIRMAP is not set -+# CONFIG_ALTERA_SPI is not set -+# CONFIG_APPLE_SPI is not set -+# CONFIG_ATCSPI200_SPI is not set -+# CONFIG_ATMEL_SPI is not set -+# CONFIG_BCMSTB_SPI is not set -+# CONFIG_CORTINA_SFLASH is not set -+# CONFIG_CADENCE_QSPI is not set -+# CONFIG_CF_SPI is not set -+# CONFIG_DESIGNWARE_SPI is not set -+# CONFIG_EXYNOS_SPI is not set -+# CONFIG_FSL_DSPI is not set -+# CONFIG_FSL_QSPI is not set -+# CONFIG_GXP_SPI is not set -+# CONFIG_ICH_SPI is not set -+# CONFIG_IPROC_QSPI is not set -+# CONFIG_KIRKWOOD_SPI is not set -+# CONFIG_MICROCHIP_COREQSPI is not set -+# CONFIG_MPC8XXX_SPI is not set -+# CONFIG_MTK_SNOR is not set -+# CONFIG_MTK_SNFI_SPI is not set -+CONFIG_MTK_SPIM=y -+# CONFIG_MVEBU_A3700_SPI is not set -+# CONFIG_MXS_SPI is not set -+# CONFIG_SPI_MXIC is not set -+# CONFIG_NPCM_FIU_SPI is not set -+# CONFIG_NPCM_PSPI is not set -+# CONFIG_NXP_FSPI is not set -+# CONFIG_OMAP3_SPI is not set -+# CONFIG_PL022_SPI is not set -+# CONFIG_ROCKCHIP_SFC is not set -+# CONFIG_ROCKCHIP_SPI is not set -+# CONFIG_SPI_ASPEED_SMC is not set -+# CONFIG_SPI_SIFIVE is not set -+# CONFIG_SOFT_SPI is not set -+# CONFIG_SPI_SN_F_OSPI is not set -+# CONFIG_SPI_SUNXI is not set -+# CONFIG_TEGRA114_SPI is not set -+# CONFIG_TEGRA20_SFLASH is not set -+# CONFIG_TEGRA20_SLINK is not set -+# CONFIG_TEGRA210_QSPI is not set -+# CONFIG_TI_QSPI is not set -+# CONFIG_XILINX_SPI is not set -+# CONFIG_ZYNQ_SPI is not set -+# CONFIG_ZYNQ_QSPI is not set -+# CONFIG_ZYNQMP_GQSPI is not set -+# CONFIG_SH_QSPI is not set -+# CONFIG_MXC_SPI is not set -+ -+# -+# SPMI support -+# -+# CONFIG_SPMI is not set -+# CONFIG_SYSINFO is not set -+ -+# -+# System reset device drivers -+# -+# CONFIG_SYSRESET is not set -+# CONFIG_TEE is not set -+# CONFIG_DM_THERMAL is not set -+ -+# -+# Timer Support -+# -+# CONFIG_TIMER is not set -+ -+# -+# TPM support -+# -+CONFIG_USB=y -+CONFIG_DM_USB=y -+# CONFIG_DM_USB_GADGET is not set -+ -+# -+# USB Host Controller Drivers -+# -+CONFIG_USB_HOST=y -+CONFIG_USB_XHCI_HCD=y -+# CONFIG_USB_XHCI_DWC3 is not set -+# CONFIG_USB_XHCI_DWC3_OF_SIMPLE is not set -+CONFIG_USB_XHCI_MTK=y -+# CONFIG_USB_XHCI_FSL is not set -+# CONFIG_USB_XHCI_BRCM is not set -+# CONFIG_USB_EHCI_HCD is not set -+# CONFIG_USB_OHCI_HCD is not set -+# CONFIG_USB_UHCI_HCD is not set -+# CONFIG_USB_DWC2 is not set -+# CONFIG_USB_R8A66597_HCD is not set -+# CONFIG_USB_ISP1760 is not set -+# CONFIG_USB_CDNS3 is not set -+# CONFIG_USB_DWC3 is not set -+# CONFIG_USB_MTU3 is not set -+ -+# -+# Legacy MUSB Support -+# -+# CONFIG_USB_MUSB_HCD is not set -+# CONFIG_USB_MUSB_UDC is not set -+ -+# -+# MUSB Controller Driver -+# -+# CONFIG_USB_MUSB_HOST is not set -+# CONFIG_USB_MUSB_PIO_ONLY is not set -+ -+# -+# USB Phy -+# -+# CONFIG_TWL4030_USB is not set -+# CONFIG_ROCKCHIP_USB2_PHY is not set -+ -+# -+# ULPI drivers -+# -+ -+# -+# USB peripherals -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_KEYBOARD is not set -+# CONFIG_USB_ONBOARD_HUB is not set -+CONFIG_USB_HUB_DEBOUNCE_TIMEOUT=1000 -+# CONFIG_USB_HOST_ETHER is not set -+# CONFIG_USB_GADGET is not set -+# CONFIG_SPL_USB_GADGET is not set -+ -+# -+# UFS Host Controller Support -+# -+# CONFIG_TI_J721E_UFS is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VIDEO is not set -+ -+# -+# VirtIO Drivers -+# -+# CONFIG_VIRTIO_MMIO is not set -+ -+# -+# 1-Wire support -+# -+# CONFIG_W1 is not set -+ -+# -+# 1-wire EEPROM support -+# -+# CONFIG_W1_EEPROM is not set -+ -+# -+# Watchdog Timer Support -+# -+# CONFIG_WATCHDOG is not set -+CONFIG_WATCHDOG_TIMEOUT_MSECS=60000 -+# CONFIG_IMX_WATCHDOG is not set -+# CONFIG_ULP_WATCHDOG is not set -+# CONFIG_WDT is not set -+# CONFIG_PHYS_TO_BUS is not set -+ -+# -+# File systems -+# -+# CONFIG_FS_BTRFS is not set -+# CONFIG_FS_CBFS is not set -+# CONFIG_FS_EXT4 is not set -+CONFIG_FS_FAT=y -+CONFIG_FAT_WRITE=y -+CONFIG_FS_FAT_MAX_CLUSTSIZE=65536 -+# CONFIG_FS_JFFS2 is not set -+CONFIG_UBIFS_SILENCE_MSG=y -+CONFIG_UBIFS_SILENCE_DEBUG_DUMP=y -+# CONFIG_FS_CRAMFS is not set -+# CONFIG_YAFFS2 is not set -+# CONFIG_FS_SQUASHFS is not set -+# CONFIG_FS_EROFS is not set -+ -+# -+# Library routines -+# -+# CONFIG_ADDR_MAP is not set -+# CONFIG_SYS_TIMER_COUNTS_DOWN is not set -+# CONFIG_PHYSMEM is not set -+# CONFIG_BCH is not set -+# CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED is not set -+CONFIG_CHARSET=y -+# CONFIG_DYNAMIC_CRC_TABLE is not set -+CONFIG_LIB_UUID=y -+# CONFIG_SEMIHOSTING is not set -+CONFIG_PRINTF=y -+CONFIG_SPRINTF=y -+CONFIG_STRTO=y -+CONFIG_SYS_HZ=1000 -+# CONFIG_PANIC_HANG is not set -+CONFIG_REGEX=y -+CONFIG_LIB_RAND=y -+# CONFIG_LIB_HW_RAND is not set -+CONFIG_SUPPORT_ACPI=y -+# CONFIG_ACPI is not set -+CONFIG_RBTREE=y -+# CONFIG_BITREVERSE is not set -+# CONFIG_TRACE is not set -+# CONFIG_CIRCBUF is not set -+# CONFIG_CMD_DHRYSTONE is not set -+ -+# -+# Security support -+# -+# CONFIG_AES is not set -+# CONFIG_ECDSA is not set -+# CONFIG_RSA is not set -+# CONFIG_TPM is not set -+ -+# -+# Android Verified Boot -+# -+ -+# -+# Hashing Support -+# -+# CONFIG_BLAKE2 is not set -+CONFIG_SHA1=y -+CONFIG_SHA256=y -+# CONFIG_SHA512 is not set -+# CONFIG_SHA384 is not set -+# CONFIG_SHA_HW_ACCEL is not set -+CONFIG_MD5=y -+CONFIG_CRC8=y -+CONFIG_CRC32=y -+ -+# -+# Compression Support -+# -+# CONFIG_LZ4 is not set -+CONFIG_LZMA=y -+CONFIG_LZO=y -+CONFIG_GZIP=y -+# CONFIG_ZLIB_UNCOMPRESS is not set -+# CONFIG_BZIP2 is not set -+CONFIG_ZLIB=y -+# CONFIG_ZSTD is not set -+CONFIG_VPL_LZMA=y -+# CONFIG_SPL_GZIP is not set -+# CONFIG_ERRNO_STR is not set -+CONFIG_HEXDUMP=y -+# CONFIG_GETOPT is not set -+CONFIG_OF_LIBFDT=y -+CONFIG_OF_LIBFDT_ASSUME_MASK=0x0 -+CONFIG_SYS_FDT_PAD=0x3000 -+ -+# -+# System tables -+# -+CONFIG_GENERATE_SMBIOS_TABLE=y -+# CONFIG_LIB_RATIONAL is not set -+CONFIG_SMBIOS=y -+# CONFIG_SMBIOS_PARSER is not set -+CONFIG_EFI_LOADER=y -+CONFIG_CMD_BOOTEFI_BOOTMGR=y -+CONFIG_EFI_VARIABLE_FILE_STORE=y -+# CONFIG_EFI_VARIABLE_NO_STORE is not set -+# CONFIG_EFI_VARIABLES_PRESEED is not set -+CONFIG_EFI_VAR_BUF_SIZE=131072 -+# CONFIG_EFI_SCROLL_ON_CLEAR_SCREEN is not set -+# CONFIG_EFI_RUNTIME_UPDATE_CAPSULE is not set -+CONFIG_EFI_CAPSULE_MAX=15 -+CONFIG_EFI_DEVICE_PATH_TO_TEXT=y -+CONFIG_EFI_DEVICE_PATH_UTIL=y -+CONFIG_EFI_DT_FIXUP=y -+CONFIG_EFI_LOADER_HII=y -+CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2=y -+CONFIG_EFI_UNICODE_CAPITALIZATION=y -+# CONFIG_EFI_LOADER_BOUNCE_BUFFER is not set -+CONFIG_EFI_PLATFORM_LANG_CODES="en-US" -+CONFIG_EFI_HAVE_RUNTIME_RESET=y -+CONFIG_EFI_LOAD_FILE2_INITRD=y -+CONFIG_EFI_ECPT=y -+CONFIG_EFI_EBBR_2_1_CONFORMANCE=y -+# CONFIG_OPTEE_LIB is not set -+# CONFIG_OPTEE_IMAGE is not set -+# CONFIG_BOOTM_OPTEE is not set -+# CONFIG_TEST_FDTDEC is not set -+CONFIG_LIB_ELF=y -+CONFIG_LMB=y -+CONFIG_LMB_USE_MAX_REGIONS=y -+CONFIG_LMB_MAX_REGIONS=64 -+# CONFIG_PHANDLE_CHECK_SEQ is not set -+ -+# -+# Testing -+# -+# CONFIG_UNIT_TEST is not set -+# CONFIG_POST is not set -+ -+# -+# Tools options -+# -+CONFIG_MKIMAGE_DTC_PATH="dtc" -+CONFIG_TOOLS_CRC32=y -+CONFIG_TOOLS_LIBCRYPTO=y -+CONFIG_TOOLS_FIT=y -+CONFIG_TOOLS_FIT_FULL_CHECK=y -+CONFIG_TOOLS_FIT_PRINT=y -+CONFIG_TOOLS_FIT_RSASSA_PSS=y -+CONFIG_TOOLS_FIT_SIGNATURE=y -+CONFIG_TOOLS_FIT_SIGNATURE_MAX_SIZE=0x10000000 -+CONFIG_TOOLS_FIT_VERBOSE=y -+CONFIG_TOOLS_MD5=y -+CONFIG_TOOLS_OF_LIBFDT=y -+CONFIG_TOOLS_SHA1=y -+CONFIG_TOOLS_SHA256=y -+CONFIG_TOOLS_SHA384=y -+CONFIG_TOOLS_SHA512=y -+# CONFIG_TOOLS_MKEFICAPSULE is not set -+# CONFIG_FSPI_CONF_HEADER is not set -+# CONFIG_TOOLS_MKFWUMDATA is not set ---- /dev/null -+++ b/openwrt-one-nor_env -@@ -0,0 +1,46 @@ -+bl2_mtd_write=mtd erase bl2-nor && mtd write bl2-nor $loadaddr 0x0 0x40000 -+bl2_tftp_write=tftpboot $loadaddr $bootfile_bl2_nor && run bl2_mtd_write -+bootcmd=run check_button ; run led_start ; mtd read recovery ${loadaddr} ; bootm ; run led_loop_error -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-openwrt_one-initramfs.itb -+bootfile_bl2_nor=openwrt-mediatek-filogic-openwrt_one-nor-preloader.bin -+bootfile_fip_nor=openwrt-mediatek-filogic-openwrt_one-nor-bl31-uboot.fip -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run bootcmd -+bootmenu_1=Boot system via TFTP.=run tftp_boot ; run bootmenu_confirm_return -+bootmenu_2=Unlock NOR. (Make sure the NOR/WP jumper is populated)=sf probe 1:0 && sf protect unlock 0x0 0x1000000 ; run bootmenu_confirm_return -+bootmenu_3=Load BL31+U-Boot FIP via TFTP then write to NOR.=run fip_tftp_write ; run bootmenu_confirm_return -+bootmenu_4=Load BL2 preloader via TFTP then write to NOR.=run bl2_tftp_write ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NOR.=run tftp_write ; run bootmenu_confirm_return -+bootmenu_6=Lock NOR. (Remove jumper afterwards)=sf probe 1:0 && sf protect lock 0x0 0x1000000 ; run bootmenu_confirm_return -+bootmenu_7=Reboot.=reset -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) [SPI-NOR] -+check_button=if button front ; then run usb_recovery ; run led_loop_error ; fi -+fip_mtd_write=mtd erase fip-nor && mtd write fip-nor $loadaddr -+fip_tftp_write=tftpboot $loadaddr $bootfile_fip_nor && run fip_mtd_write -+ipaddr=192.168.11.11 -+led_done=led green off ; led white on -+led_loop_done=led white off ; led green on ; echo done ; while true ; do sleep 1 ; done -+led_loop_error=led white off ; led green off ; while true ; do led red on ; sleep 1 ; led red off ; sleep 1 ; done -+led_boot=led green on ; led white on ; led red on -+led_start=led green off ; led red off; led white on -+loadaddr=0x46000000 -+preboot=run led_boot -+recoverfile_bl2=openwrt-mediatek-filogic-openwrt_one-snand-preloader.bin -+recoverfile_ubi=openwrt-mediatek-filogic-openwrt_one-factory.ubi -+recovery_write_bl2=mtd erase bl2 && for offset in 0x0 0x40000 0x80000; do mtd write bl2 $loadaddr $offset 0x40000 ; done -+recovery_write_ubi=mtd erase ubi && mtd write ubi $loadaddr 0 ${filesize} -+serverip=192.168.11.23 -+tftp_boot=run led_start ; tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+tftp_write=run led_start ; tftpboot $loadaddr $bootfile && mtd erase recovery 0x0 ${filesize} && mtd write recovery $loadaddr 0x0 ${filesize} -+usb_recovery=run led_start ; usb start && run usb_recovery_bl2 && run usb_recovery_ubi && run led_loop_done -+usb_recovery_bl2=fatload usb 0:1 ${loadaddr} ${recoverfile_bl2} && run recovery_write_bl2 -+usb_recovery_ubi=fatload usb 0:1 ${loadaddr} ${recoverfile_ubi} && run recovery_write_ubi -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; bootmenu -+_init_env=setenv _init_env ; echo Initialize Env ; run ubi_create_env ; saveenv -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title ---- /dev/null -+++ b/openwrt-one-spi-nand_env -@@ -0,0 +1,59 @@ -+ipaddr=192.168.11.11 -+serverip=192.168.11.23 -+loadaddr=0x46000000 -+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0 -+bootcmd=run check_buttons ; run led_start ; run boot_calibration ; run boot_production ; run boot_recovery -+bootconf=config-1 -+bootdelay=0 -+bootfile=openwrt-mediatek-filogic-openwrt_one-initramfs.itb -+bootfile_bl2=openwrt-mediatek-filogic-openwrt_one-snand-preloader.bin -+bootfile_fip=openwrt-mediatek-filogic-openwrt_one-snand-bl31-uboot.fip -+bootfile_upg=openwrt-mediatek-filogic-openwrt_one-squashfs-sysupgrade.itb -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; run led_boot ; bootmenu 60 -+bootmenu_default=0 -+bootmenu_delay=0 -+bootmenu_title= ( ( ( OpenWrt ) ) ) [SPI-NAND] -+bootmenu_0=Initialize environment.=run _firstboot -+bootmenu_0d=Run default boot command.=run boot_default -+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=Load production system via TFTP then write to NAND.=noboot=1 ; replacevol=1 ; run boot_tftp_production ; noboot= ; replacevol= ; run bootmenu_confirm_return -+bootmenu_5=Load recovery system via TFTP then write to NAND.=noboot=1 ; replacevol=1 ; run boot_tftp_recovery ; noboot= ; replacevol= ; run bootmenu_confirm_return -+bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return -+bootmenu_8=Reboot.=reset -+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset -+boot_default=run bootcmd ; run boot_recovery ; replacevol=1 ; run boot_tftp_forever -+boot_calibration=ubi read $loadaddr calibration && bootm $loadaddr#$bootconf -+boot_production=led white on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led white off -+boot_recovery=led green on ; run ubi_read_recovery && bootm $loadaddr#$bootconf ; led green off -+boot_tftp=run led_start ; tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_forever=led green off ; led white off ; led red on ; while true ; do run boot_tftp_recovery ; led red off ; sleep 1 ; done -+boot_tftp_production=tftpboot $loadaddr $bootfile_upg && test $replacevol = 1 && iminfo $loadaddr && run ubi_write_production ; if test $noboot = 1 ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp_recovery=tftpboot $loadaddr $bootfile && test $replacevol = 1 && iminfo $loadaddr && run ubi_write_recovery ; if test $noboot = 1 ; then else bootm $loadaddr#$bootconf ; fi -+boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf -+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run ubi_write_fip && run reset_factory -+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run snand_write_bl2 -+check_buttons=if button front ; then run boot_recovery ; run boot_tftp ; run led_loop_error ; else if button back ; then ; run usb_recover ; run led_loop_error ; fi ; fi -+led_boot=led green on ; led white on ; led red on -+led_done=led green on ; led white off ; led red off -+led_loop_error=led white off ; led green off ; while true ; do led red on ; sleep 1 ; led red off ; sleep 1 ; done -+led_start=led white on ; led green off ; led red off -+preboot=run led_boot -+reset_factory=mw $loadaddr 0xff 0x1f000 ; ubi write $loadaddr ubootenv 0x1f000 ; ubi write $loadaddr ubootenv2 0x1f000 ; ubi remove rootfs_data -+snand_write_bl2=mtd erase bl2 && for offset in 0x0 0x40000 0x80000 0xc0000 ; do mtd write bl2 $loadaddr $offset 0x40000 ; done -+ubi_create_env=ubi check ubootenv || ubi create ubootenv 0x1f000 dynamic ; ubi check ubootenv2 || ubi create ubootenv2 0x1f000 dynamic -+ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi -+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs -+ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery -+ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data -+usb_recover=run led_start ; usb start && run usb_recover_production && run led_loop_done -+usb_recover_production=fatload usb 0:1 ${loadaddr} ${bootfile_upg} && iminfo $loadaddr && run ubi_write_production -+ubi_write_fip=run ubi_remove_rootfs ; ubi check fip && ubi remove fip ; ubi create fip $filesize static && ubi write $loadaddr fip $filesize -+ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic && ubi write $loadaddr fit $filesize -+ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic && ubi write $loadaddr recovery $filesize -+_init_env=setenv _init_env ; run ubi_create_env ; saveenv ; saveenv -+_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; bootmenu -+_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title -+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/lede/package/kernel/cryptodev-linux/Makefile b/lede/package/kernel/cryptodev-linux/Makefile index 0b794a3cd9..d04aaeacec 100644 --- a/lede/package/kernel/cryptodev-linux/Makefile +++ b/lede/package/kernel/cryptodev-linux/Makefile @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=cryptodev-linux PKG_VERSION:=1.13 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE_URL:=https://codeload.github.com/$(PKG_NAME)/$(PKG_NAME)/tar.gz/$(PKG_NAME)-$(PKG_VERSION)? PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz diff --git a/lede/package/kernel/cryptodev-linux/patches/0005-fix-build-for-linux-5.10.220+.patch b/lede/package/kernel/cryptodev-linux/patches/0005-fix-build-for-linux-5.10.220+.patch new file mode 100644 index 0000000000..3d25653177 --- /dev/null +++ b/lede/package/kernel/cryptodev-linux/patches/0005-fix-build-for-linux-5.10.220+.patch @@ -0,0 +1,11 @@ +--- a/ioctl.c ++++ b/ioctl.c +@@ -933,7 +933,7 @@ + if (unlikely(ret)) { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) + sys_close(fd); +-#elif (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 220)) + ksys_close(fd); + #else + close_fd(fd); diff --git a/lede/package/system/fstools/Makefile b/lede/package/system/fstools/Makefile index 7277741928..a61d4bb5a0 100644 --- a/lede/package/system/fstools/Makefile +++ b/lede/package/system/fstools/Makefile @@ -12,16 +12,15 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/fstools.git -PKG_MIRROR_HASH:=cf9e09885954e0e43b58126ce4b6f5552462cf1495b89330ce4e66056249787e -PKG_SOURCE_DATE:=2024-01-22 -PKG_SOURCE_VERSION:=08cd7083cac4bddf88459efa0881ee52858e7d0a +PKG_MIRROR_HASH:=edda9151c73c1adfe369f5e315347344727a540ad57d3e2b41b9f57f9d4313fe +PKG_SOURCE_DATE:=2023-01-22 +PKG_SOURCE_VERSION:=1ea5855e980cd88766dd9f615e78e7dd6edfbb74 CMAKE_INSTALL:=1 PKG_LICENSE:=GPL-2.0 PKG_LICENSE_FILES:= PKG_USE_MIPS16:=0 -PKG_BUILD_FLAGS:=no-mips16 PKG_FLAGS:=nonshared PKG_BUILD_DEPENDS := util-linux @@ -49,7 +48,7 @@ define Package/fstools/config depends on PACKAGE_fstools depends on NAND_SUPPORT bool "Support extroot functionality with UBIFS" - default y + default n help This option makes it possible to use extroot functionality if the root filesystem resides on an UBIFS partition @@ -83,7 +82,7 @@ define Package/block-mount SECTION:=base CATEGORY:=Base system TITLE:=Block device mounting and checking - DEPENDS:=+ubox +libubox +libuci +libblobmsg-json +libjson-c + DEPENDS:=+fstools +ubox +libubox +libuci +libblobmsg-json +libjson-c endef define Package/blockd diff --git a/lede/package/system/fstools/patches/0001-fstools-support-extroot-for-non-MTD-rootfs_data.patch b/lede/package/system/fstools/patches/0001-fstools-support-extroot-for-non-MTD-rootfs_data.patch new file mode 100644 index 0000000000..20a68484d3 --- /dev/null +++ b/lede/package/system/fstools/patches/0001-fstools-support-extroot-for-non-MTD-rootfs_data.patch @@ -0,0 +1,129 @@ +From: Qi Liu + +In order to support extroot, block extroot command has to be able to +discover and properly mount the rootfs_data volume in order to discover +the extroot volume. Currently this process can only discover MTD devices. +This patch leverages libfstools in a similar way as mount_root to +discover, initialize, and mount rootfs_data volume. It would enable any +device with non-MTD rootfs_data volume to support extroot, including x86. + +Signed-off-by: Qi Liu +--- + CMakeLists.txt | 4 ++-- + block.c | 40 ++++++++++++++++++++++++++++++++++++++++ + libfstools/fstype.h | 12 ++++++++++++ + libfstools/libfstools.h | 11 +---------- + 4 files changed, 55 insertions(+), 12 deletions(-) + create mode 100644 libfstools/fstype.h + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -78,9 +78,9 @@ INSTALL(TARGETS blockd RUNTIME DESTINATI + ADD_EXECUTABLE(block block.c probe.c probe-libblkid.c) + IF(DEFINED CMAKE_UBIFS_EXTROOT) + ADD_DEFINITIONS(-DUBIFS_EXTROOT) +- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json}) ++ TARGET_LINK_LIBRARIES(block fstools blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json}) + ELSE(DEFINED CMAKE_UBIFS_EXTROOT) +- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ${json}) ++ TARGET_LINK_LIBRARIES(block fstools blkid-tiny dl uci ubox ubus blobmsg_json ${json}) + ENDIF(DEFINED CMAKE_UBIFS_EXTROOT) + INSTALL(TARGETS block RUNTIME DESTINATION sbin) + +--- a/block.c ++++ b/block.c +@@ -44,6 +44,8 @@ + #include + #include + ++#include "libfstools/fstype.h" ++#include "libfstools/volume.h" + #include "probe.h" + + #define AUTOFS_MOUNT_PATH "/tmp/run/blockd/" +@@ -1696,6 +1698,44 @@ static int main_extroot(int argc, char * + } + #endif + ++ /* Find volume using libfstools */ ++ struct volume *data = volume_find("rootfs_data"); ++ if (data) { ++ volume_init(data); ++ ++ switch (volume_identify(data)) { ++ case FS_EXT4: { ++ char cfg[] = "/tmp/ext4_cfg"; ++ ++ /* Mount volume and try extroot (using fstab from that vol) */ ++ mkdir_p(cfg, 0755); ++ if (!mount(data->blk, cfg, "ext4", MS_NOATIME, NULL)) { ++ err = mount_extroot(cfg); ++ umount2(cfg, MNT_DETACH); ++ } ++ if (err < 0) ++ rmdir("/tmp/overlay"); ++ rmdir(cfg); ++ return err; ++ } ++ ++ case FS_F2FS: { ++ char cfg[] = "/tmp/f2fs_cfg"; ++ ++ /* Mount volume and try extroot (using fstab from that vol) */ ++ mkdir_p(cfg, 0755); ++ if (!mount(data->blk, cfg, "f2fs", MS_NOATIME, NULL)) { ++ err = mount_extroot(cfg); ++ umount2(cfg, MNT_DETACH); ++ } ++ if (err < 0) ++ rmdir("/tmp/overlay"); ++ rmdir(cfg); ++ return err; ++ } ++ } ++ } ++ + /* As a last resort look for /etc/config/fstab on "rootfs" partition */ + return mount_extroot(NULL); + } +--- /dev/null ++++ b/libfstools/fstype.h +@@ -0,0 +1,13 @@ ++#ifndef _FS_TYPE_H__ ++#define _FS_TYPE_H__ ++enum { ++ FS_NONE, ++ FS_SNAPSHOT, ++ FS_JFFS2, ++ FS_DEADCODE, ++ FS_UBIFS, ++ FS_F2FS, ++ FS_EXT4, ++ FS_TARGZ, ++}; ++#endif +\ No newline at end of file +--- a/libfstools/libfstools.h ++++ b/libfstools/libfstools.h +@@ -18,20 +18,10 @@ + #include + #include + #include ++#include "fstype.h" + + struct volume; + +-enum { +- FS_NONE, +- FS_SNAPSHOT, +- FS_JFFS2, +- FS_DEADCODE, +- FS_UBIFS, +- FS_F2FS, +- FS_EXT4, +- FS_TARGZ, +-}; +- + enum fs_state { + FS_STATE_UNKNOWN, + FS_STATE_PENDING, diff --git a/lede/package/utils/fitblk/Makefile b/lede/package/utils/fitblk/Makefile index 4da4dc46f1..cb9e7ebb40 100644 --- a/lede/package/utils/fitblk/Makefile +++ b/lede/package/utils/fitblk/Makefile @@ -16,7 +16,7 @@ define Package/fitblk SECTION:=base CATEGORY:=Base system TITLE:=fitblk firmware release tool - DEPENDS:=@!LINUX_5_15 + DEPENDS:=@LINUX_6_1 endef define Package/fitblk/description diff --git a/lede/target/linux/generic/config-5.15 b/lede/target/linux/generic/config-5.15 index 7daac70a4d..cd2f3f7f70 100644 --- a/lede/target/linux/generic/config-5.15 +++ b/lede/target/linux/generic/config-5.15 @@ -2050,7 +2050,6 @@ CONFIG_FILE_LOCKING=y # CONFIG_FIRMWARE_EDID is not set # CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_FIRMWARE_MEMMAP is not set -# CONFIG_FIT_PARTITION is not set # CONFIG_FIXED_PHY is not set CONFIG_FLATMEM=y CONFIG_FLATMEM_MANUAL=y diff --git a/lede/target/linux/generic/config-6.1 b/lede/target/linux/generic/config-6.1 index 50740c4d40..33bceba08c 100644 --- a/lede/target/linux/generic/config-6.1 +++ b/lede/target/linux/generic/config-6.1 @@ -2167,7 +2167,6 @@ CONFIG_FILE_LOCKING=y # CONFIG_FIRMWARE_EDID is not set # CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_FIRMWARE_MEMMAP is not set -# CONFIG_FIT_PARTITION is not set # CONFIG_FIXED_PHY is not set CONFIG_FLATMEM=y CONFIG_FLATMEM_MANUAL=y diff --git a/lede/target/linux/generic/config-6.6 b/lede/target/linux/generic/config-6.6 index 20fe98099f..6ae27dbadd 100644 --- a/lede/target/linux/generic/config-6.6 +++ b/lede/target/linux/generic/config-6.6 @@ -1,11 +1,13 @@ # CONFIG_104_QUAD_8 is not set CONFIG_32BIT=y +CONFIG_64BIT_TIME=y # CONFIG_6LOWPAN is not set # CONFIG_6LOWPAN_DEBUGFS is not set # CONFIG_6PACK is not set # CONFIG_8139CP is not set # CONFIG_8139TOO is not set # CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set # CONFIG_AB8500_CORE is not set # CONFIG_ABP060MG is not set # CONFIG_ABX500_CORE is not set @@ -58,6 +60,7 @@ CONFIG_32BIT=y # CONFIG_AD7091R5 is not set # CONFIG_AD7124 is not set # CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set # CONFIG_AD7192 is not set # CONFIG_AD7266 is not set # CONFIG_AD7280 is not set @@ -91,6 +94,7 @@ CONFIG_32BIT=y # CONFIG_AD9834 is not set # CONFIG_ADA4250 is not set # CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7854 is not set # CONFIG_ADF4350 is not set # CONFIG_ADF4371 is not set # CONFIG_ADF4377 is not set @@ -157,7 +161,6 @@ CONFIG_AF_UNIX_OOB=y CONFIG_AIO=y # CONFIG_AIRO is not set # CONFIG_AIRO_CS is not set -# CONFIG_AIR_EN8811H_PHY is not set # CONFIG_AIX_PARTITION is not set # CONFIG_AK09911 is not set # CONFIG_AK8974 is not set @@ -184,7 +187,9 @@ CONFIG_ALLOW_DEV_COREDUMP=y # CONFIG_AMILO_RFKILL is not set # CONFIG_AMPERE_ERRATUM_AC03_CPU_38 is not set # CONFIG_AMT is not set +# CONFIG_ANDROID is not set # CONFIG_ANDROID_BINDER_IPC is not set +CONFIG_ANON_INODES=y # CONFIG_ANON_VMA_NAME is not set # CONFIG_APDS9300 is not set # CONFIG_APDS9802ALS is not set @@ -202,6 +207,7 @@ CONFIG_ALLOW_DEV_COREDUMP=y # CONFIG_AR8216_PHY is not set # CONFIG_AR8216_PHY_LEDS is not set # CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_AGILEX is not set # CONFIG_ARCH_AIROHA is not set # CONFIG_ARCH_ALPINE is not set # CONFIG_ARCH_APPLE is not set @@ -211,12 +217,14 @@ CONFIG_ALLOW_DEV_COREDUMP=y # CONFIG_ARCH_AXXIA is not set # CONFIG_ARCH_BCM is not set # CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM4908 is not set # CONFIG_ARCH_BCMBCA is not set # CONFIG_ARCH_BCM_21664 is not set # CONFIG_ARCH_BCM_23550 is not set # CONFIG_ARCH_BCM_281XX is not set # CONFIG_ARCH_BCM_5301X is not set # CONFIG_ARCH_BCM_53573 is not set +# CONFIG_ARCH_BCM_63XX is not set # CONFIG_ARCH_BCM_CYGNUS is not set # CONFIG_ARCH_BCM_HR2 is not set # CONFIG_ARCH_BCM_IPROC is not set @@ -226,10 +234,12 @@ CONFIG_ARCH_BINFMT_ELF_STATE=y # CONFIG_ARCH_BITMAIN is not set # CONFIG_ARCH_BRCMSTB is not set # CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_DIGICOLOR is not set # CONFIG_ARCH_DMA_ADDR_T_64BIT is not set # CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set # CONFIG_ARCH_EXYNOS is not set CONFIG_ARCH_FLATMEM_ENABLE=y @@ -242,10 +252,14 @@ CONFIG_ARCH_FORCE_MAX_ORDER=11 # CONFIG_ARCH_HPE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_INTEL_SOCFPGA is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set # CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_K3 is not set # CONFIG_ARCH_KEEMBAY is not set # CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KS8695 is not set # CONFIG_ARCH_LAYERSCAPE is not set # CONFIG_ARCH_LG1K is not set # CONFIG_ARCH_LPC32XX is not set @@ -268,6 +282,7 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARCH_MXC is not set # CONFIG_ARCH_MXS is not set # CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set # CONFIG_ARCH_NOMADIK is not set # CONFIG_ARCH_NPCM is not set # CONFIG_ARCH_NSPIRE is not set @@ -279,8 +294,12 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARCH_OMAP3 is not set # CONFIG_ARCH_OMAP4 is not set # CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_OXNAS is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PRIMA2 is not set # CONFIG_ARCH_PXA is not set # CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_RANDOM is not set # CONFIG_ARCH_RDA is not set # CONFIG_ARCH_REALTEK is not set # CONFIG_ARCH_REALVIEW is not set @@ -288,21 +307,27 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARCH_ROCKCHIP is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_S32 is not set +# CONFIG_ARCH_S3C24XX is not set # CONFIG_ARCH_S3C64XX is not set # CONFIG_ARCH_S5PV210 is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_SEATTLE is not set # CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set # CONFIG_ARCH_SPARX5 is not set # CONFIG_ARCH_SPRD is not set # CONFIG_ARCH_STI is not set # CONFIG_ARCH_STM32 is not set +# CONFIG_ARCH_STRATIX10 is not set # CONFIG_ARCH_SUNPLUS is not set # CONFIG_ARCH_SUNXI is not set # CONFIG_ARCH_SYNQUACER is not set +# CONFIG_ARCH_TANGO is not set # CONFIG_ARCH_TEGRA is not set # CONFIG_ARCH_THUNDER is not set # CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_U300 is not set # CONFIG_ARCH_U8500 is not set # CONFIG_ARCH_UNIPHIER is not set # CONFIG_ARCH_VERSATILE is not set @@ -310,11 +335,14 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARCH_VIRT is not set # CONFIG_ARCH_VISCONTI is not set # CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_VULCAN is not set +# CONFIG_ARCH_W90X900 is not set # CONFIG_ARCH_WANTS_THP_SWAP is not set # CONFIG_ARCH_WM8505 is not set # CONFIG_ARCH_WM8750 is not set # CONFIG_ARCH_WM8850 is not set # CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set # CONFIG_ARCH_ZYNQ is not set # CONFIG_ARCH_ZYNQMP is not set # CONFIG_ARCNET is not set @@ -324,6 +352,7 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARM64_64K_PAGES is not set # CONFIG_ARM64_AMU_EXTN is not set # CONFIG_ARM64_BTI is not set +# CONFIG_ARM64_CRYPTO is not set # CONFIG_ARM64_E0PD is not set # CONFIG_ARM64_ERRATUM_1024718 is not set # CONFIG_ARM64_ERRATUM_1165522 is not set @@ -356,31 +385,37 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARM64_ERRATUM_858921 is not set # CONFIG_ARM64_HW_AFDBM is not set # CONFIG_ARM64_LSE_ATOMICS is not set +CONFIG_ARM64_MODULE_PLTS=y # CONFIG_ARM64_MTE is not set # CONFIG_ARM64_PAN is not set # CONFIG_ARM64_PMEM is not set # CONFIG_ARM64_PSEUDO_NMI is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set # CONFIG_ARM64_PTR_AUTH is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set # CONFIG_ARM64_RAS_EXTN is not set # CONFIG_ARM64_RELOC_TEST is not set # CONFIG_ARM64_SME is not set # CONFIG_ARM64_SVE is not set CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_TLB_RANGE is not set +# CONFIG_ARM64_UAO is not set # CONFIG_ARM64_USE_LSE_ATOMICS is not set # CONFIG_ARM64_VA_BITS_48 is not set +# CONFIG_ARM64_VHE is not set # CONFIG_ARM_APPENDED_DTB is not set # CONFIG_ARM_ARCH_TIMER is not set # CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set # CONFIG_ARM_CCI is not set # CONFIG_ARM_CCI400_PMU is not set # CONFIG_ARM_CCI5xx_PMU is not set # CONFIG_ARM_CCI_PMU is not set # CONFIG_ARM_CCN is not set # CONFIG_ARM_CMN is not set -# CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU is not set # CONFIG_ARM_CPUIDLE is not set CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_ARM_CRYPTO is not set CONFIG_ARM_DMA_MEM_BUFFERABLE=y # CONFIG_ARM_DSU_PMU is not set # CONFIG_ARM_ERRATA_326103 is not set @@ -429,7 +464,6 @@ CONFIG_ARM_MODULE_PLTS=y # CONFIG_ARM_SDE_INTERFACE is not set # CONFIG_ARM_SMCCC_SOC_ID is not set # CONFIG_ARM_SMC_WATCHDOG is not set -# CONFIG_ARM_SMMU_V3_PMU is not set # CONFIG_ARM_SP805_WATCHDOG is not set # CONFIG_ARM_SPE_PMU is not set # CONFIG_ARM_THUMBEE is not set @@ -482,6 +516,7 @@ CONFIG_ATA_SFF=y # CONFIG_ATMEL is not set # CONFIG_ATMEL_PIT is not set # CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set # CONFIG_ATM_BR2684 is not set CONFIG_ATM_BR2684_IPFILTER=y # CONFIG_ATM_CLIP is not set @@ -489,8 +524,10 @@ CONFIG_ATM_CLIP_NO_ICMP=y # CONFIG_ATM_DRIVERS is not set # CONFIG_ATM_DUMMY is not set # CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set # CONFIG_ATM_FORE200E is not set # CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set # CONFIG_ATM_IA is not set # CONFIG_ATM_IDT77252 is not set # CONFIG_ATM_LANAI is not set @@ -499,10 +536,13 @@ CONFIG_ATM_CLIP_NO_ICMP=y # CONFIG_ATM_NICSTAR is not set # CONFIG_ATM_SOLOS is not set # CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set # CONFIG_ATOMIC64_SELFTEST is not set # CONFIG_ATP is not set # CONFIG_AUDIT is not set # CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AURORA_NB8800 is not set +# CONFIG_AUTOFS4_FS is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTO_ZRELADDR is not set # CONFIG_AUXDISPLAY is not set @@ -529,17 +569,21 @@ CONFIG_ATM_CLIP_NO_ICMP=y # CONFIG_BACKLIGHT_ARCXCNN is not set # CONFIG_BACKLIGHT_BD6107 is not set # CONFIG_BACKLIGHT_CLASS_DEVICE is not set +# CONFIG_BACKLIGHT_GENERIC is not set # CONFIG_BACKLIGHT_GPIO is not set # CONFIG_BACKLIGHT_KTD253 is not set # CONFIG_BACKLIGHT_KTZ8866 is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # CONFIG_BACKLIGHT_LED is not set # CONFIG_BACKLIGHT_LM3630A is not set # CONFIG_BACKLIGHT_LM3639 is not set # CONFIG_BACKLIGHT_LP855X is not set # CONFIG_BACKLIGHT_LV5207LP is not set # CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKLIGHT_PM8941_WLED is not set # CONFIG_BACKLIGHT_PWM is not set # CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_RPI is not set # CONFIG_BACKLIGHT_SAHARA is not set # CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_BACKTRACE_VERBOSE is not set @@ -569,6 +613,7 @@ CONFIG_BASE_SMALL=0 # CONFIG_BAYCOM_SER_FDX is not set # CONFIG_BAYCOM_SER_HDX is not set # CONFIG_BCACHE is not set +# CONFIG_BCM2712_MIP is not set # CONFIG_BCM47XX is not set # CONFIG_BCM54140_PHY is not set # CONFIG_BCM63XX is not set @@ -598,6 +643,7 @@ CONFIG_BCMA_POSSIBLE=y # CONFIG_BIG_KEYS is not set # CONFIG_BIG_LITTLE is not set CONFIG_BINARY_PRINTF=y +# CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_ELF_FDPIC is not set # CONFIG_BINFMT_FLAT is not set @@ -607,35 +653,92 @@ CONFIG_BITREVERSE=y # CONFIG_BLK_CGROUP_IOCOST is not set # CONFIG_BLK_CGROUP_IOLATENCY is not set # CONFIG_BLK_CGROUP_IOPRIO is not set +# CONFIG_BLK_CMDLINE_PARSER is not set # CONFIG_BLK_DEBUG_FS is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set # CONFIG_BLK_DEV_BSG is not set # CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set # CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set # CONFIG_BLK_DEV_DM is not set # CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set # CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_INTEGRITY is not set # CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_LOOP is not set CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_NULL_BLK is not set # CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PLATFORM is not set # CONFIG_BLK_DEV_PMEM is not set +# CONFIG_BLK_DEV_QD65XX is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set # CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set # CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_UBLK is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_BLK_DEV_ZONED is not set # CONFIG_BLK_INLINE_ENCRYPTION is not set -# CONFIG_BLOCK_NOTIFIERS is not set +# CONFIG_BLK_NVMEM is not set # CONFIG_BLK_SED_OPAL is not set # CONFIG_BLK_WBT is not set CONFIG_BLOCK=y @@ -761,6 +864,7 @@ CONFIG_BT_HCIUART_H4=y # CONFIG_BT_HCIUART_RTL is not set # CONFIG_BT_HCIVHCI is not set # CONFIG_BT_HIDP is not set +# CONFIG_BT_HS is not set # CONFIG_BT_LE is not set # CONFIG_BT_LEDS is not set CONFIG_BT_LE_L2CAP_ECRED=y @@ -775,7 +879,9 @@ CONFIG_BT_RFCOMM_TTY=y # CONFIG_BT_VIRTIO is not set CONFIG_BUG=y # CONFIG_BUG_ON_DATA_CORRUPTION is not set +CONFIG_BUILDTIME_EXTABLE_SORT=y CONFIG_BUILDTIME_TABLE_SORT=y +# CONFIG_BUILD_BIN2C is not set CONFIG_BUILD_SALT="" # CONFIG_C2PORT is not set # CONFIG_CACHESTAT_SYSCALL is not set @@ -812,8 +918,12 @@ CONFIG_CACHE_L2X0_PMU=y # CONFIG_CAN_UCAN is not set # CONFIG_CAN_VCAN is not set # CONFIG_CAN_VXCAN is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set # CONFIG_CAPI_TRACE is not set CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set # CONFIG_CARL9170 is not set # CONFIG_CASSINI is not set # CONFIG_CAVIUM_CPT is not set @@ -856,6 +966,7 @@ CONFIG_CFG80211_HEADERS=y # CONFIG_CHARGER_ISP1704 is not set # CONFIG_CHARGER_LP8727 is not set # CONFIG_CHARGER_LT3651 is not set +# CONFIG_CHARGER_LTC3651 is not set # CONFIG_CHARGER_LTC4162L is not set # CONFIG_CHARGER_MANAGER is not set # CONFIG_CHARGER_MAX77976 is not set @@ -869,27 +980,35 @@ CONFIG_CFG80211_HEADERS=y # CONFIG_CHARGER_SMB347 is not set # CONFIG_CHARGER_TWL4030 is not set # CONFIG_CHARGER_UCS1002 is not set +# CONFIG_CHASH_SELFTEST is not set +# CONFIG_CHASH_STATS is not set # CONFIG_CHECKPOINT_RESTORE is not set # CONFIG_CHELSIO_T1 is not set # CONFIG_CHELSIO_T3 is not set # CONFIG_CHELSIO_T4 is not set # CONFIG_CHELSIO_T4VF is not set # CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set # CONFIG_CHR_DEV_SCH is not set # CONFIG_CHR_DEV_SG is not set # CONFIG_CHR_DEV_ST is not set # CONFIG_CICADA_PHY is not set # CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y # CONFIG_CIFS_DEBUG is not set # CONFIG_CIFS_DEBUG2 is not set # CONFIG_CIFS_FSCACHE is not set # CONFIG_CIFS_NFSD_EXPORT is not set CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +# CONFIG_CIFS_STATS is not set # CONFIG_CIFS_STATS2 is not set # CONFIG_CIFS_SWN_UPCALL is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set CONFIG_CIFS_XATTR=y # CONFIG_CIO_DAC is not set +# CONFIG_CLEANCACHE is not set # CONFIG_CLKSRC_PISTACHIO is not set # CONFIG_CLKSRC_VERSATILE is not set # CONFIG_CLK_GFM_LPASS_SM8250 is not set @@ -897,6 +1016,7 @@ CONFIG_CIFS_XATTR=y # CONFIG_CLK_ICST is not set # CONFIG_CLK_QORIQ is not set # CONFIG_CLK_SP810 is not set +# CONFIG_CLOCK_THERMAL is not set CONFIG_CLS_U32_MARK=y # CONFIG_CLS_U32_PERF is not set # CONFIG_CM32181 is not set @@ -939,6 +1059,8 @@ CONFIG_CMDLINE="" # CONFIG_COMMON_CLK_PWM is not set # CONFIG_COMMON_CLK_PXA is not set # CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_RP1 is not set +# CONFIG_COMMON_CLK_RP1_SDIO is not set # CONFIG_COMMON_CLK_RS9_PCIE is not set # CONFIG_COMMON_CLK_SI514 is not set # CONFIG_COMMON_CLK_SI521XX is not set @@ -982,6 +1104,7 @@ CONFIG_CONSTRUCTORS=y # CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set # CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_STAT_DETAILS is not set # CONFIG_CPU_FREQ_THERMAL is not set # CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set # CONFIG_CPU_ICACHE_DISABLE is not set @@ -1015,7 +1138,7 @@ CONFIG_CRC32_SARWATE=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC_ITU_T is not set # CONFIG_CRC_T10DIF is not set -# CONFIG_CROS_HPS_I2C is not set +CONFIG_CROSS_COMPILE="" # CONFIG_CROSS_MEMORY_ATTACH is not set CONFIG_CRYPTO=y # CONFIG_CRYPTO_842 is not set @@ -1024,8 +1147,13 @@ CONFIG_CRYPTO_ACOMP2=y CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_AEAD2=y # CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128L is not set +# CONFIG_CRYPTO_AEGIS128L_AESNI_SSE2 is not set # CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +# CONFIG_CRYPTO_AEGIS256 is not set +# CONFIG_CRYPTO_AEGIS256_AESNI_SSE2 is not set CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set # CONFIG_CRYPTO_AES_ARM is not set # CONFIG_CRYPTO_AES_ARM64 is not set # CONFIG_CRYPTO_AES_ARM64_BS is not set @@ -1091,14 +1219,14 @@ CONFIG_CRYPTO_CTR=y # CONFIG_CRYPTO_DEV_CCREE is not set # CONFIG_CRYPTO_DEV_FSL_CAAM is not set # CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is not set -# CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG is not set -# CONFIG_CRYPTO_DEV_FSL_CAAM_INTC is not set -# CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST is not set # CONFIG_CRYPTO_DEV_HIFN_795X is not set # CONFIG_CRYPTO_DEV_HISI_SEC is not set # CONFIG_CRYPTO_DEV_HISI_ZIP is not set # CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set # CONFIG_CRYPTO_DEV_MARVELL_CESA is not set +# CONFIG_CRYPTO_DEV_MEDIATEK is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_MXC_SCC is not set # CONFIG_CRYPTO_DEV_MXS_DCP is not set # CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set # CONFIG_CRYPTO_DEV_OCTEONTX_CPT is not set @@ -1129,6 +1257,7 @@ CONFIG_CRYPTO_CTR=y # CONFIG_CRYPTO_FCRYPT is not set # CONFIG_CRYPTO_FIPS is not set CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_GF128MUL=y CONFIG_CRYPTO_GHASH=y # CONFIG_CRYPTO_GHASH_ARM64_CE is not set # CONFIG_CRYPTO_GHASH_ARM_CE is not set @@ -1159,14 +1288,22 @@ CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9 CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_MANAGER2=y CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set # CONFIG_CRYPTO_MD4 is not set # CONFIG_CRYPTO_MD5 is not set # CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_MORUS1280 is not set +# CONFIG_CRYPTO_MORUS1280_AVX2 is not set +# CONFIG_CRYPTO_MORUS1280_SSE2 is not set +# CONFIG_CRYPTO_MORUS640 is not set +# CONFIG_CRYPTO_MORUS640_SSE2 is not set # CONFIG_CRYPTO_NHPOLY1305_NEON is not set CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_NULL2=y # CONFIG_CRYPTO_OFB is not set # CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set CONFIG_CRYPTO_PCRYPT=y # CONFIG_CRYPTO_POLY1305 is not set # CONFIG_CRYPTO_POLY1305_ARM is not set @@ -1211,6 +1348,7 @@ CONFIG_CRYPTO_SKCIPHER2=y # CONFIG_CRYPTO_SM4_ARM64_CE_GCM is not set # CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set # CONFIG_CRYPTO_SM4_GENERIC is not set +# CONFIG_CRYPTO_SPECK is not set # CONFIG_CRYPTO_STATS is not set # CONFIG_CRYPTO_STREEBOG is not set # CONFIG_CRYPTO_TEA is not set @@ -1230,6 +1368,7 @@ CONFIG_CRYPTO_SKCIPHER2=y # CONFIG_CRYPTO_XCBC is not set # CONFIG_CRYPTO_XTS is not set # CONFIG_CRYPTO_XXHASH is not set +# CONFIG_CRYPTO_ZLIB is not set # CONFIG_CRYPTO_ZSTD is not set # CONFIG_CS5535_MFGPT is not set # CONFIG_CS89x0 is not set @@ -1238,8 +1377,12 @@ CONFIG_CRYPTO_SKCIPHER2=y # CONFIG_CUSE is not set # CONFIG_CW1200 is not set # CONFIG_CXD2880_SPI_DRV is not set +# CONFIG_CXL_AFU_DRIVER_OPS is not set # CONFIG_CXL_BASE is not set # CONFIG_CXL_BUS is not set +# CONFIG_CXL_EEH is not set +# CONFIG_CXL_KERNEL_API is not set +# CONFIG_CXL_LIB is not set # CONFIG_CYPRESS_FIRMWARE is not set # CONFIG_DA280 is not set # CONFIG_DA311 is not set @@ -1250,11 +1393,14 @@ CONFIG_CRYPTO_SKCIPHER2=y # CONFIG_DDR is not set # CONFIG_DEBUG_ALIGN_RODATA is not set # CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_DEBUG_CGROUP_REF is not set +# CONFIG_DEBUG_CREDENTIALS is not set # CONFIG_DEBUG_DEVRES is not set # CONFIG_DEBUG_DRIVER is not set # CONFIG_DEBUG_EFI is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set # CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set # CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set CONFIG_DEBUG_FS=y @@ -1294,12 +1440,14 @@ CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_MUTEXES is not set # CONFIG_DEBUG_NET is not set # CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set # CONFIG_DEBUG_OBJECTS is not set # CONFIG_DEBUG_PAGEALLOC is not set # CONFIG_DEBUG_PAGE_REF is not set # CONFIG_DEBUG_PERF_USE_VMALLOC is not set # CONFIG_DEBUG_PER_CPU_MAPS is not set # CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PI_LIST is not set # CONFIG_DEBUG_PLIST is not set # CONFIG_DEBUG_PREEMPT is not set # CONFIG_DEBUG_RODATA_TEST is not set @@ -1314,10 +1462,12 @@ CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_STACKOVERFLOW is not set # CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set # CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set # CONFIG_DEBUG_TIMEKEEPING is not set # CONFIG_DEBUG_UART_8250_PALMCHIP is not set # CONFIG_DEBUG_UART_8250_WORD is not set +# CONFIG_DEBUG_UART_BCM63XX is not set # CONFIG_DEBUG_UART_FLOW_CONTROL is not set # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_VIRTUAL is not set @@ -1326,12 +1476,15 @@ CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_VM_PGFLAGS is not set # CONFIG_DEBUG_VM_PGTABLE is not set # CONFIG_DEBUG_VM_RB is not set +# CONFIG_DEBUG_VM_VMACACHE is not set # CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set # CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set # CONFIG_DEBUG_WX is not set # CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set # CONFIG_DEFAULT_CODEL is not set CONFIG_DEFAULT_CUBIC=y +CONFIG_DEFAULT_DEADLINE=y # CONFIG_DEFAULT_FQ is not set CONFIG_DEFAULT_FQ_CODEL=y # CONFIG_DEFAULT_FQ_PIE is not set @@ -1340,12 +1493,15 @@ CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 CONFIG_DEFAULT_INIT="" CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 CONFIG_DEFAULT_NET_SCH="fq_codel" +# CONFIG_DEFAULT_NOOP is not set # CONFIG_DEFAULT_PFIFO_FAST is not set # CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" CONFIG_DEFAULT_SECURITY_DAC=y # CONFIG_DEFAULT_SECURITY_SELINUX is not set # CONFIG_DEFAULT_SFQ is not set CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set # CONFIG_DELL_LAPTOP is not set # CONFIG_DELL_RBTN is not set @@ -1353,13 +1509,27 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_DELL_SMO8800 is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set # CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set # CONFIG_DEVMEM is not set CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_DEVTMPFS is not set # CONFIG_DEVTMPFS_MOUNT is not set # CONFIG_DEVTMPFS_SAFE is not set # CONFIG_DEV_DAX is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set # CONFIG_DHT11 is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set # CONFIG_DL2K is not set # CONFIG_DLHL60D is not set # CONFIG_DLM is not set @@ -1376,6 +1546,7 @@ CONFIG_DEVPORT=y # CONFIG_DMARD06 is not set # CONFIG_DMARD09 is not set # CONFIG_DMARD10 is not set +# CONFIG_DMASCC is not set # CONFIG_DMATEST is not set # CONFIG_DMA_API_DEBUG is not set CONFIG_DMA_COHERENT_POOL=y @@ -1385,8 +1556,11 @@ CONFIG_DMA_DECLARE_COHERENT=y # CONFIG_DMA_JZ4780 is not set # CONFIG_DMA_MAP_BENCHMARK is not set CONFIG_DMA_NONCOHERENT_MMAP=y +# CONFIG_DMA_NOOP_OPS is not set +# CONFIG_DMA_PERNUMA_CMA is not set # CONFIG_DMA_RESTRICTED_POOL is not set # CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DMA_VIRT_OPS is not set # CONFIG_DM_CACHE is not set # CONFIG_DM_CLONE is not set # CONFIG_DM_DEBUG is not set @@ -1398,6 +1572,7 @@ CONFIG_DMA_NONCOHERENT_MMAP=y # CONFIG_DM_INTEGRITY is not set # CONFIG_DM_LOG_USERSPACE is not set # CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_MQ_DEFAULT is not set # CONFIG_DM_MULTIPATH is not set # CONFIG_DM_RAID is not set # CONFIG_DM_SWITCH is not set @@ -1411,6 +1586,7 @@ CONFIG_DMA_NONCOHERENT_MMAP=y # CONFIG_DNET is not set # CONFIG_DNOTIFY is not set # CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y # CONFIG_DP83640_PHY is not set # CONFIG_DP83822_PHY is not set # CONFIG_DP83848_PHY is not set @@ -1427,10 +1603,14 @@ CONFIG_DQL=y # CONFIG_DRM_ACCEL is not set # CONFIG_DRM_AMDGPU is not set # CONFIG_DRM_AMDGPU_CIK is not set +# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set # CONFIG_DRM_AMDGPU_SI is not set # CONFIG_DRM_AMDGPU_USERPTR is not set # CONFIG_DRM_AMDGPU_WERROR is not set # CONFIG_DRM_AMD_ACP is not set +# CONFIG_DRM_AMD_DC_DCN2_0 is not set +# CONFIG_DRM_AMD_DC_DCN3_0 is not set +# CONFIG_DRM_AMD_DC_HDCP is not set # CONFIG_DRM_AMD_DC_SI is not set # CONFIG_DRM_AMD_SECURE_DISPLAY is not set # CONFIG_DRM_ANALOGIX_ANX6345 is not set @@ -1449,9 +1629,11 @@ CONFIG_DQL=y # CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set # CONFIG_DRM_DEBUG_MM is not set # CONFIG_DRM_DEBUG_MODESET_LOCK is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set # CONFIG_DRM_DISPLAY_CONNECTOR is not set # CONFIG_DRM_DP_AUX_CHARDEV is not set # CONFIG_DRM_DP_CEC is not set +# CONFIG_DRM_DUMB_VGA_DAC is not set # CONFIG_DRM_DW_HDMI_CEC is not set # CONFIG_DRM_ETNAVIV is not set # CONFIG_DRM_EXYNOS is not set @@ -1485,6 +1667,7 @@ CONFIG_DQL=y # CONFIG_DRM_LONTIUM_LT9611UXC is not set # CONFIG_DRM_LOONGSON is not set # CONFIG_DRM_LVDS_CODEC is not set +# CONFIG_DRM_LVDS_ENCODER is not set # CONFIG_DRM_MALI_DISPLAY is not set # CONFIG_DRM_MCDE is not set # CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set @@ -1510,6 +1693,7 @@ CONFIG_DQL=y # CONFIG_DRM_PANEL_HIMAX_HX8394 is not set # CONFIG_DRM_PANEL_ILITEK_IL9322 is not set # CONFIG_DRM_PANEL_ILITEK_ILI9341 is not set +# CONFIG_DRM_PANEL_ILITEK_ILI9806E is not set # CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set # CONFIG_DRM_PANEL_INNOLUX_EJ030NA is not set # CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set @@ -1543,6 +1727,7 @@ CONFIG_DQL=y # CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set # CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set # CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set +# CONFIG_DRM_PANEL_ROCKTECH_JH057N00900 is not set # CONFIG_DRM_PANEL_RONBO_RB070D30 is not set # CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20 is not set # CONFIG_DRM_PANEL_SAMSUNG_DB7430 is not set @@ -1565,6 +1750,7 @@ CONFIG_DQL=y # CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set # CONFIG_DRM_PANEL_SITRONIX_ST7703 is not set # CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PANEL_SONY_ACX424AKP is not set # CONFIG_DRM_PANEL_SONY_ACX565AKM is not set # CONFIG_DRM_PANEL_SONY_TD4353_JDI is not set # CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521 is not set @@ -1573,10 +1759,12 @@ CONFIG_DQL=y # CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set # CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set # CONFIG_DRM_PANEL_TPO_TPG110 is not set +# CONFIG_DRM_PANEL_TPO_Y17P is not set # CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set # CONFIG_DRM_PANEL_VISIONOX_R66451 is not set # CONFIG_DRM_PANEL_VISIONOX_RM69299 is not set # CONFIG_DRM_PANEL_VISIONOX_VTDR6130 is not set +# CONFIG_DRM_PANEL_WAVESHARE_TOUCHSCREEN is not set # CONFIG_DRM_PANEL_WIDECHIPS_WS2401 is not set # CONFIG_DRM_PANEL_XINPENG_XPP055C272 is not set # CONFIG_DRM_PANFROST is not set @@ -1591,6 +1779,9 @@ CONFIG_DQL=y # CONFIG_DRM_RCAR_USE_LVDS is not set # CONFIG_DRM_RCAR_USE_MIPI_DSI is not set # CONFIG_DRM_ROCKCHIP is not set +# CONFIG_DRM_RP1_DPI is not set +# CONFIG_DRM_RP1_DSI is not set +# CONFIG_DRM_RP1_VEC is not set # CONFIG_DRM_SAMSUNG_DSIM is not set # CONFIG_DRM_SII902X is not set # CONFIG_DRM_SII9234 is not set @@ -1604,6 +1795,7 @@ CONFIG_DQL=y # CONFIG_DRM_THINE_THC63LVD1024 is not set # CONFIG_DRM_TIDSS is not set # CONFIG_DRM_TILCDC is not set +# CONFIG_DRM_TINYDRM is not set # CONFIG_DRM_TI_DLPC3433 is not set # CONFIG_DRM_TI_SN65DSI83 is not set # CONFIG_DRM_TI_SN65DSI86 is not set @@ -1818,7 +2010,9 @@ CONFIG_EFI_PARTITION=y CONFIG_ELFCORE=y # CONFIG_ELF_CORE is not set # CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y # CONFIG_EM_TIMER_STI is not set +CONFIG_ENABLE_WARN_DEPRECATED=y # CONFIG_ENA_ETHERNET is not set # CONFIG_ENC28J60 is not set # CONFIG_ENCLOSURE_SERVICES is not set @@ -1846,12 +2040,14 @@ CONFIG_EXPORTFS=y CONFIG_EXT2_FS_XATTR=y # CONFIG_EXT3_FS is not set # CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_ENCRYPTION is not set # CONFIG_EXT4_FS is not set # CONFIG_EXT4_FS_POSIX_ACL is not set # CONFIG_EXT4_FS_SECURITY is not set CONFIG_EXT4_USE_FOR_EXT2=y # CONFIG_EXTCON is not set # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set # CONFIG_EXTCON_AXP288 is not set # CONFIG_EXTCON_FSA9480 is not set # CONFIG_EXTCON_GPIO is not set @@ -1866,16 +2062,19 @@ CONFIG_EXT4_USE_FOR_EXT2=y CONFIG_EXTRA_FIRMWARE="" CONFIG_EXTRA_TARGETS="" # CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set # CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set # CONFIG_EZX_PCAP is not set # CONFIG_F2FS_CHECK_FS is not set # CONFIG_F2FS_FAULT_INJECTION is not set # CONFIG_F2FS_FS is not set # CONFIG_F2FS_FS_COMPRESSION is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set # CONFIG_F2FS_FS_POSIX_ACL is not set # CONFIG_F2FS_FS_SECURITY is not set CONFIG_F2FS_FS_XATTR=y # CONFIG_F2FS_IOSTAT is not set +# CONFIG_F2FS_IO_TRACE is not set CONFIG_F2FS_STAT_FS=y # CONFIG_F2FS_UNFAIR_RWSEM is not set # CONFIG_FAILOVER is not set @@ -1896,8 +2095,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_FB_ATMEL is not set # CONFIG_FB_ATY is not set # CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set # CONFIG_FB_BACKLIGHT is not set # CONFIG_FB_BIG_ENDIAN is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set # CONFIG_FB_BOTH_ENDIAN is not set # CONFIG_FB_BROADSHEET is not set # CONFIG_FB_CARMINE is not set @@ -1910,6 +2111,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_FB_DA8XX is not set # CONFIG_FB_DDC is not set # CONFIG_FB_DEVICE is not set +# CONFIG_FB_FLEX is not set # CONFIG_FB_FOREIGN_ENDIAN is not set # CONFIG_FB_FSL_DIU is not set # CONFIG_FB_GEODE is not set @@ -1927,6 +2129,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_FB_MB862XX is not set # CONFIG_FB_METRONOME is not set # CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_MXS is not set # CONFIG_FB_N411 is not set # CONFIG_FB_NEOMAGIC is not set CONFIG_FB_NOTIFY=y @@ -1940,6 +2143,7 @@ CONFIG_FB_NOTIFY=y # CONFIG_FB_PXA is not set # CONFIG_FB_RADEON is not set # CONFIG_FB_RIVA is not set +# CONFIG_FB_RPISENSE is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_S3 is not set # CONFIG_FB_SAVAGE is not set @@ -1957,6 +2161,7 @@ CONFIG_FB_NOTIFY=y # CONFIG_FB_TFT is not set # CONFIG_FB_TFT_AGM1264K_FL is not set # CONFIG_FB_TFT_BD663474 is not set +# CONFIG_FB_TFT_FBTFT_DEVICE is not set # CONFIG_FB_TFT_HX8340BN is not set # CONFIG_FB_TFT_HX8347D is not set # CONFIG_FB_TFT_HX8353D is not set @@ -1977,6 +2182,7 @@ CONFIG_FB_NOTIFY=y # CONFIG_FB_TFT_SSD1289 is not set # CONFIG_FB_TFT_SSD1305 is not set # CONFIG_FB_TFT_SSD1306 is not set +# CONFIG_FB_TFT_SSD1325 is not set # CONFIG_FB_TFT_SSD1331 is not set # CONFIG_FB_TFT_SSD1351 is not set # CONFIG_FB_TFT_ST7735R is not set @@ -1986,7 +2192,9 @@ CONFIG_FB_NOTIFY=y # CONFIG_FB_TFT_UC1611 is not set # CONFIG_FB_TFT_UC1701 is not set # CONFIG_FB_TFT_UPD161704 is not set +# CONFIG_FB_TFT_WATTEROTT is not set # CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set # CONFIG_FB_TRIDENT is not set # CONFIG_FB_UDL is not set # CONFIG_FB_UVESA is not set @@ -1995,10 +2203,12 @@ CONFIG_FB_NOTIFY=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_VOODOO1 is not set # CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set # CONFIG_FCOE is not set # CONFIG_FCOE_FNIC is not set # CONFIG_FDDI is not set # CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set # CONFIG_FHANDLE is not set CONFIG_FIB_RULES=y # CONFIG_FIELDBUS_DEV is not set @@ -2006,12 +2216,16 @@ CONFIG_FILE_LOCKING=y # CONFIG_FIND_BIT_BENCHMARK is not set # CONFIG_FIREWIRE is not set # CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set # CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_FIRMWARE_MEMMAP is not set # CONFIG_FIXED_PHY is not set CONFIG_FLATMEM=y CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_FM10K is not set +# CONFIG_FMC is not set # CONFIG_FONTS is not set # CONFIG_FONT_6x8 is not set # CONFIG_FONT_TER16x32 is not set @@ -2025,6 +2239,7 @@ CONFIG_FORTIFY_SOURCE=y # CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set # CONFIG_FRAME_POINTER is not set # CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set # CONFIG_FSCACHE is not set # CONFIG_FSI is not set # CONFIG_FSL_DPAA2_SWITCH is not set @@ -2084,6 +2299,7 @@ CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_GACT_PROB=y # CONFIG_GADGET_UAC1 is not set # CONFIG_GAMEPORT is not set +# CONFIG_GATEWORKS_GW16083 is not set # CONFIG_GCC_PLUGINS is not set # CONFIG_GCOV is not set # CONFIG_GCOV_KERNEL is not set @@ -2104,6 +2320,9 @@ CONFIG_GENERIC_VDSO_TIME_NS=y # CONFIG_GENEVE is not set # CONFIG_GENWQE is not set # CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_DUMMYLL is not set # CONFIG_GLOB_SELFTEST is not set # CONFIG_GNSS is not set # CONFIG_GOLDFISH is not set @@ -2123,6 +2342,7 @@ CONFIG_GPIOLIB_FASTPATH_LIMIT=512 # CONFIG_GPIO_74X164 is not set # CONFIG_GPIO_74XX_MMIO is not set # CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set # CONFIG_GPIO_AGGREGATOR is not set # CONFIG_GPIO_ALTERA is not set # CONFIG_GPIO_AMD8111 is not set @@ -2153,6 +2373,7 @@ CONFIG_GPIOLIB_FASTPATH_LIMIT=512 # CONFIG_GPIO_IT87 is not set # CONFIG_GPIO_LATCH is not set # CONFIG_GPIO_LOGICVC is not set +# CONFIG_GPIO_LYNXPOINT is not set # CONFIG_GPIO_MAX3191X is not set # CONFIG_GPIO_MAX7300 is not set # CONFIG_GPIO_MAX7301 is not set @@ -2171,6 +2392,7 @@ CONFIG_GPIOLIB_FASTPATH_LIMIT=512 # CONFIG_GPIO_PCI_IDIO_16 is not set # CONFIG_GPIO_PISOSR is not set # CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_PWM is not set # CONFIG_GPIO_RCAR is not set # CONFIG_GPIO_RDC321X is not set # CONFIG_GPIO_SAMA5D2_PIOBU is not set @@ -2178,6 +2400,7 @@ CONFIG_GPIOLIB_FASTPATH_LIMIT=512 # CONFIG_GPIO_SCH311X is not set # CONFIG_GPIO_SIFIVE is not set # CONFIG_GPIO_SIM is not set +# CONFIG_GPIO_SX150X is not set # CONFIG_GPIO_SYSCON is not set CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_TPIC2810 is not set @@ -2192,17 +2415,24 @@ CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_XILINX is not set # CONFIG_GPIO_XRA1403 is not set # CONFIG_GPIO_ZEVIO is not set +# CONFIG_GPIO_ZX is not set # CONFIG_GP_PCI1XXXX is not set # CONFIG_GREENASIA_FF is not set # CONFIG_GREYBUS is not set +# CONFIG_GS_FPGABOOT is not set # CONFIG_GTP is not set +# CONFIG_GUP_BENCHMARK is not set # CONFIG_GUP_TEST is not set # CONFIG_GVE is not set +# CONFIG_HABANA_AI is not set # CONFIG_HAMACHI is not set # CONFIG_HAMRADIO is not set # CONFIG_HAPPYMEAL is not set CONFIG_HARDENED_USERCOPY=y +# CONFIG_HARDENED_USERCOPY_FALLBACK is not set +# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set CONFIG_HARDEN_BRANCH_HISTORY=y +CONFIG_HARDEN_EL2_VECTORS=y # CONFIG_HARDLOCKUP_DETECTOR is not set # CONFIG_HAVE_ARM_ARCH_TIMER is not set # CONFIG_HCALL_STATS is not set @@ -2216,10 +2446,14 @@ CONFIG_HARDEN_BRANCH_HISTORY=y # CONFIG_HDLC_RAW_ETH is not set # CONFIG_HDMI_LPE_AUDIO is not set # CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set # CONFIG_HEADERS_INSTALL is not set +# CONFIG_HEADER_TEST is not set # CONFIG_HERMES is not set # CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set # CONFIG_HFS_FS is not set +# CONFIG_HFS_FS_POSIX_ACL is not set # CONFIG_HI6421V600_IRQ is not set # CONFIG_HI8435 is not set # CONFIG_HIBERNATION is not set @@ -2366,15 +2600,19 @@ CONFIG_HIGH_RES_TIMERS=y # CONFIG_HOTPLUG_CPU is not set # CONFIG_HOTPLUG_PCI is not set # CONFIG_HP03 is not set +# CONFIG_HP100 is not set # CONFIG_HP206C is not set CONFIG_HPET_MMAP_DEFAULT=y # CONFIG_HPFS_FS is not set # CONFIG_HP_ILO is not set # CONFIG_HP_WATCHDOG is not set +# CONFIG_HP_WIRELESS is not set # CONFIG_HSA_AMD is not set # CONFIG_HSI is not set # CONFIG_HSR is not set # CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set # CONFIG_HTE is not set # CONFIG_HTS221 is not set # CONFIG_HTU21 is not set @@ -2414,6 +2652,8 @@ CONFIG_HW_RANDOM_TPM=y # CONFIG_HW_RANDOM_XIPHERA is not set # CONFIG_HX711 is not set # CONFIG_HYPERV is not set +# CONFIG_HYPERV_TSCPAGE is not set +# CONFIG_HYSDN is not set CONFIG_HZ=100 CONFIG_HZ_100=y # CONFIG_HZ_1000 is not set @@ -2490,6 +2730,7 @@ CONFIG_HZ_100=y # CONFIG_I2C_OCORES is not set # CONFIG_I2C_OCTEON is not set # CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PCA_ISA is not set # CONFIG_I2C_PCA_PLATFORM is not set # CONFIG_I2C_PCI1XXXX is not set @@ -2538,7 +2779,12 @@ CONFIG_HZ_100=y # CONFIG_ICP10100 is not set # CONFIG_ICPLUS_PHY is not set # CONFIG_ICS932S401 is not set +# CONFIG_ICST is not set +# CONFIG_IDE is not set # CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set # CONFIG_IDLE_PAGE_TRACKING is not set # CONFIG_IEEE802154 is not set # CONFIG_IEEE802154_ADF7242 is not set @@ -2555,6 +2801,7 @@ CONFIG_HZ_100=y # CONFIG_IIO_BUFFER_CB is not set # CONFIG_IIO_BUFFER_DMA is not set # CONFIG_IIO_BUFFER_DMAENGINE is not set +# CONFIG_IIO_BUFFER_HDC2010 is not set # CONFIG_IIO_BUFFER_HW_CONSUMER is not set # CONFIG_IIO_CONFIGFS is not set CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 @@ -2563,6 +2810,7 @@ CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 # CONFIG_IIO_KX022A_I2C is not set # CONFIG_IIO_KX022A_SPI is not set # CONFIG_IIO_MUX is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set # CONFIG_IIO_RESCALE is not set # CONFIG_IIO_SIMPLE_DUMMY is not set # CONFIG_IIO_SSP_SENSORHUB is not set @@ -2581,11 +2829,11 @@ CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 # CONFIG_IKCONFIG_PROC is not set # CONFIG_IKHEADERS is not set # CONFIG_IMA is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set # CONFIG_IMGPDC_WDT is not set # CONFIG_IMG_MDC_DMA is not set # CONFIG_IMX7D_ADC is not set # CONFIG_IMX8QXP_ADC is not set -# CONFIG_IMX93_ADC is not set # CONFIG_IMX_IPUV3_CORE is not set # CONFIG_IMX_THERMAL is not set # CONFIG_INA2XX_ADC is not set @@ -2602,6 +2850,7 @@ CONFIG_INET=y # CONFIG_INET_ESP is not set # CONFIG_INET_ESPINTCP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set CONFIG_INET_TABLE_PERTURB_ORDER=16 # CONFIG_INET_TCP_DIAG is not set # CONFIG_INET_TUNNEL is not set @@ -2650,9 +2899,11 @@ CONFIG_INOTIFY_USER=y # CONFIG_INPUT_EVBUG is not set # CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set # CONFIG_INPUT_GPIO_BEEPER is not set # CONFIG_INPUT_GPIO_DECODER is not set # CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set # CONFIG_INPUT_GPIO_VIBRA is not set # CONFIG_INPUT_IBM_PANEL is not set # CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set @@ -2672,14 +2923,18 @@ CONFIG_INPUT_MISC=y # CONFIG_INPUT_MMA8450 is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_MSM_VIBRATOR is not set # CONFIG_INPUT_PALMAS_PWRBUTTON is not set # CONFIG_INPUT_PCF8574 is not set # CONFIG_INPUT_PCSPKR is not set # CONFIG_INPUT_PM8941_PWRKEY is not set # CONFIG_INPUT_PM8XXX_VIBRATOR is not set +# CONFIG_INPUT_POLLDEV is not set # CONFIG_INPUT_POWERMATE is not set # CONFIG_INPUT_PWM_BEEPER is not set # CONFIG_INPUT_PWM_VIBRA is not set +# CONFIG_INPUT_RASPBERRYPI_BUTTON is not set # CONFIG_INPUT_REGULATOR_HAPTIC is not set # CONFIG_INPUT_SOC_BUTTON_ARRAY is not set # CONFIG_INPUT_SPARSEKMAP is not set @@ -2698,6 +2953,7 @@ CONFIG_INPUT_MISC=y # CONFIG_INTEGRITY_SIGNATURE is not set # CONFIG_INTEL_ATOMISP2_LED is not set # CONFIG_INTEL_ATOMISP2_PM is not set +# CONFIG_INTEL_CHT_INT33FE is not set # CONFIG_INTEL_HID_EVENT is not set # CONFIG_INTEL_IDLE is not set # CONFIG_INTEL_IDMA64 is not set @@ -2707,6 +2963,9 @@ CONFIG_INPUT_MISC=y # CONFIG_INTEL_MEI is not set # CONFIG_INTEL_MEI_ME is not set # CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set # CONFIG_INTEL_OAKTRAIL is not set # CONFIG_INTEL_PMC_CORE is not set # CONFIG_INTEL_PUNIT_IPC is not set @@ -2791,6 +3050,7 @@ CONFIG_IPW2200_MONITOR=y # CONFIG_IPW2200_QOS is not set # CONFIG_IPW2200_RADIOTAP is not set # CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set CONFIG_IP_ADVANCED_ROUTER=y # CONFIG_IP_DCCP is not set # CONFIG_IP_FIB_TRIE_STATS is not set @@ -2810,6 +3070,7 @@ CONFIG_IP_MULTIPLE_TABLES=y # CONFIG_IP_NF_MATCH_TTL is not set # CONFIG_IP_NF_RAW is not set # CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set # CONFIG_IP_NF_TARGET_ECN is not set # CONFIG_IP_NF_TARGET_MASQUERADE is not set # CONFIG_IP_NF_TARGET_NETMAP is not set @@ -2829,8 +3090,10 @@ CONFIG_IP_ROUTE_VERBOSE=y # CONFIG_IP_VS_MH is not set CONFIG_IP_VS_MH_TAB_INDEX=10 # CONFIG_IP_VS_TWOS is not set +# CONFIG_IRDA is not set # CONFIG_IRQSOFF_TRACER is not set # CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set # CONFIG_IRQ_POLL is not set # CONFIG_IRQ_TIME_ACCOUNTING is not set # CONFIG_IRSD200 is not set @@ -2842,12 +3105,14 @@ CONFIG_IP_VS_MH_TAB_INDEX=10 # CONFIG_IR_IMON is not set # CONFIG_IR_IMON_RAW is not set # CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set # CONFIG_IR_MCEUSB is not set # CONFIG_IR_NEC_DECODER is not set # CONFIG_IR_RC5_DECODER is not set # CONFIG_IR_RC6_DECODER is not set # CONFIG_IR_REDRAT3 is not set # CONFIG_IR_SERIAL is not set +# CONFIG_IR_SIR is not set # CONFIG_IR_SONY_DECODER is not set # CONFIG_IR_STREAMZAP is not set # CONFIG_IR_TOY is not set @@ -2857,7 +3122,18 @@ CONFIG_IP_VS_MH_TAB_INDEX=10 # CONFIG_ISCSI_BOOT_SYSFS is not set # CONFIG_ISCSI_TCP is not set CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set # CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set # CONFIG_ISL29003 is not set # CONFIG_ISL29020 is not set # CONFIG_ISL29125 is not set @@ -2867,6 +3143,7 @@ CONFIG_ISDN=y # CONFIG_ITG3200 is not set # CONFIG_IWL3945 is not set # CONFIG_IWLWIFI is not set +# CONFIG_IXGB is not set # CONFIG_IXGBE is not set # CONFIG_IXGBEVF is not set # CONFIG_JAILHOUSE_GUEST is not set @@ -2899,6 +3176,7 @@ CONFIG_JOLIET=y # CONFIG_JSA1212 is not set # CONFIG_JUMP_LABEL is not set # CONFIG_JZ4740_WDT is not set +# CONFIG_JZ4770_PHY is not set # CONFIG_KALLSYMS is not set # CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set # CONFIG_KALLSYMS_ALL is not set @@ -2914,6 +3192,7 @@ CONFIG_KASAN_STACK=y CONFIG_KCOV_IRQ_AREA_SIZE=0x40000 # CONFIG_KCSAN is not set # CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_CAT is not set # CONFIG_KERNEL_GZIP is not set # CONFIG_KERNEL_LZ4 is not set # CONFIG_KERNEL_LZMA is not set @@ -2969,7 +3248,9 @@ CONFIG_KERNFS=y # CONFIG_KEY_DH_OPERATIONS is not set # CONFIG_KFENCE is not set # CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set # CONFIG_KMX61 is not set +# CONFIG_KPC2000 is not set # CONFIG_KPROBES is not set # CONFIG_KPROBES_SANITY_TEST is not set # CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set @@ -2996,20 +3277,25 @@ CONFIG_KUSER_HELPERS=y # CONFIG_L2TP_V3 is not set # CONFIG_LAN743X is not set # CONFIG_LAN966X_SWITCH is not set +# CONFIG_LANMEDIA is not set # CONFIG_LANTIQ is not set # CONFIG_LAPB is not set +# CONFIG_LASAT is not set # CONFIG_LATENCYTOP is not set # CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y # CONFIG_LCD_AMS369FG06 is not set # CONFIG_LCD_CLASS_DEVICE is not set # CONFIG_LCD_HX8357 is not set # CONFIG_LCD_ILI922X is not set # CONFIG_LCD_ILI9320 is not set # CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LD9040 is not set # CONFIG_LCD_LMS283GF05 is not set # CONFIG_LCD_LMS501KF03 is not set # CONFIG_LCD_LTV350QV is not set # CONFIG_LCD_OTM3225A is not set +# CONFIG_LCD_S6E63M0 is not set # CONFIG_LCD_TDO24M is not set # CONFIG_LCD_VGG2432A4 is not set CONFIG_LDISC_AUTOLOAD=y @@ -3093,6 +3379,7 @@ CONFIG_LEDS_TRIGGER_TIMER=y # CONFIG_LED_TRIGGER_PHY is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_LEGACY_TIOCSTI is not set +# CONFIG_LGUEST is not set # CONFIG_LIB80211 is not set # CONFIG_LIB80211_CRYPT_CCMP is not set # CONFIG_LIB80211_CRYPT_TKIP is not set @@ -3106,11 +3393,13 @@ CONFIG_LEDS_TRIGGER_TIMER=y # CONFIG_LIBFCOE is not set # CONFIG_LIBIPW_DEBUG is not set # CONFIG_LIBNVDIMM is not set +CONFIG_LIB_MEMNEQ=y # CONFIG_LIDAR_LITE_V2 is not set CONFIG_LINEAR_RANGES=y # CONFIG_LIQUIDIO is not set # CONFIG_LIQUIDIO_VF is not set # CONFIG_LIRC is not set +# CONFIG_LIS3L02DQ is not set # CONFIG_LIST_HARDENED is not set # CONFIG_LITEX_LITEETH is not set # CONFIG_LITEX_SOC_CONTROLLER is not set @@ -3120,6 +3409,7 @@ CONFIG_LLC=y # CONFIG_LLC2 is not set # CONFIG_LMK04832 is not set # CONFIG_LMP91000 is not set +# CONFIG_LNET is not set CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set # CONFIG_LOCKD is not set @@ -3135,6 +3425,7 @@ CONFIG_LOCKD_V4=y CONFIG_LOCK_MM_AND_FIND_VMA=y # CONFIG_LOCK_STAT is not set # CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set # CONFIG_LOGIG940_FF is not set # CONFIG_LOGIRUMBLEPAD2_FF is not set # CONFIG_LOGITECH_FF is not set @@ -3162,8 +3453,10 @@ CONFIG_LSM_MMAP_MIN_ADDR=65536 # CONFIG_LTC2983 is not set # CONFIG_LTE_GDM724X is not set CONFIG_LTO_NONE=y +# CONFIG_LTPC is not set # CONFIG_LTR501 is not set # CONFIG_LTRF216A is not set +# CONFIG_LUSTRE_FS is not set # CONFIG_LV0104CS is not set # CONFIG_LWTUNNEL is not set # CONFIG_LXT_PHY is not set @@ -3190,8 +3483,12 @@ CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 # CONFIG_MACH_LOONGSON64 is not set # CONFIG_MACH_NINTENDO64 is not set # CONFIG_MACH_PIC32 is not set +# CONFIG_MACH_PISTACHIO is not set # CONFIG_MACH_REALTEK_RTL is not set +# CONFIG_MACH_TX39XX is not set # CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACH_XILFPGA is not set # CONFIG_MACINTOSH_DRIVERS is not set # CONFIG_MACSEC is not set # CONFIG_MACVLAN is not set @@ -3205,6 +3502,7 @@ CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" # CONFIG_MAILBOX is not set # CONFIG_MANAGER_SBS is not set +# CONFIG_MANDATORY_FILE_LOCKING is not set # CONFIG_MANGLE_BOOTARGS is not set # CONFIG_MARVELL_10G_PHY is not set # CONFIG_MARVELL_88Q2XXX_PHY is not set @@ -3236,6 +3534,7 @@ CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" # CONFIG_MAXIM_THERMOCOUPLE is not set # CONFIG_MAXLINEAR_GPHY is not set CONFIG_MAX_SKB_FRAGS=17 +CONFIG_MAY_USE_DEVLINK=y # CONFIG_MB1232 is not set # CONFIG_MC3230 is not set # CONFIG_MCB is not set @@ -3266,6 +3565,7 @@ CONFIG_MAX_SKB_FRAGS=17 # CONFIG_MDIO_MVUSB is not set # CONFIG_MDIO_OCTEON is not set # CONFIG_MDIO_THUNDER is not set +# CONFIG_MDIO_XPCS is not set # CONFIG_MDM_GCC_9607 is not set # CONFIG_MD_BITMAP_FILE is not set # CONFIG_MD_FAULTY is not set @@ -3282,6 +3582,7 @@ CONFIG_MAX_SKB_FRAGS=17 # CONFIG_MEDIA_PLATFORM_DRIVERS is not set # CONFIG_MEDIA_PLATFORM_SUPPORT is not set # CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set # CONFIG_MEDIA_SDR_SUPPORT is not set # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set # CONFIG_MEDIA_SUPPORT is not set @@ -3349,6 +3650,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_ARIZONA_SPI is not set # CONFIG_MFD_AS3711 is not set # CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set # CONFIG_MFD_ATC260X_I2C is not set # CONFIG_MFD_ATMEL_FLEXCOM is not set # CONFIG_MFD_ATMEL_HLCDC is not set @@ -3358,6 +3660,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_BD9571MWV is not set # CONFIG_MFD_CORE is not set # CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_CROS_EC is not set # CONFIG_MFD_CS42L43_I2C is not set # CONFIG_MFD_CS5535 is not set # CONFIG_MFD_DA9052_I2C is not set @@ -3371,6 +3674,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_GATEWORKS_GSC is not set # CONFIG_MFD_HI6421_PMIC is not set # CONFIG_MFD_INTEL_M10_BMC_SPI is not set +# CONFIG_MFD_INTEL_PMT is not set # CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set # CONFIG_MFD_IQS62X is not set # CONFIG_MFD_JANZ_CMODIO is not set @@ -3406,39 +3710,52 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_OMAP_USB_HOST is not set # CONFIG_MFD_PALMAS is not set # CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set # CONFIG_MFD_PM8XXX is not set # CONFIG_MFD_QCOM_PM8008 is not set +# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set # CONFIG_MFD_RC5T583 is not set # CONFIG_MFD_RDC321X is not set # CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set # CONFIG_MFD_RK8XX_I2C is not set # CONFIG_MFD_RK8XX_SPI is not set # CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_ROHM_BD70528 is not set # CONFIG_MFD_ROHM_BD71828 is not set # CONFIG_MFD_ROHM_BD718XX is not set # CONFIG_MFD_ROHM_BD957XMUF is not set +# CONFIG_MFD_RP1 is not set +# CONFIG_MFD_RPISENSE_CORE is not set # CONFIG_MFD_RSMU_I2C is not set # CONFIG_MFD_RSMU_SPI is not set # CONFIG_MFD_RT4831 is not set # CONFIG_MFD_RT5033 is not set # CONFIG_MFD_RT5120 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set # CONFIG_MFD_SEC_CORE is not set # CONFIG_MFD_SI476X_CORE is not set # CONFIG_MFD_SKY81452 is not set # CONFIG_MFD_SL28CPLD is not set # CONFIG_MFD_SM501 is not set # CONFIG_MFD_SMPRO is not set +# CONFIG_MFD_SMSC is not set # CONFIG_MFD_STMFX is not set # CONFIG_MFD_STMPE is not set # CONFIG_MFD_STPMIC1 is not set # CONFIG_MFD_SY7636A is not set # CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set # CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set # CONFIG_MFD_TIMBERDALE is not set # CONFIG_MFD_TI_AM335X_TSCADC is not set # CONFIG_MFD_TI_LMU is not set # CONFIG_MFD_TI_LP873X is not set # CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TMIO is not set # CONFIG_MFD_TPS65086 is not set # CONFIG_MFD_TPS65090 is not set # CONFIG_MFD_TPS65217 is not set @@ -3451,6 +3768,8 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_TPS65912_SPI is not set # CONFIG_MFD_TPS6594_I2C is not set # CONFIG_MFD_TPS6594_SPI is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TPS80031 is not set # CONFIG_MFD_TQMX86 is not set # CONFIG_MFD_VIPERBOARD is not set # CONFIG_MFD_VX855 is not set @@ -3461,6 +3780,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_WM8350_I2C is not set # CONFIG_MFD_WM8400 is not set # CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set # CONFIG_MHI_BUS is not set # CONFIG_MHI_BUS_DEBUG is not set # CONFIG_MHI_BUS_EP is not set @@ -3470,6 +3790,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MHI_WWAN_MBIM is not set # CONFIG_MICREL_KS8995MA is not set # CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_KSZ is not set # CONFIG_MICROCHIP_PHY is not set # CONFIG_MICROCHIP_PIT64B is not set # CONFIG_MICROCHIP_T1S_PHY is not set @@ -3488,16 +3809,20 @@ CONFIG_MII=y # CONFIG_MIPS_CDMM is not set # CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set # CONFIG_MIPS_CMDLINE_FROM_DTB is not set +# CONFIG_MIPS_CMP is not set # CONFIG_MIPS_COBALT is not set # CONFIG_MIPS_CPS is not set # CONFIG_MIPS_ELF_APPENDED_DTB is not set +# CONFIG_MIPS_FPU_EMULATOR is not set # CONFIG_MIPS_FP_SUPPORT is not set # CONFIG_MIPS_GENERIC is not set # CONFIG_MIPS_GENERIC_KERNEL is not set # CONFIG_MIPS_MALTA is not set # CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_PARAVIRT is not set # CONFIG_MIPS_PLATFORM_DEVICES is not set # CONFIG_MIPS_RAW_APPENDED_DTB is not set +# CONFIG_MIPS_SEAD3 is not set # CONFIG_MIPS_VA_BITS_48 is not set # CONFIG_MIPS_VPE_LOADER is not set # CONFIG_MISC_ALCOR_PCI is not set @@ -3517,6 +3842,7 @@ CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y # CONFIG_MLX4_CORE is not set # CONFIG_MLX4_EN is not set # CONFIG_MLX5_CORE is not set +# CONFIG_MLX5_EN_MACSEC is not set # CONFIG_MLX5_MACSEC is not set # CONFIG_MLX5_SF is not set # CONFIG_MLX5_VFIO_PCI is not set @@ -3524,6 +3850,7 @@ CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y # CONFIG_MLX90632 is not set # CONFIG_MLXFW is not set # CONFIG_MLXSW_CORE is not set +# CONFIG_MLX_CPLD_PLATFORM is not set # CONFIG_MLX_PLATFORM is not set # CONFIG_MMA7455_I2C is not set # CONFIG_MMA7455_SPI is not set @@ -3536,6 +3863,7 @@ CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y # CONFIG_MMC_ARMMMCI is not set # CONFIG_MMC_AU1X is not set # CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y CONFIG_MMC_BLOCK_MINORS=8 # CONFIG_MMC_CAVIUM_THUNDERX is not set # CONFIG_MMC_CB710 is not set @@ -3546,6 +3874,7 @@ CONFIG_MMC_BLOCK_MINORS=8 # CONFIG_MMC_JZ4740 is not set # CONFIG_MMC_MTK is not set # CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set # CONFIG_MMC_SDHCI is not set # CONFIG_MMC_SDHCI_ACPI is not set # CONFIG_MMC_SDHCI_AM654 is not set @@ -3584,6 +3913,7 @@ CONFIG_MMU_GATHER_TABLE_FREE=y CONFIG_MODPROBE_PATH="/sbin/modprobe" CONFIG_MODULES=y # CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_MODULE_COMPRESS is not set # CONFIG_MODULE_COMPRESS_GZIP is not set CONFIG_MODULE_COMPRESS_NONE=y # CONFIG_MODULE_COMPRESS_XZ is not set @@ -3659,12 +3989,15 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y # CONFIG_MTD_DATAFLASH is not set # CONFIG_MTD_DOCG3 is not set CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set # CONFIG_MTD_HYPERBUS is not set # CONFIG_MTD_IMPA7 is not set # CONFIG_MTD_INTEL_VR_NOR is not set # CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set # CONFIG_MTD_LPDDR is not set # CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set CONFIG_MTD_MAP_BANK_WIDTH_1=y # CONFIG_MTD_MAP_BANK_WIDTH_16 is not set CONFIG_MTD_MAP_BANK_WIDTH_2=y @@ -3673,12 +4006,18 @@ CONFIG_MTD_MAP_BANK_WIDTH_4=y # CONFIG_MTD_MAP_BANK_WIDTH_8 is not set # CONFIG_MTD_MCHP23K256 is not set # CONFIG_MTD_MCHP48L640 is not set +# CONFIG_MTD_MT81xx_NOR is not set # CONFIG_MTD_MTDRAM is not set # CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set # CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set # CONFIG_MTD_NAND_ARASAN is not set # CONFIG_MTD_NAND_ATMEL is not set # CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BF5XX is not set # CONFIG_MTD_NAND_BRCMNAND is not set # CONFIG_MTD_NAND_BRCMNAND_BCM63XX is not set # CONFIG_MTD_NAND_BRCMNAND_BCMBCA is not set @@ -3686,14 +4025,19 @@ CONFIG_MTD_MAP_BANK_WIDTH_4=y # CONFIG_MTD_NAND_BRCMNAND_IPROC is not set # CONFIG_MTD_NAND_CADENCE is not set # CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set # CONFIG_MTD_NAND_CS553X is not set # CONFIG_MTD_NAND_DAVINCI is not set # CONFIG_MTD_NAND_DENALI is not set # CONFIG_MTD_NAND_DENALI_DT is not set # CONFIG_MTD_NAND_DENALI_PCI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 # CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set # CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set # CONFIG_MTD_NAND_ECC_MXIC is not set +# CONFIG_MTD_NAND_ECC_SMC is not set # CONFIG_MTD_NAND_ECC_SW_BCH is not set # CONFIG_MTD_NAND_ECC_SW_HAMMING is not set # CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC is not set @@ -3704,7 +4048,9 @@ CONFIG_MTD_MAP_BANK_WIDTH_4=y # CONFIG_MTD_NAND_GPIO is not set # CONFIG_MTD_NAND_GPMI_NAND is not set # CONFIG_MTD_NAND_HISI504 is not set +CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_INTEL_LGM is not set +# CONFIG_MTD_NAND_JZ4740 is not set # CONFIG_MTD_NAND_MPC5121_NFC is not set # CONFIG_MTD_NAND_MTK is not set # CONFIG_MTD_NAND_MTK_BMT is not set @@ -3712,16 +4058,22 @@ CONFIG_MTD_MAP_BANK_WIDTH_4=y # CONFIG_MTD_NAND_MXIC is not set # CONFIG_MTD_NAND_NANDSIM is not set # CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NUC900 is not set # CONFIG_MTD_NAND_OMAP2 is not set # CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set # CONFIG_MTD_NAND_ORION is not set # CONFIG_MTD_NAND_PASEMI is not set # CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RB91X is not set # CONFIG_MTD_NAND_RICOH is not set # CONFIG_MTD_NAND_S3C2410 is not set # CONFIG_MTD_NAND_SHARPSL is not set # CONFIG_MTD_NAND_SH_FLCTL is not set # CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_TMIO is not set # CONFIG_MTD_NAND_TXX9NDFMC is not set CONFIG_MTD_OF_PARTS=y # CONFIG_MTD_ONENAND is not set @@ -3738,6 +4090,8 @@ CONFIG_MTD_OF_PARTS=y # CONFIG_MTD_PHYSMAP_GPIO_ADDR is not set # CONFIG_MTD_PHYSMAP_IXP4XX is not set CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PHYSMAP_OF_GEMINI is not set +# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set # CONFIG_MTD_PHYSMAP_VERSATILE is not set # CONFIG_MTD_PLATRAM is not set # CONFIG_MTD_PMC551 is not set @@ -3753,6 +4107,7 @@ CONFIG_MTD_ROOTFS_ROOT_DEV=y # CONFIG_MTD_SERCOMM_PARTS is not set # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPINAND_MT29F is not set # CONFIG_MTD_SPI_NAND is not set # CONFIG_MTD_SPI_NOR is not set # CONFIG_MTD_SPI_NOR_SWP_DISABLE is not set @@ -3788,8 +4143,10 @@ CONFIG_MTD_SPLIT_SUPPORT=y # CONFIG_MTD_UBI_FASTMAP is not set # CONFIG_MTD_UBI_GLUEBI is not set # CONFIG_MTD_UBI_NVMEM is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set # CONFIG_MTD_VIRT_CONCAT is not set # CONFIG_MTK_DEVAPC is not set +# CONFIG_MTK_MMC is not set # CONFIG_MTK_MMSYS is not set # CONFIG_MTK_T7XX is not set # CONFIG_MTK_THERMAL is not set @@ -3803,6 +4160,7 @@ CONFIG_MULTIUSER=y # CONFIG_MV643XX_ETH is not set # CONFIG_MVMDIO is not set # CONFIG_MVNETA_BM is not set +# CONFIG_MVSW61XX_PHY is not set # CONFIG_MV_XOR_V2 is not set # CONFIG_MWAVE is not set # CONFIG_MWL8K is not set @@ -3815,8 +4173,10 @@ CONFIG_MULTIUSER=y # CONFIG_NAU7802 is not set # CONFIG_NBPFAXI_DMA is not set # CONFIG_NCN26000_PHY is not set +# CONFIG_NCP_FS is not set # CONFIG_NE2000 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set CONFIG_NET=y # CONFIG_NETCONSOLE is not set # CONFIG_NETCONSOLE_EXTENDED_LOG is not set @@ -3824,6 +4184,7 @@ CONFIG_NETDEVICES=y # CONFIG_NETDEVSIM is not set # CONFIG_NETFILTER is not set # CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set # CONFIG_NETFILTER_EGRESS is not set # CONFIG_NETFILTER_INGRESS is not set # CONFIG_NETFILTER_NETLINK is not set @@ -3909,6 +4270,7 @@ CONFIG_NETDEVICES=y # CONFIG_NETFS_STATS is not set # CONFIG_NETLABEL is not set # CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set # CONFIG_NETPOLL is not set # CONFIG_NETROM is not set CONFIG_NETWORK_FILESYSTEMS=y @@ -3934,6 +4296,7 @@ CONFIG_NETWORK_FILESYSTEMS=y # CONFIG_NET_ACT_SKBMOD is not set # CONFIG_NET_ACT_TUNNEL_KEY is not set # CONFIG_NET_ACT_VLAN is not set +CONFIG_NET_CADENCE=y # CONFIG_NET_CALXEDA_XGMAC is not set CONFIG_NET_CLS=y # CONFIG_NET_CLS_ACT is not set @@ -3942,8 +4305,11 @@ CONFIG_NET_CLS=y # CONFIG_NET_CLS_FLOW is not set # CONFIG_NET_CLS_FLOWER is not set # CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y # CONFIG_NET_CLS_MATCHALL is not set # CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set # CONFIG_NET_CLS_U32 is not set CONFIG_NET_CORE=y # CONFIG_NET_DEVLINK is not set @@ -3953,14 +4319,22 @@ CONFIG_NET_CORE=y # CONFIG_NET_DSA_AR9331 is not set # CONFIG_NET_DSA_BCM_SF2 is not set # CONFIG_NET_DSA_LANTIQ_GSWIP is not set +# CONFIG_NET_DSA_LEGACY is not set # CONFIG_NET_DSA_LOOP is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ8795 is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ9477 is not set # CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON is not set # CONFIG_NET_DSA_MSCC_FELIX is not set # CONFIG_NET_DSA_MSCC_OCELOT_EXT is not set # CONFIG_NET_DSA_MSCC_SEVILLE is not set # CONFIG_NET_DSA_MT7530 is not set # CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set # CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set # CONFIG_NET_DSA_MV88E6XXX_PTP is not set # CONFIG_NET_DSA_QCA8K is not set # CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT is not set @@ -3969,6 +4343,7 @@ CONFIG_NET_CORE=y # CONFIG_NET_DSA_SJA1105 is not set # CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set # CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set +# CONFIG_NET_DSA_TAG_8021Q is not set # CONFIG_NET_DSA_TAG_AR9331 is not set # CONFIG_NET_DSA_TAG_BRCM is not set # CONFIG_NET_DSA_TAG_BRCM_LEGACY is not set @@ -4023,6 +4398,7 @@ CONFIG_NET_IPGRE_BROADCAST=y # CONFIG_NET_NCSI is not set # CONFIG_NET_NSH is not set # CONFIG_NET_NS_REFCNT_TRACKER is not set +# CONFIG_NET_PACKET_ENGINE is not set # CONFIG_NET_PKTGEN is not set # CONFIG_NET_POLL_CONTROLLER is not set # CONFIG_NET_PTP_CLASSIFY is not set @@ -4060,9 +4436,11 @@ CONFIG_NET_SCH_FQ_CODEL=y # CONFIG_NET_SCH_TAPRIO is not set # CONFIG_NET_SCH_TBF is not set # CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set # CONFIG_NET_SELFTESTS is not set CONFIG_NET_SOCK_MSG=y # CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_TCPPROBE is not set # CONFIG_NET_TC_SKB_EXT is not set # CONFIG_NET_TEAM is not set # CONFIG_NET_TULIP is not set @@ -4080,6 +4458,7 @@ CONFIG_NET_VENDOR_AQUANTIA=y CONFIG_NET_VENDOR_ARC=y # CONFIG_NET_VENDOR_ASIX is not set CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_AURORA=y CONFIG_NET_VENDOR_BROADCOM=y CONFIG_NET_VENDOR_BROCADE=y CONFIG_NET_VENDOR_CADENCE=y @@ -4093,6 +4472,7 @@ CONFIG_NET_VENDOR_DEC=y CONFIG_NET_VENDOR_DLINK=y CONFIG_NET_VENDOR_EMULEX=y # CONFIG_NET_VENDOR_ENGLEDER is not set +CONFIG_NET_VENDOR_EXAR=y CONFIG_NET_VENDOR_EZCHIP=y CONFIG_NET_VENDOR_FARADAY=y CONFIG_NET_VENDOR_FREESCALE=y @@ -4100,6 +4480,7 @@ CONFIG_NET_VENDOR_FUJITSU=y # CONFIG_NET_VENDOR_FUNGIBLE is not set CONFIG_NET_VENDOR_GOOGLE=y CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y CONFIG_NET_VENDOR_HUAWEI=y CONFIG_NET_VENDOR_I825XX=y CONFIG_NET_VENDOR_IBM=y @@ -4153,6 +4534,7 @@ CONFIG_NEW_LEDS=y # CONFIG_NFSD is not set # CONFIG_NFSD_V2 is not set # CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y # CONFIG_NFSD_V3_ACL is not set # CONFIG_NFSD_V4 is not set # CONFIG_NFS_ACL_SUPPORT is not set @@ -4176,8 +4558,11 @@ CONFIG_NFS_V3=y # CONFIG_NFT_FIB_IPV6 is not set # CONFIG_NFT_FIB_NETDEV is not set # CONFIG_NFT_FLOW_OFFLOAD is not set +# CONFIG_NFT_OBJREF is not set # CONFIG_NFT_OSF is not set # CONFIG_NFT_REJECT_NETDEV is not set +# CONFIG_NFT_RT is not set +# CONFIG_NFT_SET_BITMAP is not set # CONFIG_NFT_SOCKET is not set # CONFIG_NFT_SYNPROXY is not set # CONFIG_NFT_TPROXY is not set @@ -4195,6 +4580,7 @@ CONFIG_NFS_V3=y # CONFIG_NF_CONNTRACK_NETBIOS_NS is not set # CONFIG_NF_CONNTRACK_PPTP is not set CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set # CONFIG_NF_CONNTRACK_SANE is not set # CONFIG_NF_CONNTRACK_SECMARK is not set # CONFIG_NF_CONNTRACK_SIP is not set @@ -4216,14 +4602,18 @@ CONFIG_NF_CONNTRACK_PROCFS=y # CONFIG_NF_FLOW_TABLE is not set # CONFIG_NF_FLOW_TABLE_PROCFS is not set # CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_BRIDGE is not set # CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_LOG_NETDEV is not set # CONFIG_NF_LOG_SYSLOG is not set # CONFIG_NF_NAT is not set # CONFIG_NF_NAT_AMANDA is not set # CONFIG_NF_NAT_FTP is not set # CONFIG_NF_NAT_H323 is not set # CONFIG_NF_NAT_IRC is not set +# CONFIG_NF_NAT_NEEDED is not set # CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set # CONFIG_NF_NAT_SIP is not set # CONFIG_NF_NAT_SNMP_BASIC is not set # CONFIG_NF_NAT_TFTP is not set @@ -4238,9 +4628,11 @@ CONFIG_NF_TABLES_INET=y CONFIG_NF_TABLES_IPV4=y CONFIG_NF_TABLES_IPV6=y CONFIG_NF_TABLES_NETDEV=y +# CONFIG_NF_TABLES_SET is not set # CONFIG_NF_TPROXY_IPV4 is not set # CONFIG_NF_TPROXY_IPV6 is not set # CONFIG_NGBE is not set +# CONFIG_NI65 is not set # CONFIG_NI903X_WDT is not set # CONFIG_NIC7018_WDT is not set # CONFIG_NILFS2_FS is not set @@ -4248,6 +4640,8 @@ CONFIG_NF_TABLES_NETDEV=y # CONFIG_NI_XGE_MANAGEMENT_ENET is not set CONFIG_NLATTR=y # CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set # CONFIG_NLS is not set # CONFIG_NLS_ASCII is not set # CONFIG_NLS_CODEPAGE_1250 is not set @@ -4300,11 +4694,14 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_MAC_TURKISH is not set # CONFIG_NLS_UCS2_UTILS is not set # CONFIG_NLS_UTF8 is not set +CONFIG_NMI_LOG_BUF_SHIFT=13 # CONFIG_NOA1305 is not set # CONFIG_NOP_USB_XCEIV is not set # CONFIG_NORTEL_HERMES is not set # CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT is not set # CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set # CONFIG_NO_HZ is not set # CONFIG_NO_HZ_FULL is not set # CONFIG_NO_HZ_IDLE is not set @@ -4321,9 +4718,9 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NULL_TTY is not set # CONFIG_NUMA is not set # CONFIG_NVIDIA_CARMEL_CNP_ERRATUM is not set +# CONFIG_NVM is not set # CONFIG_NVMEM is not set # CONFIG_NVMEM_BCM_OCOTP is not set -# CONFIG_NVMEM_BLOCK is not set # CONFIG_NVMEM_IMX_OCOTP is not set # CONFIG_NVMEM_LAYOUT_ONIE_TLV is not set # CONFIG_NVMEM_LAYOUT_SL28_VPD is not set @@ -4340,6 +4737,8 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NV_TCO is not set # CONFIG_NXP_C45_TJA11XX_PHY is not set # CONFIG_NXP_CBTX_PHY is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set # CONFIG_NXP_TJA11XX_PHY is not set # CONFIG_N_GSM is not set # CONFIG_OABI_COMPAT is not set @@ -4360,8 +4759,11 @@ CONFIG_OF_RESERVED_MEM=y # CONFIG_OMFS_FS is not set # CONFIG_OPENVSWITCH is not set # CONFIG_OPEN_DICE is not set +# CONFIG_OPROFILE is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set # CONFIG_OPT3001 is not set # CONFIG_OPT4001 is not set +CONFIG_OPTIMIZE_INLINING=y # CONFIG_ORANGEFS_FS is not set # CONFIG_ORION_WATCHDOG is not set # CONFIG_OSF_PARTITION is not set @@ -4373,6 +4775,7 @@ CONFIG_OVERLAY_FS=y CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y # CONFIG_OVERLAY_FS_REDIRECT_DIR is not set CONFIG_OVERLAY_FS_XINO_AUTO=y +# CONFIG_OWL_LOADER is not set # CONFIG_P54_COMMON is not set # CONFIG_PA12203001 is not set CONFIG_PACKET=y @@ -4401,6 +4804,7 @@ CONFIG_PANIC_TIMEOUT=1 # CONFIG_PARAVIRT_TIME_ACCOUNTING is not set # CONFIG_PARPORT is not set # CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set # CONFIG_PARPORT_GSC is not set # CONFIG_PARPORT_PC is not set CONFIG_PARTITION_ADVANCED=y @@ -4479,6 +4883,7 @@ CONFIG_PCIE_BUS_DEFAULT=y # CONFIG_PCIE_BUS_PERFORMANCE is not set # CONFIG_PCIE_BUS_SAFE is not set # CONFIG_PCIE_BUS_TUNE_OFF is not set +# CONFIG_PCIE_BW is not set # CONFIG_PCIE_CADENCE_HOST is not set # CONFIG_PCIE_CADENCE_PLAT_HOST is not set # CONFIG_PCIE_DPC is not set @@ -4549,6 +4954,7 @@ CONFIG_PCI_SYSCALL=y # CONFIG_PCS_MTK_USXGMII is not set # CONFIG_PCS_XPCS is not set # CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set # CONFIG_PDC_ADMA is not set # CONFIG_PDS_CORE is not set # CONFIG_PECI is not set @@ -4564,6 +4970,7 @@ CONFIG_PCI_SYSCALL=y # CONFIG_PHYLIB_LEDS is not set # CONFIG_PHYS_ADDR_T_64BIT is not set # CONFIG_PHY_BRCM_USB is not set +# CONFIG_PHY_CADENCE_DP is not set # CONFIG_PHY_CADENCE_DPHY is not set # CONFIG_PHY_CADENCE_DPHY_RX is not set # CONFIG_PHY_CADENCE_SALVO is not set @@ -4587,6 +4994,7 @@ CONFIG_PCI_SYSCALL=y # CONFIG_PHY_PISTACHIO_USB is not set # CONFIG_PHY_PXA_28NM_HSIC is not set # CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_QCOM_DWC3 is not set # CONFIG_PHY_QCOM_USB_HS is not set # CONFIG_PHY_QCOM_USB_HSIC is not set # CONFIG_PHY_SAMSUNG_USB2 is not set @@ -4599,9 +5007,11 @@ CONFIG_PINCONF=y # CONFIG_PINCTRL is not set # CONFIG_PINCTRL_AMD is not set # CONFIG_PINCTRL_AXP209 is not set +# CONFIG_PINCTRL_BCM2712 is not set # CONFIG_PINCTRL_CEDARFORK is not set # CONFIG_PINCTRL_CY8C95X0 is not set # CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set # CONFIG_PINCTRL_ICELAKE is not set # CONFIG_PINCTRL_INGENIC is not set # CONFIG_PINCTRL_LPASS_LPI is not set @@ -4618,6 +5028,7 @@ CONFIG_PINCONF=y # CONFIG_PINCTRL_MTK_V2 is not set # CONFIG_PINCTRL_OCELOT is not set # CONFIG_PINCTRL_PISTACHIO is not set +# CONFIG_PINCTRL_RP1 is not set # CONFIG_PINCTRL_SC7280 is not set # CONFIG_PINCTRL_SC8180X is not set # CONFIG_PINCTRL_SDX55 is not set @@ -4643,6 +5054,7 @@ CONFIG_PINMUX=y # CONFIG_PLX_HERMES is not set # CONFIG_PM is not set # CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set # CONFIG_PMIC_ADP5520 is not set # CONFIG_PMIC_DA903X is not set # CONFIG_PMS7003 is not set @@ -4654,6 +5066,7 @@ CONFIG_PINMUX=y # CONFIG_POSIX_MQUEUE is not set CONFIG_POSIX_TIMERS=y # CONFIG_POWERCAP is not set +# CONFIG_POWER_AVS is not set # CONFIG_POWER_RESET is not set # CONFIG_POWER_RESET_BRCMKONA is not set # CONFIG_POWER_RESET_BRCMSTB is not set @@ -4705,6 +5118,7 @@ CONFIG_PPP_MULTILINK=y # CONFIG_PPTP is not set # CONFIG_PREEMPT is not set # CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_PREEMPTIRQ_EVENTS is not set # CONFIG_PREEMPT_DYNAMIC is not set CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_TRACER is not set @@ -4715,9 +5129,12 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_PRINTK=y # CONFIG_PRINTK_CALLER is not set # CONFIG_PRINTK_INDEX is not set +CONFIG_PRINTK_NMI=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 # CONFIG_PRINTK_TIME is not set CONFIG_PRINT_STACK_DEPTH=64 # CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set # CONFIG_PROC_CHILDREN is not set CONFIG_PROC_FS=y # CONFIG_PROC_KCORE is not set @@ -4732,18 +5149,26 @@ CONFIG_PROC_SYSCTL=y # CONFIG_PROVE_RAW_LOCK_NESTING is not set # CONFIG_PROVE_RCU is not set # CONFIG_PROVE_RCU_LIST is not set +# CONFIG_PROVE_RCU_REPEATEDLY is not set # CONFIG_PSAMPLE is not set # CONFIG_PSB6970_PHY is not set # CONFIG_PSE_CONTROLLER is not set # CONFIG_PSI is not set # CONFIG_PSTORE is not set +# CONFIG_PSTORE_842_COMPRESS is not set # CONFIG_PSTORE_BLK is not set # CONFIG_PSTORE_COMPRESS is not set # CONFIG_PSTORE_CONSOLE is not set CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240 +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT is not set # CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set # CONFIG_PSTORE_PMSG is not set # CONFIG_PSTORE_RAM is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set # CONFIG_PTDUMP_DEBUGFS is not set # CONFIG_PTP_1588_CLOCK is not set # CONFIG_PTP_1588_CLOCK_IDT82P33 is not set @@ -4754,6 +5179,7 @@ CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240 # CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_PCH is not set # CONFIG_PTP_1588_CLOCK_VMW is not set +# CONFIG_PUBLIC_KEY_ALGO_RSA is not set # CONFIG_PVPANIC is not set # CONFIG_PWM is not set # CONFIG_PWM_ATMEL_TCB is not set @@ -4766,6 +5192,7 @@ CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240 # CONFIG_PWM_MEDIATEK is not set # CONFIG_PWM_PCA9685 is not set # CONFIG_PWM_RASPBERRYPI_POE is not set +# CONFIG_PWM_RP1 is not set # CONFIG_PWM_XILINX is not set CONFIG_PWRSEQ_EMMC=y # CONFIG_PWRSEQ_SD8787 is not set @@ -4806,15 +5233,18 @@ CONFIG_PWRSEQ_SIMPLE=y # CONFIG_QRTR_MHI is not set # CONFIG_QRTR_TUN is not set # CONFIG_QSEMI_PHY is not set +# CONFIG_QUEUED_LOCK_STAT is not set # CONFIG_QUICC_ENGINE is not set # CONFIG_QUOTA is not set # CONFIG_QUOTACTL is not set # CONFIG_QUOTA_DEBUG is not set # CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_R3964 is not set # CONFIG_R6040 is not set # CONFIG_R8169 is not set -# CONFIG_R8169_LEDS is not set +# CONFIG_R8188EU is not set # CONFIG_R8712U is not set +# CONFIG_R8723AU is not set # CONFIG_RADIO_ADAPTERS is not set # CONFIG_RADIO_AZTECH is not set # CONFIG_RADIO_CADET is not set @@ -4836,22 +5266,29 @@ CONFIG_PWRSEQ_SIMPLE=y CONFIG_RANDOMIZE_KSTACK_OFFSET=y # CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set # CONFIG_RANDOM_KMALLOC_CACHES is not set +CONFIG_RANDOM_TRUST_BOOTLOADER=y +CONFIG_RANDOM_TRUST_CPU=y # CONFIG_RANDSTRUCT_NONE is not set # CONFIG_RAPIDIO is not set # CONFIG_RAS is not set +# CONFIG_RASPBERRYPI_GPIOMEM is not set # CONFIG_RBTREE_TEST is not set # CONFIG_RCU_BOOST is not set # CONFIG_RCU_CPU_STALL_CPUTIME is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 # CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_RCU_EXPEDITE_BOOT is not set # CONFIG_RCU_EXPERT is not set CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0 +CONFIG_RCU_KTHREAD_PRIO=0 CONFIG_RCU_NEED_SEGCBLIST=y +# CONFIG_RCU_PERF_TEST is not set # CONFIG_RCU_REF_SCALE_TEST is not set # CONFIG_RCU_SCALE_TEST is not set CONFIG_RCU_STALL_COMMON=y # CONFIG_RCU_STRICT_GRACE_PERIOD is not set # CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 # CONFIG_RCU_TRACE is not set # CONFIG_RC_ATI_REMOTE is not set # CONFIG_RC_CORE is not set @@ -4930,6 +5367,7 @@ CONFIG_RCU_STALL_COMMON=y # CONFIG_REGULATOR_QCOM_REFGEN is not set # CONFIG_REGULATOR_RAA215300 is not set # CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set +# CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2 is not set # CONFIG_REGULATOR_RT4801 is not set # CONFIG_REGULATOR_RT4803 is not set # CONFIG_REGULATOR_RT5190A is not set @@ -4981,6 +5419,7 @@ CONFIG_REISERFS_FS_XATTR=y # CONFIG_RESET_PISTACHIO is not set # CONFIG_RESET_SIMPLE is not set # CONFIG_RESET_SOCFPGA is not set +# CONFIG_RESET_STM32 is not set # CONFIG_RESET_SUNXI is not set # CONFIG_RESET_TEGRA_BPMP is not set # CONFIG_RESET_TI_SYSCON is not set @@ -4993,6 +5432,7 @@ CONFIG_RFKILL=y # CONFIG_RFKILL_GPIO is not set # CONFIG_RFKILL_INPUT is not set # CONFIG_RFKILL_LEDS is not set +# CONFIG_RFKILL_REGULATOR is not set # CONFIG_RICHTEK_RTQ6056 is not set # CONFIG_RING_BUFFER_BENCHMARK is not set # CONFIG_RING_BUFFER_STARTUP_TEST is not set @@ -5035,6 +5475,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1305 is not set # CONFIG_RTC_DRV_DS1307 is not set # CONFIG_RTC_DRV_DS1307_CENTURY is not set +# CONFIG_RTC_DRV_DS1307_HWMON is not set # CONFIG_RTC_DRV_DS1343 is not set # CONFIG_RTC_DRV_DS1347 is not set # CONFIG_RTC_DRV_DS1374 is not set @@ -5046,6 +5487,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1742 is not set # CONFIG_RTC_DRV_DS2404 is not set # CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set # CONFIG_RTC_DRV_EM3027 is not set # CONFIG_RTC_DRV_EP93XX is not set # CONFIG_RTC_DRV_FM3130 is not set @@ -5056,6 +5498,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_HYM8563 is not set # CONFIG_RTC_DRV_ISL12022 is not set # CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_ISL12057 is not set # CONFIG_RTC_DRV_ISL1208 is not set # CONFIG_RTC_DRV_JZ4740 is not set # CONFIG_RTC_DRV_M41T80 is not set @@ -5085,11 +5528,13 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_PL030 is not set # CONFIG_RTC_DRV_PL031 is not set # CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set # CONFIG_RTC_DRV_R7301 is not set # CONFIG_RTC_DRV_R9701 is not set # CONFIG_RTC_DRV_RP5C01 is not set # CONFIG_RTC_DRV_RS5C348 is not set # CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set # CONFIG_RTC_DRV_RV3028 is not set # CONFIG_RTC_DRV_RV3029C2 is not set # CONFIG_RTC_DRV_RV3032 is not set @@ -5106,6 +5551,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_SUN6I is not set # CONFIG_RTC_DRV_TEGRA is not set # CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set # CONFIG_RTC_DRV_X1205 is not set # CONFIG_RTC_DRV_XGENE is not set # CONFIG_RTC_DRV_ZYNQMP is not set @@ -5134,8 +5580,10 @@ CONFIG_RTC_SYSTOHC_DEVICE="rtc0" # CONFIG_RTL_CARDS is not set # CONFIG_RTS5208 is not set CONFIG_RT_MUTEXES=y +# CONFIG_RUNTIME_DEBUG is not set CONFIG_RUNTIME_TESTING_MENU=y # CONFIG_RV is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_RXKAD=y # CONFIG_RXPERF is not set # CONFIG_S2IO is not set @@ -5185,9 +5633,11 @@ CONFIG_SCHED_OMIT_FRAME_POINTER=y # CONFIG_SCHED_SMT is not set CONFIG_SCHED_STACK_END_CHECK=y # CONFIG_SCHED_TRACER is not set +# CONFIG_SCR24X is not set # CONFIG_SCSI is not set # CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_ADVANSYS is not set @@ -5211,13 +5661,20 @@ CONFIG_SCHED_STACK_END_CHECK=y # CONFIG_SCSI_DH is not set CONFIG_SCSI_DMA=y # CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_ESAS2R is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set # CONFIG_SCSI_HISI_SAS is not set # CONFIG_SCSI_HPSA is not set # CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_IPR is not set @@ -5232,13 +5689,17 @@ CONFIG_SCSI_MOD=y # CONFIG_SCSI_MPI3MR is not set # CONFIG_SCSI_MPT2SAS is not set # CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set # CONFIG_SCSI_MVSAS is not set # CONFIG_SCSI_MVSAS_DEBUG is not set # CONFIG_SCSI_MVUMI is not set # CONFIG_SCSI_MYRB is not set # CONFIG_SCSI_MYRS is not set +# CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NETLINK is not set # CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PM8001 is not set # CONFIG_SCSI_PMCRAID is not set CONFIG_SCSI_PROC_FS=y @@ -5254,8 +5715,12 @@ CONFIG_SCSI_PROC_FS=y # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_SRP_ATTRS is not set # CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set # CONFIG_SCSI_VIRTIO is not set # CONFIG_SCSI_WD719X is not set # CONFIG_SC_CAMCC_7180 is not set @@ -5289,8 +5754,10 @@ CONFIG_SECURITY_DMESG_RESTRICT=y # CONFIG_SECURITY_SAFESETID is not set # CONFIG_SECURITY_SELINUX_AVC_STATS is not set # CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=0 # CONFIG_SECURITY_SELINUX_DEBUG is not set # CONFIG_SECURITY_SELINUX_DEVELOP is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set # CONFIG_SECURITY_SMACK is not set # CONFIG_SECURITY_TOMOYO is not set # CONFIG_SECURITY_YAMA is not set @@ -5316,6 +5783,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_ADM1266 is not set # CONFIG_SENSORS_ADM1275 is not set # CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set # CONFIG_SENSORS_ADS7828 is not set # CONFIG_SENSORS_ADS7871 is not set # CONFIG_SENSORS_ADT7310 is not set @@ -5338,6 +5806,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_AXI_FAN_CONTROL is not set # CONFIG_SENSORS_BEL_PFE is not set # CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set # CONFIG_SENSORS_BPA_RS600 is not set # CONFIG_SENSORS_CORETEMP is not set # CONFIG_SENSORS_CORSAIR_CPRO is not set @@ -5372,6 +5841,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_HMC5843_I2C is not set # CONFIG_SENSORS_HMC5843_SPI is not set # CONFIG_SENSORS_HS3001 is not set +# CONFIG_SENSORS_HTU21 is not set # CONFIG_SENSORS_I5500 is not set # CONFIG_SENSORS_I5K_AMB is not set # CONFIG_SENSORS_IBM_CFFPS is not set @@ -5483,6 +5953,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_Q54SJ108A2 is not set # CONFIG_SENSORS_RM3100_I2C is not set # CONFIG_SENSORS_RM3100_SPI is not set +# CONFIG_SENSORS_RP1_ADC is not set # CONFIG_SENSORS_SBRMI is not set # CONFIG_SENSORS_SBTSI is not set # CONFIG_SENSORS_SCH5627 is not set @@ -5494,6 +5965,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_SHT4x is not set # CONFIG_SENSORS_SHTC1 is not set # CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set # CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_SMSC47M192 is not set @@ -5559,6 +6031,7 @@ CONFIG_SERIAL_8250_DMA=y # CONFIG_SERIAL_8250_LPSS is not set # CONFIG_SERIAL_8250_MANY_PORTS is not set # CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_8250_MOXA is not set CONFIG_SERIAL_8250_NR_UARTS=2 # CONFIG_SERIAL_8250_PCI is not set # CONFIG_SERIAL_8250_PCI1XXXX is not set @@ -5581,11 +6054,13 @@ CONFIG_SERIAL_EARLYCON=y # CONFIG_SERIAL_FSL_LINFLEXUART is not set # CONFIG_SERIAL_FSL_LPUART is not set # CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set # CONFIG_SERIAL_JSM is not set # CONFIG_SERIAL_MAX3100 is not set # CONFIG_SERIAL_MAX310X is not set # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set # CONFIG_SERIAL_PCH_UART is not set # CONFIG_SERIAL_RP2 is not set # CONFIG_SERIAL_SC16IS7XX is not set @@ -5616,9 +6091,11 @@ CONFIG_SERIAL_EARLYCON=y # CONFIG_SFC is not set # CONFIG_SFC_FALCON is not set # CONFIG_SFC_SIENA is not set +# CONFIG_SFI is not set # CONFIG_SFP is not set # CONFIG_SF_PDMA is not set # CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SGI_IP27 is not set # CONFIG_SGI_IP28 is not set @@ -5630,6 +6107,7 @@ CONFIG_SERIAL_EARLYCON=y # CONFIG_SG_SPLIT is not set # CONFIG_SHADOW_CALL_STACK is not set CONFIG_SHMEM=y +# CONFIG_SHORTCUT_FE is not set # CONFIG_SHRINKER_DEBUG is not set # CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set # CONFIG_SH_ETH is not set @@ -5641,6 +6119,8 @@ CONFIG_SHMEM=y # CONFIG_SI7005 is not set # CONFIG_SI7020 is not set # CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set # CONFIG_SIBYTE_CRHONE is not set # CONFIG_SIBYTE_LITTLESUR is not set # CONFIG_SIBYTE_RHONE is not set @@ -5648,12 +6128,15 @@ CONFIG_SHMEM=y # CONFIG_SIBYTE_SWARM is not set CONFIG_SIGNALFD=y # CONFIG_SIGNED_PE_FILE_VERIFICATION is not set +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIMPLE_PM_BUS is not set # CONFIG_SIOX is not set # CONFIG_SIS190 is not set # CONFIG_SIS900 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set # CONFIG_SKY2_DEBUG is not set +CONFIG_SLABINFO=y # CONFIG_SLAB_DEPRECATED is not set CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_SLAB_FREELIST_RANDOM=y @@ -5662,14 +6145,17 @@ CONFIG_SLAB_MERGE_DEFAULT=y # CONFIG_SLICOSS is not set # CONFIG_SLIMBUS is not set # CONFIG_SLIP is not set +# CONFIG_SLOB is not set CONFIG_SLUB=y CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_SLUB_DEBUG is not set # CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set # CONFIG_SLUB_STATS is not set # CONFIG_SLUB_TINY is not set # CONFIG_SMARTJOYPLUS_FF is not set # CONFIG_SMB_SERVER is not set +# CONFIG_SMC911X is not set # CONFIG_SMC9194 is not set # CONFIG_SMC91X is not set # CONFIG_SMP is not set @@ -5708,6 +6194,7 @@ CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_SND_AU8830 is not set # CONFIG_SND_AUDIO_GRAPH_CARD is not set # CONFIG_SND_AUDIO_GRAPH_CARD2 is not set +# CONFIG_SND_AUDIO_GRAPH_SCU_CARD is not set # CONFIG_SND_AW2 is not set # CONFIG_SND_AZT2320 is not set # CONFIG_SND_AZT3328 is not set @@ -5735,6 +6222,7 @@ CONFIG_SND_DRIVERS=y # CONFIG_SND_DUMMY is not set # CONFIG_SND_DYNAMIC_MINORS is not set # CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EDMA_SOC is not set # CONFIG_SND_EMU10K1 is not set # CONFIG_SND_EMU10K1X is not set # CONFIG_SND_EMU10K1_SEQ is not set @@ -5753,6 +6241,7 @@ CONFIG_SND_DRIVERS=y # CONFIG_SND_GUSMAX is not set # CONFIG_SND_HDA_CODEC_CS8409 is not set # CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDA_INTEL_DETECT_DMIC is not set # CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM is not set CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 CONFIG_SND_HDA_PREALLOC_SIZE=64 @@ -5817,10 +6306,12 @@ CONFIG_SND_PCM_OSS_PLUGINS=y # CONFIG_SND_PPC is not set CONFIG_SND_PROC_FS=y # CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RAWMIDI_SEQ is not set # CONFIG_SND_RIPTIDE is not set # CONFIG_SND_RME32 is not set # CONFIG_SND_RME96 is not set # CONFIG_SND_RME9652 is not set +# CONFIG_SND_RTCTIMER is not set # CONFIG_SND_SB16 is not set # CONFIG_SND_SB8 is not set # CONFIG_SND_SBAWE is not set @@ -5831,6 +6322,7 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SERIAL_GENERIC is not set # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIMPLE_SCU_CARD is not set # CONFIG_SND_SIS7019 is not set # CONFIG_SND_SOC is not set # CONFIG_SND_SOC_AC97_CODEC is not set @@ -5899,6 +6391,7 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SOC_CS53L30 is not set # CONFIG_SND_SOC_CX2072X is not set # CONFIG_SND_SOC_DA7213 is not set +# CONFIG_SND_SOC_DIO2125 is not set # CONFIG_SND_SOC_DMIC is not set # CONFIG_SND_SOC_ES7134 is not set # CONFIG_SND_SOC_ES7241 is not set @@ -5931,8 +6424,10 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SOC_IMX_HDMI is not set # CONFIG_SND_SOC_IMX_RPMSG is not set # CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set # CONFIG_SND_SOC_INNO_RK3036 is not set # CONFIG_SND_SOC_INTEL_APL is not set +# CONFIG_SND_SOC_INTEL_BAYTRAIL is not set # CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set # CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set # CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set @@ -5941,6 +6436,8 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH is not set # CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH is not set # CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH is not set # CONFIG_SND_SOC_INTEL_CATPT is not set # CONFIG_SND_SOC_INTEL_CFL is not set # CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set @@ -5973,6 +6470,7 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_LPASS_TX_MACRO is not set # CONFIG_SND_SOC_LPASS_VA_MACRO is not set # CONFIG_SND_SOC_LPASS_WSA_MACRO is not set +# CONFIG_SND_SOC_MA120X0P is not set # CONFIG_SND_SOC_MAX9759 is not set # CONFIG_SND_SOC_MAX98088 is not set # CONFIG_SND_SOC_MAX98090 is not set @@ -6014,6 +6512,7 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_NAU8824 is not set # CONFIG_SND_SOC_PCM1681 is not set # CONFIG_SND_SOC_PCM1789_I2C is not set +# CONFIG_SND_SOC_PCM1792A is not set # CONFIG_SND_SOC_PCM179X_I2C is not set # CONFIG_SND_SOC_PCM179X_SPI is not set # CONFIG_SND_SOC_PCM186X_I2C is not set @@ -6039,6 +6538,7 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_SGTL5000 is not set # CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set # CONFIG_SND_SOC_SIMPLE_MUX is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set # CONFIG_SND_SOC_SMA1303 is not set # CONFIG_SND_SOC_SOF_TOPLEVEL is not set # CONFIG_SND_SOC_SPDIF is not set @@ -6113,6 +6613,7 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_XILINX_SPDIF is not set # CONFIG_SND_SOC_XTFPGA_I2S is not set # CONFIG_SND_SOC_ZL38060 is not set +# CONFIG_SND_SOC_ZX_AUD96P22 is not set # CONFIG_SND_SONICVIBES is not set # CONFIG_SND_SPI is not set # CONFIG_SND_SSCAPE is not set @@ -6154,6 +6655,7 @@ CONFIG_SND_X86=y # CONFIG_SOC_AM33XX is not set # CONFIG_SOC_AM43XX is not set # CONFIG_SOC_BRCMSTB is not set +# CONFIG_SOC_CAMERA is not set # CONFIG_SOC_DRA7XX is not set # CONFIG_SOC_HAS_OMAP2_SDRC is not set # CONFIG_SOC_OMAP5 is not set @@ -6167,11 +6669,13 @@ CONFIG_SND_X86=y # CONFIG_SOUNDWIRE is not set # CONFIG_SOUND_OSS_CORE is not set # CONFIG_SOUND_OSS_CORE_PRECLAIM is not set +# CONFIG_SOUND_PRIME is not set # CONFIG_SP5100_TCO is not set # CONFIG_SPARSEMEM_MANUAL is not set # CONFIG_SPARSEMEM_STATIC is not set # CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set # CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set # CONFIG_SPEAKUP is not set # CONFIG_SPI is not set # CONFIG_SPINLOCK_TEST is not set @@ -6183,7 +6687,6 @@ CONFIG_SND_X86=y # CONFIG_SPI_BCM2835 is not set # CONFIG_SPI_BCM63XX_HSSPI is not set # CONFIG_SPI_BCM_QSPI is not set -# CONFIG_SPI_BCMBCA_HSSPI is not set # CONFIG_SPI_BITBANG is not set # CONFIG_SPI_BUTTERFLY is not set # CONFIG_SPI_CADENCE is not set @@ -6195,6 +6698,7 @@ CONFIG_SND_X86=y # CONFIG_SPI_FSL_ESPI is not set # CONFIG_SPI_FSL_SPI is not set # CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set # CONFIG_SPI_IMG_SPFI is not set # CONFIG_SPI_LANTIQ_SSC is not set # CONFIG_SPI_LM70_LLP is not set @@ -6205,6 +6709,7 @@ CONFIG_SND_X86=y # CONFIG_SPI_MICROCHIP_CORE_QSPI is not set # CONFIG_SPI_MPC52xx is not set # CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_MTK_QUADSPI is not set # CONFIG_SPI_MUX is not set # CONFIG_SPI_MXIC is not set # CONFIG_SPI_NXP_FLEXSPI is not set @@ -6230,6 +6735,7 @@ CONFIG_SND_X86=y # CONFIG_SPI_TOPCLIFF_PCH is not set # CONFIG_SPI_XCOMM is not set # CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set # CONFIG_SPI_ZYNQMP_GQSPI is not set CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_SPMI is not set @@ -6256,11 +6762,13 @@ CONFIG_SQUASHFS_XZ=y # CONFIG_SRF04 is not set # CONFIG_SRF08 is not set # CONFIG_SSB is not set +# CONFIG_SSB_DEBUG is not set # CONFIG_SSB_DRIVER_GPIO is not set # CONFIG_SSB_HOST_SOC is not set # CONFIG_SSB_PCMCIAHOST is not set CONFIG_SSB_POSSIBLE=y # CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set # CONFIG_SSFDC is not set # CONFIG_SSIF_IPMI_BMC is not set # CONFIG_STACKPROTECTOR is not set @@ -6269,15 +6777,19 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_STACKTRACE is not set # CONFIG_STACKTRACE_BUILD_ID is not set CONFIG_STACKTRACE_SUPPORT=y +CONFIG_STACK_HASH_ORDER=20 # CONFIG_STACK_TRACER is not set # CONFIG_STACK_VALIDATION is not set CONFIG_STAGING=y # CONFIG_STAGING_BOARD is not set +# CONFIG_STAGING_GASKET_FRAMEWORK is not set # CONFIG_STAGING_MEDIA is not set CONFIG_STANDALONE=y # CONFIG_STATIC_KEYS_SELFTEST is not set # CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_STDBINUTILS=y # CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set # CONFIG_STK3310 is not set # CONFIG_STK8312 is not set # CONFIG_STK8BA50 is not set @@ -6305,15 +6817,18 @@ CONFIG_STRIP_ASM_SYMS=y # CONFIG_SUNGEM is not set # CONFIG_SUNRPC is not set # CONFIG_SUNRPC_DEBUG is not set +CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES=y # CONFIG_SUNRPC_GSS is not set # CONFIG_SUNXI_SRAM is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SURFACE_3_BUTTON is not set # CONFIG_SURFACE_PLATFORMS is not set # CONFIG_SUSPEND is not set # CONFIG_SUSPEND_SKIP_SYNC is not set CONFIG_SWAP=y # CONFIG_SWCONFIG is not set # CONFIG_SWCONFIG_B53 is not set +# CONFIG_SWCONFIG_B53_MDIO_DRIVER is not set # CONFIG_SWCONFIG_B53_MMAP_DRIVER is not set # CONFIG_SWCONFIG_B53_SPI_DRIVER is not set # CONFIG_SWCONFIG_B53_SRAB_DRIVER is not set @@ -6327,13 +6842,18 @@ CONFIG_SWAP=y # CONFIG_SX9500 is not set # CONFIG_SXGBE_ETH is not set CONFIG_SYMBOLIC_ERRNAME=y +# CONFIG_SYNCLINK_CS is not set # CONFIG_SYNC_FILE is not set +# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set # CONFIG_SYNTH_EVENTS is not set # CONFIG_SYNTH_EVENT_GEN_TEST is not set CONFIG_SYN_COOKIES=y # CONFIG_SYSCON_REBOOT_MODE is not set CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set # CONFIG_SYSFS_SYSCALL is not set # CONFIG_SYSTEMPORT is not set # CONFIG_SYSTEM_BLACKLIST_KEYRING is not set @@ -6356,6 +6876,7 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_TCG_FTPM_TEE is not set # CONFIG_TCG_INFINEON is not set # CONFIG_TCG_NSC is not set +# CONFIG_TCG_ST33_I2C is not set # CONFIG_TCG_TIS is not set # CONFIG_TCG_TIS_I2C is not set # CONFIG_TCG_TIS_I2C_ATMEL is not set @@ -6395,6 +6916,7 @@ CONFIG_TCP_CONG_CUBIC=y # CONFIG_TEHUTI is not set # CONFIG_TERANETICS_PHY is not set # CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +# CONFIG_TEST_BITFIELD is not set # CONFIG_TEST_BITMAP is not set # CONFIG_TEST_BITOPS is not set # CONFIG_TEST_BLACKHOLE_DEV is not set @@ -6406,8 +6928,10 @@ CONFIG_TCP_CONG_CUBIC=y # CONFIG_TEST_DYNAMIC_DEBUG is not set # CONFIG_TEST_FIRMWARE is not set # CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_HASH is not set # CONFIG_TEST_HEXDUMP is not set # CONFIG_TEST_IDA is not set +# CONFIG_TEST_KASAN_MODULE is not set # CONFIG_TEST_KMOD is not set # CONFIG_TEST_KSTRTOX is not set # CONFIG_TEST_LIST_SORT is not set @@ -6417,14 +6941,18 @@ CONFIG_TCP_CONG_CUBIC=y # CONFIG_TEST_MEMCAT_P is not set # CONFIG_TEST_MEMINIT is not set # CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_OVERFLOW is not set # CONFIG_TEST_POWER is not set # CONFIG_TEST_PRINTF is not set # CONFIG_TEST_REF_TRACKER is not set # CONFIG_TEST_RHASHTABLE is not set # CONFIG_TEST_SCANF is not set +# CONFIG_TEST_SIPHASH is not set # CONFIG_TEST_SORT is not set +# CONFIG_TEST_STACKINIT is not set # CONFIG_TEST_STATIC_KEYS is not set # CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set # CONFIG_TEST_SYSCTL is not set # CONFIG_TEST_UBSAN is not set # CONFIG_TEST_UDELAY is not set @@ -6452,8 +6980,10 @@ CONFIG_TEXTSEARCH=y # CONFIG_THERMAL_STATISTICS is not set # CONFIG_THERMAL_WRITABLE_TRIPS is not set # CONFIG_THINKPAD_ACPI is not set +CONFIG_THIN_ARCHIVES=y # CONFIG_THRUSTMASTER_FF is not set # CONFIG_THUMB2_KERNEL is not set +# CONFIG_THUNDERBOLT is not set # CONFIG_THUNDER_NIC_BGX is not set # CONFIG_THUNDER_NIC_PF is not set # CONFIG_THUNDER_NIC_RGX is not set @@ -6465,6 +6995,7 @@ CONFIG_TICK_ONESHOT=y # CONFIG_TIMB_DMA is not set CONFIG_TIMERFD=y # CONFIG_TIMERLAT_TRACER is not set +# CONFIG_TIMER_STATS is not set # CONFIG_TIME_NS is not set # CONFIG_TINYDRM_HX8357D is not set # CONFIG_TINYDRM_ILI9163 is not set @@ -6494,15 +7025,19 @@ CONFIG_TINY_RCU=y # CONFIG_TI_ADS8688 is not set # CONFIG_TI_AM335X_ADC is not set # CONFIG_TI_CPSW is not set +# CONFIG_TI_CPSW_ALE is not set # CONFIG_TI_CPSW_PHY_SEL is not set # CONFIG_TI_CPTS is not set # CONFIG_TI_DAC082S085 is not set # CONFIG_TI_DAC5571 is not set # CONFIG_TI_DAC7311 is not set +# CONFIG_TI_DAC7512 is not set # CONFIG_TI_DAC7612 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set # CONFIG_TI_DAVINCI_MDIO is not set # CONFIG_TI_LMP92064 is not set # CONFIG_TI_ST is not set +# CONFIG_TI_SYSCON_RESET is not set # CONFIG_TI_TLC4541 is not set # CONFIG_TI_TMAG5273 is not set # CONFIG_TI_TSC2046 is not set @@ -6594,9 +7129,12 @@ CONFIG_TMPFS_XATTR=y # CONFIG_TOUCHSCREEN_PCAP is not set # CONFIG_TOUCHSCREEN_PENMOUNT is not set # CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_PROPERTIES is not set # CONFIG_TOUCHSCREEN_RASPBERRYPI_FW is not set # CONFIG_TOUCHSCREEN_RM_TS is not set # CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set +# CONFIG_TOUCHSCREEN_RPI_FT5406 is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set # CONFIG_TOUCHSCREEN_S6SY761 is not set # CONFIG_TOUCHSCREEN_SILEAD is not set # CONFIG_TOUCHSCREEN_SIS_I2C is not set @@ -6619,6 +7157,7 @@ CONFIG_TMPFS_XATTR=y # CONFIG_TOUCHSCREEN_TSC2007_IIO is not set # CONFIG_TOUCHSCREEN_TSC200X_CORE is not set # CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_UCB1400 is not set # CONFIG_TOUCHSCREEN_USB_3M is not set # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set # CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set @@ -6638,6 +7177,7 @@ CONFIG_TMPFS_XATTR=y # CONFIG_TOUCHSCREEN_USB_NEXIO is not set # CONFIG_TOUCHSCREEN_USB_PANJIT is not set # CONFIG_TOUCHSCREEN_USB_ZYTRONIC is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set # CONFIG_TOUCHSCREEN_WACOM_I2C is not set # CONFIG_TOUCHSCREEN_WACOM_W8001 is not set # CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set @@ -6647,6 +7187,7 @@ CONFIG_TMPFS_XATTR=y # CONFIG_TOUCHSCREEN_WM9713 is not set # CONFIG_TOUCHSCREEN_WM97XX is not set # CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set +# CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE is not set # CONFIG_TOUCHSCREEN_ZET6223 is not set # CONFIG_TOUCHSCREEN_ZFORCE is not set # CONFIG_TOUCHSCREEN_ZINITIX is not set @@ -6662,10 +7203,13 @@ CONFIG_TMPFS_XATTR=y # CONFIG_TRACE_EVENT_INJECT is not set CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_TRACE_MMIO_ACCESS is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_TRACING_EVENTS_GPIO is not set CONFIG_TRACING_SUPPORT=y CONFIG_TRAD_SIGNALS=y # CONFIG_TRANSPARENT_HUGEPAGE is not set # CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set # CONFIG_TRIM_UNUSED_KSYMS is not set # CONFIG_TRUSTED_FOUNDATIONS is not set # CONFIG_TRUSTED_KEYS is not set @@ -6675,6 +7219,7 @@ CONFIG_TRAD_SIGNALS=y # CONFIG_TSL2583 is not set # CONFIG_TSL2591 is not set # CONFIG_TSL2772 is not set +# CONFIG_TSL2x7x is not set # CONFIG_TSL4531 is not set # CONFIG_TSNEP is not set # CONFIG_TSYS01 is not set @@ -6699,6 +7244,7 @@ CONFIG_TTY=y # CONFIG_UBIFS_ATIME_SUPPORT is not set # CONFIG_UBIFS_FS_ADVANCED_COMPR is not set # CONFIG_UBIFS_FS_AUTHENTICATION is not set +# CONFIG_UBIFS_FS_ENCRYPTION is not set CONFIG_UBIFS_FS_LZO=y # CONFIG_UBIFS_FS_SECURITY is not set CONFIG_UBIFS_FS_XATTR=y @@ -6709,8 +7255,11 @@ CONFIG_UBSAN_ALIGNMENT=y CONFIG_UBSAN_BOOL=y # CONFIG_UBSAN_DIV_ZERO is not set CONFIG_UBSAN_ENUM=y +# CONFIG_UBSAN_MISC is not set CONFIG_UBSAN_SHIFT=y # CONFIG_UBSAN_UNREACHABLE is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_UCSI is not set # CONFIG_UDF_FS is not set # CONFIG_UDMABUF is not set CONFIG_UEVENT_HELPER=y @@ -6723,11 +7272,15 @@ CONFIG_UID16=y # CONFIG_ULTRA is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_UNICODE is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_UNISYS_VISORBUS is not set CONFIG_UNIX=y CONFIG_UNIX98_PTYS=y # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_UNIX_DIAG is not set CONFIG_UNIX_SCM=y +# CONFIG_UNUSED_BOARD_FILES is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_UNWINDER_FRAME_POINTER is not set # CONFIG_UPROBES is not set # CONFIG_UPROBE_EVENTS is not set @@ -6760,8 +7313,8 @@ CONFIG_USB_BELKIN=y # CONFIG_USB_CDNS3 is not set # CONFIG_USB_CDNS3_IMX is not set # CONFIG_USB_CDNS3_PCI_WRAP is not set -# CONFIG_USB_CDNS_SUPPORT is not set # CONFIG_USB_CDNSP_PCI is not set +# CONFIG_USB_CDNS_SUPPORT is not set # CONFIG_USB_CHAOSKEY is not set # CONFIG_USB_CHIPIDEA is not set # CONFIG_USB_CHIPIDEA_GENERIC is not set @@ -6793,11 +7346,13 @@ CONFIG_USB_DEFAULT_PERSIST=y # CONFIG_USB_DWC3_ULPI is not set # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_ATH79 is not set # CONFIG_USB_EHCI_FSL is not set # CONFIG_USB_EHCI_HCD is not set # CONFIG_USB_EHCI_HCD_AT91 is not set # CONFIG_USB_EHCI_HCD_OMAP is not set # CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set # CONFIG_USB_EHCI_MV is not set CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y @@ -6811,6 +7366,7 @@ CONFIG_USB_EHCI_TT_NEWSCHED=y # CONFIG_USB_FOTG210_HCD is not set # CONFIG_USB_FOTG210_UDC is not set # CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_FUNCTIONFS is not set # CONFIG_USB_FUSB300 is not set # CONFIG_USB_GADGET is not set @@ -6889,7 +7445,9 @@ CONFIG_USB_GADGET_VBUS_DRAW=2 # CONFIG_USB_HSIC_USB4604 is not set # CONFIG_USB_HSO is not set # CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HWA_HCD is not set # CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_IMX21_HCD is not set # CONFIG_USB_IOWARRIOR is not set # CONFIG_USB_IPHETH is not set # CONFIG_USB_ISIGHTFW is not set @@ -6904,6 +7462,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=2 # CONFIG_USB_LAN78XX is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set # CONFIG_USB_LEDS_TRIGGER_USBPORT is not set # CONFIG_USB_LED_TRIG is not set # CONFIG_USB_LEGOTOWER is not set @@ -6920,6 +7479,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=2 # CONFIG_USB_MON is not set # CONFIG_USB_MOUSE is not set # CONFIG_USB_MSI2500 is not set +# CONFIG_USB_MSM_OTG is not set # CONFIG_USB_MTU3 is not set # CONFIG_USB_MUSB_GADGET is not set # CONFIG_USB_MUSB_HDRC is not set @@ -6965,9 +7525,11 @@ CONFIG_USB_GADGET_VBUS_DRAW=2 CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_ONBOARD_HUB is not set # CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set # CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set # CONFIG_USB_OTG_FSM is not set # CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_WHITELIST is not set # CONFIG_USB_OXU210HP_HCD is not set # CONFIG_USB_PCI is not set # CONFIG_USB_PEGASUS is not set @@ -6979,7 +7541,9 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_R8A66597 is not set # CONFIG_USB_R8A66597_HCD is not set # CONFIG_USB_RAW_GADGET is not set +# CONFIG_USB_RCAR_PHY is not set # CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set # CONFIG_USB_ROLES_INTEL_XHCI is not set # CONFIG_USB_ROLE_SWITCH is not set # CONFIG_USB_RTL8150 is not set @@ -7009,7 +7573,19 @@ CONFIG_USB_SERIAL_GENERIC=y # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_IUU is not set # CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y # CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_KOBIL_SCT is not set # CONFIG_USB_SERIAL_MCT_U232 is not set @@ -7039,6 +7615,7 @@ CONFIG_USB_SERIAL_SAFE_PADDED=y # CONFIG_USB_SERIAL_VISOR is not set # CONFIG_USB_SERIAL_WHITEHEAT is not set # CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_XR is not set # CONFIG_USB_SERIAL_XSENS_MT is not set # CONFIG_USB_SEVSEG is not set @@ -7047,6 +7624,7 @@ CONFIG_USB_SERIAL_SAFE_PADDED=y # CONFIG_USB_SL811_HCD is not set # CONFIG_USB_SNP_UDC_PLAT is not set # CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_ALAUDA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set @@ -7064,6 +7642,7 @@ CONFIG_USB_SERIAL_SAFE_PADDED=y # CONFIG_USB_STORAGE_USBAT is not set # CONFIG_USB_STV06XX is not set # CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SWITCH_FSA9480 is not set # CONFIG_USB_TEST is not set # CONFIG_USB_TMC is not set # CONFIG_USB_TRANCEVIBRATOR is not set @@ -7077,6 +7656,9 @@ CONFIG_USB_SERIAL_SAFE_PADDED=y CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USB_VL600 is not set # CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set # CONFIG_USB_XEN_HCD is not set # CONFIG_USB_XHCI_DBGCAP is not set # CONFIG_USB_XHCI_HCD is not set @@ -7086,6 +7668,7 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USB_YUREX is not set # CONFIG_USB_ZD1201 is not set # CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set # CONFIG_USELIB is not set # CONFIG_USERFAULTFD is not set # CONFIG_USERIO is not set @@ -7093,6 +7676,7 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USER_EVENTS is not set # CONFIG_USE_OF is not set # CONFIG_UTS_NS is not set +# CONFIG_UWB is not set # CONFIG_U_SERIAL_CONSOLE is not set # CONFIG_V4L_MEM2MEM_DRIVERS is not set # CONFIG_V4L_PLATFORM_DRIVERS is not set @@ -7126,7 +7710,9 @@ CONFIG_VHOST_MENU=y # CONFIG_VHOST_VSOCK is not set # CONFIG_VIA_RHINE is not set # CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_AD5398 is not set # CONFIG_VIDEO_AD5820 is not set +# CONFIG_VIDEO_AD9389B is not set # CONFIG_VIDEO_ADP1653 is not set # CONFIG_VIDEO_ADV7170 is not set # CONFIG_VIDEO_ADV7175 is not set @@ -7143,15 +7729,20 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_AK881X is not set # CONFIG_VIDEO_AM437X_VPFE is not set # CONFIG_VIDEO_AR0521 is not set +# CONFIG_VIDEO_ARDUCAM_64MP is not set +# CONFIG_VIDEO_ARDUCAM_PIVARIETY is not set # CONFIG_VIDEO_ASPEED is not set # CONFIG_VIDEO_ATMEL_ISC is not set # CONFIG_VIDEO_ATMEL_ISI is not set # CONFIG_VIDEO_AU0828 is not set # CONFIG_VIDEO_BCM2835 is not set +# CONFIG_VIDEO_BCM2835_UNICAM is not set # CONFIG_VIDEO_BT819 is not set # CONFIG_VIDEO_BT848 is not set # CONFIG_VIDEO_BT856 is not set # CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_BU64754 is not set +# CONFIG_VIDEO_CADENCE is not set # CONFIG_VIDEO_CADENCE_CSI2RX is not set # CONFIG_VIDEO_CADENCE_CSI2TX is not set # CONFIG_VIDEO_CAFE_CCIC is not set @@ -7159,6 +7750,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_CCS is not set # CONFIG_VIDEO_COBALT is not set # CONFIG_VIDEO_CODA is not set +# CONFIG_VIDEO_CODEC_BCM2835 is not set # CONFIG_VIDEO_CS3308 is not set # CONFIG_VIDEO_CS5345 is not set # CONFIG_VIDEO_CS53L32A is not set @@ -7168,6 +7760,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_CX25840 is not set # CONFIG_VIDEO_CX88 is not set # CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set # CONFIG_VIDEO_DS90UB913 is not set # CONFIG_VIDEO_DS90UB953 is not set # CONFIG_VIDEO_DS90UB960 is not set @@ -7200,38 +7793,45 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_IMX335 is not set # CONFIG_VIDEO_IMX355 is not set # CONFIG_VIDEO_IMX412 is not set -# CONFIG_VIDEO_IMX7_CSI is not set -# CONFIG_VIDEO_IMX8MQ_MIPI_CSI2 is not set -# CONFIG_VIDEO_IMX8_ISI is not set +# CONFIG_VIDEO_IMX477 is not set +# CONFIG_VIDEO_IMX519 is not set +# CONFIG_VIDEO_IMX708 is not set # CONFIG_VIDEO_IMX8_JPEG is not set # CONFIG_VIDEO_IMX_MIPI_CSIS is not set # CONFIG_VIDEO_IMX_PXP is not set +# CONFIG_VIDEO_IRS1125 is not set # CONFIG_VIDEO_IR_I2C is not set # CONFIG_VIDEO_ISL7998X is not set +# CONFIG_VIDEO_ISP_BCM2835 is not set # CONFIG_VIDEO_IVTV is not set # CONFIG_VIDEO_KS0127 is not set # CONFIG_VIDEO_LM3560 is not set # CONFIG_VIDEO_LM3646 is not set # CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_M5MOLS is not set # CONFIG_VIDEO_MAX9286 is not set # CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set # CONFIG_VIDEO_ML86V7667 is not set # CONFIG_VIDEO_MSP3400 is not set # CONFIG_VIDEO_MT9M001 is not set +# CONFIG_VIDEO_MT9M032 is not set # CONFIG_VIDEO_MT9M111 is not set # CONFIG_VIDEO_MT9P031 is not set +# CONFIG_VIDEO_MT9T001 is not set # CONFIG_VIDEO_MT9T112 is not set # CONFIG_VIDEO_MT9V011 is not set # CONFIG_VIDEO_MT9V032 is not set # CONFIG_VIDEO_MT9V111 is not set # CONFIG_VIDEO_MUX is not set # CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set # CONFIG_VIDEO_OG01A1B is not set # CONFIG_VIDEO_OMAP2_VOUT is not set # CONFIG_VIDEO_OV02A10 is not set # CONFIG_VIDEO_OV08D10 is not set # CONFIG_VIDEO_OV13858 is not set # CONFIG_VIDEO_OV13B10 is not set +# CONFIG_VIDEO_OV2311 is not set # CONFIG_VIDEO_OV2640 is not set # CONFIG_VIDEO_OV2659 is not set # CONFIG_VIDEO_OV2680 is not set @@ -7245,6 +7845,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_OV5675 is not set # CONFIG_VIDEO_OV5693 is not set # CONFIG_VIDEO_OV5695 is not set +# CONFIG_VIDEO_OV64A40 is not set # CONFIG_VIDEO_OV6650 is not set # CONFIG_VIDEO_OV7251 is not set # CONFIG_VIDEO_OV7640 is not set @@ -7253,11 +7854,13 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_OV7740 is not set # CONFIG_VIDEO_OV8856 is not set # CONFIG_VIDEO_OV8865 is not set +# CONFIG_VIDEO_OV9281 is not set # CONFIG_VIDEO_OV9282 is not set # CONFIG_VIDEO_OV9640 is not set # CONFIG_VIDEO_OV9650 is not set # CONFIG_VIDEO_OV9734 is not set # CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_RASPBERRYPI_PISP_BE is not set # CONFIG_VIDEO_RCAR_CSI2 is not set # CONFIG_VIDEO_RCAR_ISP is not set # CONFIG_VIDEO_RCAR_VIN is not set @@ -7265,9 +7868,12 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_RDACM21 is not set # CONFIG_VIDEO_RJ54N1 is not set # CONFIG_VIDEO_ROCKCHIP_ISP1 is not set +# CONFIG_VIDEO_RP1_CFE is not set # CONFIG_VIDEO_S5C73M3 is not set +# CONFIG_VIDEO_S5K4ECGX is not set # CONFIG_VIDEO_S5K5BAF is not set # CONFIG_VIDEO_S5K6A3 is not set +# CONFIG_VIDEO_S5K6AA is not set # CONFIG_VIDEO_SAA6588 is not set # CONFIG_VIDEO_SAA6752HS is not set # CONFIG_VIDEO_SAA7110 is not set @@ -7277,9 +7883,13 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_SAA7164 is not set # CONFIG_VIDEO_SAA717X is not set # CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SMIAPP is not set # CONFIG_VIDEO_SOLO6X10 is not set # CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set # CONFIG_VIDEO_STK1160 is not set +# CONFIG_VIDEO_STK1160_COMMON is not set # CONFIG_VIDEO_ST_MIPID02 is not set # CONFIG_VIDEO_SUN4I_CSI is not set # CONFIG_VIDEO_SUN6I_CSI is not set @@ -7293,7 +7903,9 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_TEA6420 is not set # CONFIG_VIDEO_THS7303 is not set # CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set # CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set # CONFIG_VIDEO_TVAUDIO is not set # CONFIG_VIDEO_TVP514X is not set # CONFIG_VIDEO_TVP5150 is not set @@ -7308,13 +7920,17 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_UPD64031A is not set # CONFIG_VIDEO_UPD64083 is not set # CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set # CONFIG_VIDEO_VP27SMPX is not set # CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set # CONFIG_VIDEO_WM8739 is not set # CONFIG_VIDEO_WM8775 is not set # CONFIG_VIDEO_XILINX is not set # CONFIG_VIDEO_ZORAN is not set # CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_BLK_SCSI is not set # CONFIG_VIRTIO_CONSOLE is not set # CONFIG_VIRTIO_FS is not set # CONFIG_VIRTIO_INPUT is not set @@ -7325,6 +7941,7 @@ CONFIG_VIRTIO_MENU=y # CONFIG_VIRTUALIZATION is not set # CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set # CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y # CONFIG_VITESSE_PHY is not set # CONFIG_VL53L0X_I2C is not set # CONFIG_VL6180 is not set @@ -7343,6 +7960,7 @@ CONFIG_VMSPLIT_3G=y # CONFIG_VMWARE_VMCI is not set # CONFIG_VMXNET3 is not set # CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VOP_BUS is not set # CONFIG_VORTEX is not set # CONFIG_VSOCKETS is not set # CONFIG_VSOCKETS_DIAG is not set @@ -7350,10 +7968,12 @@ CONFIG_VMSPLIT_3G=y # CONFIG_VT6655 is not set # CONFIG_VT6656 is not set # CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set # CONFIG_VXLAN is not set # CONFIG_VZ89X is not set # CONFIG_W1 is not set # CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set # CONFIG_W1_MASTER_DS2482 is not set # CONFIG_W1_MASTER_DS2490 is not set # CONFIG_W1_MASTER_GPIO is not set @@ -7395,13 +8015,16 @@ CONFIG_WATCHDOG_OPEN_TIMEOUT=0 # CONFIG_WDAT_WDT is not set # CONFIG_WDTPCI is not set # CONFIG_WERROR is not set -# CONFIG_WEXT_CORE is not set -# CONFIG_WEXT_PRIV is not set -# CONFIG_WEXT_PROC is not set -# CONFIG_WEXT_SPY is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set # CONFIG_WIREGUARD is not set CONFIG_WIRELESS=y -# CONFIG_WIRELESS_EXT is not set +CONFIG_WIRELESS_EXT=y +# CONFIG_WIRELESS_WDS is not set # CONFIG_WIZNET_W5100 is not set # CONFIG_WIZNET_W5300 is not set # CONFIG_WL1251 is not set @@ -7438,6 +8061,7 @@ CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y # CONFIG_X25 is not set # CONFIG_X509_CERTIFICATE_PARSER is not set # CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y # CONFIG_X9250 is not set # CONFIG_XDP_SOCKETS is not set # CONFIG_XEN is not set @@ -7522,3 +8146,4 @@ CONFIG_ZONE_DMA=y # CONFIG_ZSMALLOC is not set CONFIG_ZSMALLOC_CHAIN_SIZE=8 # CONFIG_ZSWAP is not set +# CONFIG_ZX_TDM is not set diff --git a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig index 17d590890d..794a39f2c3 100644 --- a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig +++ b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig @@ -12,6 +12,7 @@ config MTD_SPLIT_SQUASHFS_ROOT bool "Squashfs based root partition parser" depends on MTD_SPLIT_SUPPORT select MTD_SPLIT + default n help This provides a parsing function which allows to detect the offset and size of the unused portion of a rootfs partition @@ -31,7 +32,7 @@ config MTD_SPLIT_BCM_WFI_FW config MTD_SPLIT_CFE_BOOTFS bool "Parser finding rootfs appended to the CFE bootfs" - depends on MTD_SPLIT_SUPPORT && (ARCH_BCM4908 || ARCH_BCMBCA) + depends on MTD_SPLIT_SUPPORT && ARCH_BCM4908 select MTD_SPLIT help cferom on BCM4908 (and bcm63xx) uses JFFS2 bootfs partition @@ -100,13 +101,3 @@ config MTD_SPLIT_ELF_FW bool "ELF loader firmware partition parser" depends on MTD_SPLIT_SUPPORT select MTD_SPLIT - -config MTD_SPLIT_H3C_VFS - bool "Parser finding rootfs appended to H3C VFS" - depends on MTD_SPLIT_SUPPORT - select MTD_SPLIT - -config MTD_SPLIT_SEIL_FW - bool "IIJ SEIL firmware parser" - depends on MTD_SPLIT_SUPPORT - select MTD_SPLIT diff --git a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile index e9d63c8332..1461099b7c 100644 --- a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile +++ b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile @@ -3,7 +3,6 @@ obj-$(CONFIG_MTD_SPLIT_BCM63XX_FW) += mtdsplit_bcm63xx.o obj-$(CONFIG_MTD_SPLIT_BCM_WFI_FW) += mtdsplit_bcm_wfi.o obj-$(CONFIG_MTD_SPLIT_CFE_BOOTFS) += mtdsplit_cfe_bootfs.o obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o -obj-$(CONFIG_MTD_SPLIT_SEIL_FW) += mtdsplit_seil.o obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o obj-$(CONFIG_MTD_SPLIT_FIT_FW) += mtdsplit_fit.o @@ -16,4 +15,3 @@ obj-$(CONFIG_MTD_SPLIT_WRGG_FW) += mtdsplit_wrgg.o obj-$(CONFIG_MTD_SPLIT_MINOR_FW) += mtdsplit_minor.o obj-$(CONFIG_MTD_SPLIT_JIMAGE_FW) += mtdsplit_jimage.o obj-$(CONFIG_MTD_SPLIT_ELF_FW) += mtdsplit_elf.o -obj-$(CONFIG_MTD_SPLIT_H3C_VFS) += mtdsplit_h3c_vfs.o diff --git a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c index 1cafc91fde..1ddcf6745f 100644 --- a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c +++ b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c @@ -31,7 +31,6 @@ #define CFERAM_NAME "cferam" #define CFERAM_NAME_LEN (sizeof(CFERAM_NAME) - 1) -#define CFERAM_NAME_MAX_LEN 32 #define KERNEL_NAME "vmlinux.lz" #define KERNEL_NAME_LEN (sizeof(KERNEL_NAME) - 1) #define OPENWRT_NAME "1-openwrt" @@ -158,28 +157,17 @@ static int parse_bcm_wfi(struct mtd_info *master, const struct mtd_partition **pparts, uint8_t *buf, loff_t off, loff_t size, bool cfe_part) { - struct device_node *mtd_node; struct mtd_partition *parts; loff_t cfe_off, kernel_off, rootfs_off; unsigned int num_parts = BCM_WFI_PARTS, cur_part = 0; - const char *cferam_name = CFERAM_NAME; - size_t cferam_name_len; int ret; - mtd_node = mtd_get_of_node(master); - if (mtd_node) - of_property_read_string(mtd_node, "brcm,cferam", &cferam_name); - - cferam_name_len = strnlen(cferam_name, CFERAM_NAME_MAX_LEN); - if (cferam_name_len > 0) - cferam_name_len--; - if (cfe_part) { num_parts++; cfe_off = off; - ret = jffs2_find_file(master, buf, cferam_name, - cferam_name_len, &cfe_off, + ret = jffs2_find_file(master, buf, CFERAM_NAME, + CFERAM_NAME_LEN, &cfe_off, size - (cfe_off - off), NULL, NULL); if (ret) return ret; diff --git a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c index 3b71597d23..3230d859b0 100644 --- a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c +++ b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c @@ -199,7 +199,6 @@ mtdsplit_fit_parse(struct mtd_info *mtd, struct fdt_header hdr; size_t hdr_len, retlen; size_t offset; - u32 offset_start = 0; size_t fit_offset, fit_size; size_t rootfs_offset, rootfs_size; size_t data_size, img_total, max_size = 0; @@ -212,13 +211,11 @@ mtdsplit_fit_parse(struct mtd_info *mtd, if (cmdline_match && !strstr(saved_command_line, cmdline_match)) return -ENODEV; - of_property_read_u32(np, "openwrt,fit-offset", &offset_start); - hdr_len = sizeof(struct fdt_header); /* Parse the MTD device & search for the FIT image location */ for(offset = 0; offset + hdr_len <= mtd->size; offset += mtd->erasesize) { - ret = mtd_read(mtd, offset + offset_start, hdr_len, &retlen, (void*) &hdr); + ret = mtd_read(mtd, offset, hdr_len, &retlen, (void*) &hdr); if (ret) { pr_err("read error in \"%s\" at offset 0x%llx\n", mtd->name, (unsigned long long) offset); @@ -259,11 +256,9 @@ mtdsplit_fit_parse(struct mtd_info *mtd, * last external data refernced. */ if (fit_size > 0x1000) { - enum mtdsplit_part_type type; - /* Search for the rootfs partition after the FIT image */ - ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size + offset_start, mtd->size, - &rootfs_offset, &type); + ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size, mtd->size, + &rootfs_offset, NULL); if (ret) { pr_info("no rootfs found after FIT image in \"%s\"\n", mtd->name); @@ -278,12 +273,9 @@ mtdsplit_fit_parse(struct mtd_info *mtd, parts[0].name = KERNEL_PART_NAME; parts[0].offset = fit_offset; - parts[0].size = mtd_rounddown_to_eb(fit_size + offset_start, mtd) + mtd->erasesize; + parts[0].size = mtd_rounddown_to_eb(fit_size, mtd) + mtd->erasesize; - if (type == MTDSPLIT_PART_TYPE_UBI) - parts[1].name = UBI_PART_NAME; - else - parts[1].name = ROOTFS_PART_NAME; + parts[1].name = ROOTFS_PART_NAME; parts[1].offset = rootfs_offset; parts[1].size = rootfs_size; @@ -293,7 +285,7 @@ mtdsplit_fit_parse(struct mtd_info *mtd, } else { /* Search for rootfs_data after FIT external data */ fit = kzalloc(fit_size, GFP_KERNEL); - ret = mtd_read(mtd, offset, fit_size + offset_start, &retlen, fit); + ret = mtd_read(mtd, offset, fit_size, &retlen, fit); if (ret) { pr_err("read error in \"%s\" at offset 0x%llx\n", mtd->name, (unsigned long long) offset); diff --git a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c deleted file mode 100644 index f264233dbd..0000000000 --- a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c +++ /dev/null @@ -1,170 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Some devices made by H3C use a "VFS" filesystem to store firmware images. - * This parses the start of the filesystem to read the length of the first - * file (the kernel image). It then searches for the rootfs after the end of - * the file data. This driver assumes that the filesystem was generated by - * mkh3cvfs, and only works if the filesystem matches the expected layout, - * which includes the file name of the kernel image. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "mtdsplit.h" - -#define VFS_ERASEBLOCK_SIZE 0x10000 -#define VFS_BLOCK_SIZE 0x400 -#define VFS_BLOCKS_PER_ERASEBLOCK (VFS_ERASEBLOCK_SIZE / VFS_BLOCK_SIZE) - -#define FORMAT_FLAG_OFFSET 0x0 - -#define FORMAT_FLAG (VFS_ERASEBLOCK_SIZE << 12 | VFS_BLOCK_SIZE) - -#define FILE_ENTRY_OFFSET 0x800 - -#define FILE_ENTRY_FLAGS 0x3f -#define FILE_ENTRY_PARENT_BLOCK 0 -#define FILE_ENTRY_PARENT_INDEX 0 -#define FILE_ENTRY_DATA_BLOCK 2 -#define FILE_ENTRY_NAME "openwrt-kernel.bin" - -#define NR_PARTS 2 - -struct file_entry { - uint8_t flags; - - uint8_t res0[5]; - - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - - uint8_t res1[3]; - - uint32_t length; - - uint32_t parent_block; - uint16_t parent_index; - - uint8_t res2[2]; - - uint32_t data_block; - - char name[96]; -} __attribute__ ((packed)); - -static inline size_t block_offset(int block) -{ - return VFS_ERASEBLOCK_SIZE * (block / (VFS_BLOCKS_PER_ERASEBLOCK-1)) - + VFS_BLOCK_SIZE * (1 + (block % (VFS_BLOCKS_PER_ERASEBLOCK-1))); -} - -static inline int block_count(size_t size) -{ - return (size + VFS_BLOCK_SIZE - 1) / VFS_BLOCK_SIZE; -} - -static int mtdsplit_h3c_vfs_parse(struct mtd_info *mtd, - const struct mtd_partition **pparts, - struct mtd_part_parser_data *data) -{ - struct mtd_partition *parts; - uint32_t format_flag; - struct file_entry file_entry; - size_t retlen; - int err; - size_t kernel_size; - size_t expected_offset; - size_t rootfs_offset; - - if (mtd->erasesize != VFS_ERASEBLOCK_SIZE) - return -EINVAL; - - /* Check format flag */ - err = mtd_read(mtd, FORMAT_FLAG_OFFSET, sizeof(format_flag), &retlen, - (void *) &format_flag); - if (err) - return err; - - if (retlen != sizeof(format_flag)) - return -EIO; - - if (format_flag != FORMAT_FLAG) - return -EINVAL; - - /* Check file entry */ - err = mtd_read(mtd, FILE_ENTRY_OFFSET, sizeof(file_entry), &retlen, - (void *) &file_entry); - if (err) - return err; - - if (retlen != sizeof(file_entry)) - return -EIO; - - if (file_entry.flags != FILE_ENTRY_FLAGS) - return -EINVAL; - - if (file_entry.parent_block != FILE_ENTRY_PARENT_BLOCK) - return -EINVAL; - - if (file_entry.parent_index != FILE_ENTRY_PARENT_INDEX) - return -EINVAL; - - if (file_entry.data_block != FILE_ENTRY_DATA_BLOCK) - return -EINVAL; - - if (strncmp(file_entry.name, FILE_ENTRY_NAME, sizeof(file_entry.name)) != 0) - return -EINVAL; - - /* Find rootfs offset */ - kernel_size = block_offset(file_entry.data_block + - block_count(file_entry.length) - 1) + - VFS_BLOCK_SIZE; - - expected_offset = mtd_roundup_to_eb(kernel_size, mtd); - - err = mtd_find_rootfs_from(mtd, expected_offset, mtd->size, - &rootfs_offset, NULL); - if (err) - return err; - - parts = kzalloc(NR_PARTS * sizeof(*parts), GFP_KERNEL); - if (!parts) - return -ENOMEM; - - parts[0].name = KERNEL_PART_NAME; - parts[0].offset = 0; - parts[0].size = rootfs_offset; - - parts[1].name = ROOTFS_PART_NAME; - parts[1].offset = rootfs_offset; - parts[1].size = mtd->size - rootfs_offset; - - *pparts = parts; - return NR_PARTS; -} - -static const struct of_device_id mtdsplit_h3c_vfs_of_match_table[] = { - { .compatible = "h3c,vfs-firmware" }, - {}, -}; -MODULE_DEVICE_TABLE(of, mtdsplit_h3c_vfs_of_match_table); - -static struct mtd_part_parser mtdsplit_h3c_vfs_parser = { - .owner = THIS_MODULE, - .name = "h3c-vfs", - .of_match_table = mtdsplit_h3c_vfs_of_match_table, - .parse_fn = mtdsplit_h3c_vfs_parse, - .type = MTD_PARSER_TYPE_FIRMWARE, -}; - -module_mtd_part_parser(mtdsplit_h3c_vfs_parser); diff --git a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seil.c b/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seil.c deleted file mode 100644 index e58bb49b23..0000000000 --- a/lede/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seil.c +++ /dev/null @@ -1,191 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* a mtdsplit driver for IIJ SEIL devices */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mtdsplit.h" - -#define NR_PARTS 2 -#define SEIL_VFMT 1 -#define LDR_ENV_PART_NAME "bootloader-env" -#define LDR_ENV_KEY_BOOTDEV "BOOTDEV" - -struct seil_header { - uint64_t id; /* Identifier */ - uint8_t copy[80]; /* Copyright */ - uint32_t dcrc; /* Data CRC Checksum */ - uint32_t vfmt; /* Image Version Format */ - uint32_t vmjr; /* Image Version Major */ - uint32_t vmnr; /* Image Version Minor */ - uint8_t vrel[32]; /* Image Version Release */ - uint32_t dxor; /* xor value for Data? */ - uint32_t dlen; /* Data Length */ -}; - -/* - * check whether the current mtd device is active or not - * - * example of BOOTDEV value (IIJ SA-W2): - * - "flash" : primary image on flash - * - "rescue" : secondary image on flash - * - "usb" : usb storage - * - "lan0/1" : network - */ -static bool seil_bootdev_is_active(struct device_node *np) -{ - struct mtd_info *env_mtd; - char *buf, *var, *value, *eq; - const char *devnm; - size_t rdlen; - int ret; - - /* - * read bootdev name of the partition - * if doesn't exist, return true and skip checking of active device - */ - ret = of_property_read_string(np, "iij,bootdev-name", &devnm); - if (ret == -EINVAL) - return true; - else if (ret < 0) - return false; - - env_mtd = get_mtd_device_nm(LDR_ENV_PART_NAME); - if (IS_ERR(env_mtd)) { - pr_err("failed to get mtd device \"%s\"", LDR_ENV_PART_NAME); - return false; - } - - buf = vmalloc(env_mtd->size); - if (!buf) - return false; - - ret = mtd_read(env_mtd, 0, env_mtd->size, &rdlen, buf); - if (ret || rdlen != env_mtd->size) { - pr_err("failed to read from mtd (%d)\n", ret); - ret = 0; - goto exit_vfree; - } - - for (var = buf, ret = false; - var < buf + env_mtd->size && *var; - var = value + strlen(value) + 1) { - eq = strchr(var, '='); - if (!eq) - break; - *eq = '\0'; - value = eq + 1; - - pr_debug("ENV: %s=%s\n", var, value); - if (!strcmp(var, LDR_ENV_KEY_BOOTDEV)) { - ret = !strcmp(devnm, value); - break; - } - } - -exit_vfree: - vfree(buf); - - return ret; -} - -static int mtdsplit_parse_seil_fw(struct mtd_info *master, - const struct mtd_partition **pparts, - struct mtd_part_parser_data *data) -{ - struct device_node *np = mtd_get_of_node(master); - struct mtd_partition *parts; - struct seil_header header; - size_t image_size = 0; - size_t rootfs_offset; - size_t hdrlen = sizeof(header); - size_t retlen; - int ret; - u64 id; - - if (!seil_bootdev_is_active(np)) - return -ENODEV; - - ret = of_property_read_u64(np, "iij,seil-id", &id); - if (ret) { - pr_err("failed to get iij,seil-id from dt\n"); - return ret; - } - pr_debug("got seil-id=0x%016llx from dt\n", id); - - parts = kcalloc(NR_PARTS, sizeof(*parts), GFP_KERNEL); - if (!parts) - return -ENOMEM; - - ret = mtd_read(master, 0, hdrlen, &retlen, (void *)&header); - if (ret) - goto err_free_parts; - - if (retlen != hdrlen) { - ret = -EIO; - goto err_free_parts; - } - - if (be64_to_cpu(header.id) != id || - be32_to_cpu(header.vfmt) != SEIL_VFMT) { - pr_debug("no valid seil image found in \"%s\"\n", master->name); - ret = -ENODEV; - goto err_free_parts; - } - - image_size = hdrlen + be32_to_cpu(header.dlen); - if (image_size > master->size) { - pr_err("seil image exceeds MTD device \"%s\"\n", master->name); - ret = -EINVAL; - goto err_free_parts; - } - - /* find the roots after the seil image */ - ret = mtd_find_rootfs_from(master, image_size, - master->size, &rootfs_offset, NULL); - if (ret || (master->size - rootfs_offset) == 0) { - pr_debug("no rootfs after seil image in \"%s\"\n", - master->name); - ret = -ENODEV; - goto err_free_parts; - } - - parts[0].name = KERNEL_PART_NAME; - parts[0].offset = 0; - parts[0].size = rootfs_offset; - - parts[1].name = ROOTFS_PART_NAME; - parts[1].offset = rootfs_offset; - parts[1].size = master->size - rootfs_offset; - - *pparts = parts; - return NR_PARTS; - -err_free_parts: - kfree(parts); - return ret; -} - -static const struct of_device_id mtdsplit_seil_fw_of_match_table[] = { - { .compatible = "iij,seil-firmware" }, - {}, -}; -MODULE_DEVICE_TABLE(of, mtdsplit_seil_fw_of_match_table); - -static struct mtd_part_parser mtdsplit_seil_fw_parser = { - .owner = THIS_MODULE, - .name = "seil-fw", - .of_match_table = mtdsplit_seil_fw_of_match_table, - .parse_fn = mtdsplit_parse_seil_fw, - .type = MTD_PARSER_TYPE_FIRMWARE, -}; - -module_mtd_part_parser(mtdsplit_seil_fw_parser); diff --git a/lede/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.h b/lede/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.h index 517ff7414f..dff1f28c81 100644 --- a/lede/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.h +++ b/lede/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.h @@ -95,14 +95,8 @@ bbt_nand_read(u32 page, unsigned char *dat, int dat_len, .datbuf = dat, .len = dat_len, }; - int ret; - ret = bmtd._read_oob(bmtd.mtd, page << bmtd.pg_shift, &ops); - if (ret < 0) - return ret; - if (ret) - pr_info("%s: %d bitflips\n", __func__, ret); - return 0; + return bmtd._read_oob(bmtd.mtd, page << bmtd.pg_shift, &ops); } static inline int bbt_nand_erase(u16 block) diff --git a/lede/target/linux/generic/files/drivers/mtd/nand/mtk_bmt_v2.c b/lede/target/linux/generic/files/drivers/mtd/nand/mtk_bmt_v2.c index 6b06948c0f..2770376e98 100644 --- a/lede/target/linux/generic/files/drivers/mtd/nand/mtk_bmt_v2.c +++ b/lede/target/linux/generic/files/drivers/mtd/nand/mtk_bmt_v2.c @@ -191,6 +191,36 @@ static u16 get_bmt_index(struct bbmt *bmt) return 0; } +static int +read_bmt(u16 block, unsigned char *dat, unsigned char *fdm, int fdm_len) +{ + u32 len = bmtd.bmt_pgs << bmtd.pg_shift; + + return bbt_nand_read(blk_pg(block), dat, len, fdm, fdm_len); +} + +static struct bbbt *scan_bmt(u16 block) +{ + u8 fdm[4]; + + if (block < bmtd.pool_lba) + return NULL; + + if (read_bmt(block, bmtd.bbt_buf, fdm, sizeof(fdm))) + return scan_bmt(block - 1); + + if (is_valid_bmt(bmtd.bbt_buf, fdm)) { + bmtd.bmt_blk_idx = get_bmt_index(bmt_tbl((struct bbbt *)bmtd.bbt_buf)); + if (bmtd.bmt_blk_idx == 0) { + pr_info("[BBT] FATAL ERR: bmt block index is wrong!\n"); + return NULL; + } + pr_info("[BBT] BMT.v2 is found at 0x%x\n", block); + return (struct bbbt *)bmtd.bbt_buf; + } else + return scan_bmt(block - 1); +} + /* Write the Burner Bad Block Table to Nand Flash * n - write BMT to bmt_tbl[n] */ @@ -442,30 +472,7 @@ static int mtk_bmt_init_v2(struct device_node *np) /* Scanning start from the first page of the last block * of whole flash */ - bmtd.bbt = NULL; - for (u16 block = bmtd.total_blks - 1; !bmtd.bbt && block >= bmtd.pool_lba; block--) { - u8 fdm[4]; - - if (bbt_nand_read(blk_pg(block), bmtd.bbt_buf, bufsz, fdm, sizeof(fdm))) { - /* Read failed, try the previous block */ - continue; - } - - if (!is_valid_bmt(bmtd.bbt_buf, fdm)) { - /* No valid BMT found, try the previous block */ - continue; - } - - bmtd.bmt_blk_idx = get_bmt_index(bmt_tbl((struct bbbt *)bmtd.bbt_buf)); - if (bmtd.bmt_blk_idx == 0) { - pr_info("[BBT] FATAL ERR: bmt block index is wrong!\n"); - break; - } - - pr_info("[BBT] BMT.v2 is found at 0x%x\n", block); - bmtd.bbt = (struct bbbt *)bmtd.bbt_buf; - } - + bmtd.bbt = scan_bmt(bmtd.total_blks - 1); if (!bmtd.bbt) { /* BMT not found */ if (bmtd.total_blks > BB_TABLE_MAX + BMT_TABLE_MAX) { diff --git a/lede/target/linux/generic/files/drivers/mtd/parsers/routerbootpart.c b/lede/target/linux/generic/files/drivers/mtd/parsers/routerbootpart.c index aa786cd895..f9bba0f3ba 100644 --- a/lede/target/linux/generic/files/drivers/mtd/parsers/routerbootpart.c +++ b/lede/target/linux/generic/files/drivers/mtd/parsers/routerbootpart.c @@ -167,7 +167,7 @@ static void routerboot_find_dynparts(struct mtd_info *master) while (offset < master->size) { err = mtd_read(master, offset, sizeof(buf), &bytes_read, (u8 *)&buf); if (err) { - pr_err("%s: mtd_read error while parsing (offset: 0x%zX): %d\n", + pr_err("%s: mtd_read error while parsing (offset: 0x%X): %d\n", master->name, offset, err); continue; } diff --git a/lede/target/linux/generic/files/drivers/net/phy/ar8216.c b/lede/target/linux/generic/files/drivers/net/phy/ar8216.c index 850bcefb74..11cb18e4f3 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/lede/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -891,7 +891,11 @@ ar8216_phy_write(struct ar8xxx_priv *priv, int addr, int regnum, u16 val) static int ar8229_hw_init(struct ar8xxx_priv *priv) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) phy_interface_t phy_if_mode; +#else + int phy_if_mode; +#endif if (priv->initialized) return 0; @@ -899,7 +903,11 @@ ar8229_hw_init(struct ar8xxx_priv *priv) ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) of_get_phy_mode(priv->pdev->of_node, &phy_if_mode); +#else + phy_if_mode = of_get_phy_mode(priv->pdev->of_node); +#endif if (phy_if_mode == PHY_INTERFACE_MODE_GMII) { ar8xxx_write(priv, AR8229_REG_OPER_MODE0, @@ -1419,7 +1427,8 @@ ar8xxx_sw_reset_switch(struct switch_dev *dev) int i; mutex_lock(&priv->reg_mutex); - memset(&priv->ar8xxx_priv_volatile, 0, sizeof(priv->ar8xxx_priv_volatile)); + memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) - + offsetof(struct ar8xxx_priv, vlan)); for (i = 0; i < dev->vlans; i++) priv->vlan_id[i] = i; @@ -2424,9 +2433,7 @@ static int ar8xxx_phy_config_init(struct phy_device *phydev) { struct ar8xxx_priv *priv = phydev->priv; -#ifdef CONFIG_ETHERNET_PACKET_MANGLE struct net_device *dev = phydev->attached_dev; -#endif int ret; if (WARN_ON(!priv)) @@ -2458,11 +2465,7 @@ ar8xxx_phy_config_init(struct phy_device *phydev) /* VID fixup only needed on ar8216 */ if (chip_is_ar8216(priv)) { dev->phy_ptr = priv; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) dev->priv_flags |= IFF_NO_IP_ALIGN; -#else - dev->extra_priv_flags |= IFF_NO_IP_ALIGN; -#endif dev->eth_mangle_rx = ar8216_mangle_rx; dev->eth_mangle_tx = ar8216_mangle_tx; } @@ -2697,11 +2700,7 @@ ar8xxx_phy_detach(struct phy_device *phydev) #ifdef CONFIG_ETHERNET_PACKET_MANGLE dev->phy_ptr = NULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) dev->priv_flags &= ~IFF_NO_IP_ALIGN; -#else - dev->extra_priv_flags &= ~IFF_NO_IP_ALIGN; -#endif dev->eth_mangle_rx = NULL; dev->eth_mangle_tx = NULL; #endif diff --git a/lede/target/linux/generic/files/drivers/net/phy/ar8216.h b/lede/target/linux/generic/files/drivers/net/phy/ar8216.h index f046b35f43..d62cf60f57 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/ar8216.h +++ b/lede/target/linux/generic/files/drivers/net/phy/ar8216.h @@ -506,22 +506,20 @@ struct ar8xxx_priv { unsigned int use_count; /* all fields below are cleared on reset */ - struct_group(ar8xxx_priv_volatile, - bool vlan; + bool vlan; - u16 vlan_id[AR8XXX_MAX_VLANS]; - u8 vlan_table[AR8XXX_MAX_VLANS]; - u8 vlan_tagged; - u16 pvid[AR8X16_MAX_PORTS]; - int arl_age_time; + u16 vlan_id[AR8XXX_MAX_VLANS]; + u8 vlan_table[AR8XXX_MAX_VLANS]; + u8 vlan_tagged; + u16 pvid[AR8X16_MAX_PORTS]; + int arl_age_time; - /* mirroring */ - bool mirror_rx; - bool mirror_tx; - int source_port; - int monitor_port; - u8 port_vlan_prio[AR8X16_MAX_PORTS]; - ); + /* mirroring */ + bool mirror_rx; + bool mirror_tx; + int source_port; + int monitor_port; + u8 port_vlan_prio[AR8X16_MAX_PORTS]; }; u32 diff --git a/lede/target/linux/generic/files/drivers/net/phy/ar8327.c b/lede/target/linux/generic/files/drivers/net/phy/ar8327.c index 3313149559..dce52ce0e4 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/ar8327.c +++ b/lede/target/linux/generic/files/drivers/net/phy/ar8327.c @@ -183,7 +183,7 @@ ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy) case 2: ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c, 0x0); - fallthrough; + /* fallthrough */ case 4: ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d, 0x803f); ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860); diff --git a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_common.c b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_common.c index d5f9bfc2f0..a6dab255cc 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_common.c +++ b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_common.c @@ -506,9 +506,15 @@ static int b53_configure_ports_of(struct b53_device *dev) if (fixed_link) { u32 spd; u8 po = GMII_PO_LINK; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) phy_interface_t mode; +#else + int mode = of_get_phy_mode(pn); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) of_get_phy_mode(pn, &mode); +#endif if (!of_property_read_u32(fixed_link, "speed", &spd)) { switch (spd) { @@ -523,7 +529,7 @@ static int b53_configure_ports_of(struct b53_device *dev) po |= PORT_OVERRIDE_SPEED_2000M; else po |= GMII_PO_SPEED_2000M; - fallthrough; + __attribute__((__fallthrough__)); case 1000: po |= GMII_PO_SPEED_1000M; break; @@ -1611,8 +1617,8 @@ static int b53_switch_init(struct b53_device *dev) return b53_switch_reset(dev); } -struct b53_device *b53_swconfig_switch_alloc(struct device *base, struct b53_io_ops *ops, - void *priv) +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv) { struct b53_device *dev; @@ -1627,9 +1633,9 @@ struct b53_device *b53_swconfig_switch_alloc(struct device *base, struct b53_io_ return dev; } -EXPORT_SYMBOL(b53_swconfig_switch_alloc); +EXPORT_SYMBOL(b53_switch_alloc); -int b53_swconfig_switch_detect(struct b53_device *dev) +int b53_switch_detect(struct b53_device *dev) { u32 id32; u16 tmp; @@ -1694,9 +1700,9 @@ int b53_swconfig_switch_detect(struct b53_device *dev) return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, &dev->core_rev); } -EXPORT_SYMBOL(b53_swconfig_switch_detect); +EXPORT_SYMBOL(b53_switch_detect); -int b53_swconfig_switch_register(struct b53_device *dev) +int b53_switch_register(struct b53_device *dev) { int ret; @@ -1706,7 +1712,7 @@ int b53_swconfig_switch_register(struct b53_device *dev) dev->sw_dev.alias = dev->pdata->alias; } - if (!dev->chip_id && b53_swconfig_switch_detect(dev)) + if (!dev->chip_id && b53_switch_detect(dev)) return -EINVAL; ret = b53_switch_init(dev); @@ -1717,7 +1723,7 @@ int b53_swconfig_switch_register(struct b53_device *dev) return register_switch(&dev->sw_dev, NULL); } -EXPORT_SYMBOL(b53_swconfig_switch_register); +EXPORT_SYMBOL(b53_switch_register); MODULE_AUTHOR("Jonas Gorski "); MODULE_DESCRIPTION("B53 switch library"); diff --git a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c index c85df1f305..98cdbffe73 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c +++ b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c @@ -280,7 +280,7 @@ static int b53_phy_probe(struct phy_device *phydev) if (phydev->mdio.addr != B53_PSEUDO_PHY && phydev->mdio.addr != 0) return -ENODEV; - dev = b53_swconfig_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus); + dev = b53_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus); if (!dev) return -ENOMEM; @@ -290,7 +290,7 @@ static int b53_phy_probe(struct phy_device *phydev) dev->pdata = NULL; mutex_init(&dev->reg_mutex); - ret = b53_swconfig_switch_detect(dev); + ret = b53_switch_detect(dev); if (ret) return ret; @@ -302,7 +302,7 @@ static int b53_phy_probe(struct phy_device *phydev) linkmode_copy(phydev->advertising, phydev->supported); - ret = b53_swconfig_switch_register(dev); + ret = b53_switch_register(dev); if (ret) { dev_err(dev->dev, "failed to register switch: %i\n", ret); return ret; @@ -361,6 +361,26 @@ static int b53_phy_read_status(struct phy_device *phydev) return 0; } +static const struct of_device_id b53_of_match_1[] = { + { .compatible = "brcm,bcm5325" }, + { .compatible = "brcm,bcm5395" }, + { .compatible = "brcm,bcm5397" }, + { .compatible = "brcm,bcm5398" }, + { /* sentinel */ }, +}; + +static const struct of_device_id b53_of_match_2[] = { + { .compatible = "brcm,bcm53115" }, + { .compatible = "brcm,bcm53125" }, + { .compatible = "brcm,bcm53128" }, + { /* sentinel */ }, +}; + +static const struct of_device_id b53_of_match_3[] = { + { .compatible = "brcm,bcm5365" }, + { /* sentinel */ }, +}; + /* BCM5325, BCM539x */ static struct phy_driver b53_phy_driver_id1 = { .phy_id = 0x0143bc00, @@ -372,6 +392,10 @@ static struct phy_driver b53_phy_driver_id1 = { .config_aneg = b53_phy_config_aneg, .config_init = b53_phy_config_init, .read_status = b53_phy_read_status, + .mdiodrv.driver = { + .name = "bcm539x", + .of_match_table = b53_of_match_1, + }, }; /* BCM53125, BCM53128 */ @@ -385,6 +409,10 @@ static struct phy_driver b53_phy_driver_id2 = { .config_aneg = b53_phy_config_aneg, .config_init = b53_phy_config_init, .read_status = b53_phy_read_status, + .mdiodrv.driver = { + .name = "bcm531xx", + .of_match_table = b53_of_match_2, + }, }; /* BCM5365 */ @@ -398,6 +426,10 @@ static struct phy_driver b53_phy_driver_id3 = { .config_aneg = b53_phy_config_aneg, .config_init = b53_phy_config_init, .read_status = b53_phy_read_status, + .mdiodrv.driver = { + .name = "bcm5365", + .of_match_table = b53_of_match_3, + }, }; int __init b53_phy_driver_register(void) diff --git a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c index 0a21ff1de5..ab1895e9b5 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c +++ b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c @@ -205,7 +205,7 @@ static int b53_mmap_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - dev = b53_swconfig_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs); + dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs); if (!dev) return -ENOMEM; @@ -214,7 +214,7 @@ static int b53_mmap_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - return b53_swconfig_switch_register(dev); + return b53_switch_register(dev); } static int b53_mmap_remove(struct platform_device *pdev) diff --git a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h index e455c755bf..37c17aeb25 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h +++ b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h @@ -183,12 +183,12 @@ static inline struct b53_device *sw_to_b53(struct switch_dev *sw) return container_of(sw, struct b53_device, sw_dev); } -struct b53_device *b53_swconfig_switch_alloc(struct device *base, struct b53_io_ops *ops, - void *priv); +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv); -int b53_swconfig_switch_detect(struct b53_device *dev); +int b53_switch_detect(struct b53_device *dev); -int b53_swconfig_switch_register(struct b53_device *dev); +int b53_switch_register(struct b53_device *dev); static inline void b53_switch_remove(struct b53_device *dev) { diff --git a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c index 400454df18..efc8f7ee89 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c +++ b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c @@ -288,14 +288,14 @@ static int b53_spi_probe(struct spi_device *spi) struct b53_device *dev; int ret; - dev = b53_swconfig_switch_alloc(&spi->dev, &b53_spi_ops, spi); + dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi); if (!dev) return -ENOMEM; if (spi->dev.platform_data) dev->pdata = spi->dev.platform_data; - ret = b53_swconfig_switch_register(dev); + ret = b53_switch_register(dev); if (ret) return ret; diff --git a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c index ead5209cf0..012daa3a51 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c +++ b/lede/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c @@ -342,7 +342,7 @@ static int b53_srab_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - dev = b53_swconfig_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs); + dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs); if (!dev) return -ENOMEM; @@ -351,7 +351,7 @@ static int b53_srab_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - return b53_swconfig_switch_register(dev); + return b53_switch_register(dev); } static int b53_srab_remove(struct platform_device *pdev) diff --git a/lede/target/linux/generic/files/drivers/net/phy/mvswitch.c b/lede/target/linux/generic/files/drivers/net/phy/mvswitch.c new file mode 100644 index 0000000000..bd3b9e1ad1 --- /dev/null +++ b/lede/target/linux/generic/files/drivers/net/phy/mvswitch.c @@ -0,0 +1,446 @@ +/* + * Marvell 88E6060 switch driver + * Copyright (c) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "mvswitch.h" + +/* Undefine this to use trailer mode instead. + * I don't know if header mode works with all chips */ +#define HEADER_MODE 1 + +MODULE_DESCRIPTION("Marvell 88E6060 Switch driver"); +MODULE_AUTHOR("Felix Fietkau"); +MODULE_LICENSE("GPL"); + +#define MVSWITCH_MAGIC 0x88E6060 + +struct mvswitch_priv { + netdev_features_t orig_features; + u8 vlans[16]; +}; + +#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv) + +static inline u16 +r16(struct phy_device *phydev, int addr, int reg) +{ + struct mii_bus *bus = phydev->mdio.bus; + + return bus->read(bus, addr, reg); +} + +static inline void +w16(struct phy_device *phydev, int addr, int reg, u16 val) +{ + struct mii_bus *bus = phydev->mdio.bus; + + bus->write(bus, addr, reg, val); +} + + +static struct sk_buff * +mvswitch_mangle_tx(struct net_device *dev, struct sk_buff *skb) +{ + struct mvswitch_priv *priv; + char *buf = NULL; + u16 vid; + + priv = dev->phy_ptr; + if (unlikely(!priv)) + goto error; + + if (unlikely(skb->len < 16)) + goto error; + +#ifdef HEADER_MODE + if (__vlan_hwaccel_get_tag(skb, &vid)) + goto error; + + if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) { + if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC)) + goto error_expand; + if (skb->len < 62) + skb->len = 62; + } + buf = skb_push(skb, MV_HEADER_SIZE); +#else + if (__vlan_get_tag(skb, &vid)) + goto error; + + if (unlikely((vid > 15 || !priv->vlans[vid]))) + goto error; + + if (skb->len <= 64) { + if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC)) + goto error_expand; + + buf = skb->data + 64; + skb->len = 64 + MV_TRAILER_SIZE; + } else { + if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) { + if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC)) + goto error_expand; + } + buf = skb_put(skb, 4); + } + + /* move the ethernet header 4 bytes forward, overwriting the vlan tag */ + memmove(skb->data + 4, skb->data, 12); + skb->data += 4; + skb->len -= 4; + skb->mac_header += 4; +#endif + + if (!buf) + goto error; + + +#ifdef HEADER_MODE + /* prepend the tag */ + *((__be16 *) buf) = cpu_to_be16( + ((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) | + ((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M) + ); +#else + /* append the tag */ + *((__be32 *) buf) = cpu_to_be32(( + (MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) | + ((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S) + )); +#endif + + return skb; + +error_expand: + if (net_ratelimit()) + printk("%s: failed to expand/update skb for the switch\n", dev->name); + +error: + /* any errors? drop the packet! */ + dev_kfree_skb_any(skb); + return NULL; +} + +static void +mvswitch_mangle_rx(struct net_device *dev, struct sk_buff *skb) +{ + struct mvswitch_priv *priv; + unsigned char *buf; + int vlan = -1; + int i; + + priv = dev->phy_ptr; + if (WARN_ON_ONCE(!priv)) + return; + +#ifdef HEADER_MODE + buf = skb->data; + skb_pull(skb, MV_HEADER_SIZE); +#else + buf = skb->data + skb->len - MV_TRAILER_SIZE; + if (buf[0] != 0x80) + return; +#endif + + /* look for the vlan matching the incoming port */ + for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) { + if ((1 << buf[1]) & priv->vlans[i]) + vlan = i; + } + + if (vlan == -1) + return; + + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); +} + + +static int +mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val) +{ + int i = 100; + u16 r; + + do { + r = r16(pdev, addr, reg) & mask; + if (r == val) + return 0; + } while(--i > 0); + return -ETIMEDOUT; +} + +static int +mvswitch_config_init(struct phy_device *pdev) +{ + struct mvswitch_priv *priv = to_mvsw(pdev); + struct net_device *dev = pdev->attached_dev; + u8 vlmap = 0; + int i; + + if (!dev) + return -EINVAL; + + printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name); + linkmode_zero(pdev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported); + linkmode_copy(pdev->advertising, pdev->supported); + dev->phy_ptr = priv; + pdev->irq = PHY_POLL; +#ifdef HEADER_MODE + dev->flags |= IFF_PROMISC; +#endif + + /* initialize default vlans */ + for (i = 0; i < MV_PORTS; i++) + priv->vlans[(i == MV_WANPORT ? 2 : 1)] |= (1 << i); + + /* before entering reset, disable all ports */ + for (i = 0; i < MV_PORTS; i++) + w16(pdev, MV_PORTREG(CONTROL, i), 0x00); + + msleep(2); /* wait for the status change to settle in */ + + /* put the ATU in reset */ + w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET); + + i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0); + if (i < 0) { + printk("%s: Timeout waiting for the switch to reset.\n", dev->name); + return i; + } + + /* set the ATU flags */ + w16(pdev, MV_SWITCHREG(ATU_CTRL), + MV_ATUCTL_NO_LEARN | + MV_ATUCTL_ATU_1K | + MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */ + ); + + /* initialize the cpu port */ + w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT), +#ifdef HEADER_MODE + MV_PORTCTRL_HEADER | +#else + MV_PORTCTRL_RXTR | + MV_PORTCTRL_TXTR | +#endif + MV_PORTCTRL_ENABLED + ); + /* wait for the phy change to settle in */ + msleep(2); + for (i = 0; i < MV_PORTS; i++) { + u8 pvid = 0; + int j; + + vlmap = 0; + + /* look for the matching vlan */ + for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) { + if (priv->vlans[j] & (1 << i)) { + vlmap = priv->vlans[j]; + pvid = j; + } + } + /* leave port unconfigured if it's not part of a vlan */ + if (!vlmap) + continue; + + /* add the cpu port to the allowed destinations list */ + vlmap |= (1 << MV_CPUPORT); + + /* take port out of its own vlan destination map */ + vlmap &= ~(1 << i); + + /* apply vlan settings */ + w16(pdev, MV_PORTREG(VLANMAP, i), + MV_PORTVLAN_PORTS(vlmap) | + MV_PORTVLAN_ID(i) + ); + + /* re-enable port */ + w16(pdev, MV_PORTREG(CONTROL, i), + MV_PORTCTRL_ENABLED + ); + } + + w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT), + MV_PORTVLAN_ID(MV_CPUPORT) + ); + + /* set the port association vector */ + for (i = 0; i <= MV_PORTS; i++) { + w16(pdev, MV_PORTREG(ASSOC, i), + MV_PORTASSOC_PORTS(1 << i) + ); + } + + /* init switch control */ + w16(pdev, MV_SWITCHREG(CTRL), + MV_SWITCHCTL_MSIZE | + MV_SWITCHCTL_DROP + ); + + dev->eth_mangle_rx = mvswitch_mangle_rx; + dev->eth_mangle_tx = mvswitch_mangle_tx; + priv->orig_features = dev->features; + +#ifdef HEADER_MODE + dev->priv_flags |= IFF_NO_IP_ALIGN; + dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; +#else + dev->features |= NETIF_F_HW_VLAN_CTAG_RX; +#endif + + return 0; +} + +static int +mvswitch_read_status(struct phy_device *pdev) +{ + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->link = 1; + + /* XXX ugly workaround: we can't force the switch + * to gracefully handle hosts moving from one port to another, + * so we have to regularly clear the ATU database */ + + /* wait for the ATU to become available */ + mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0); + + /* flush the ATU */ + w16(pdev, MV_SWITCHREG(ATU_OP), + MV_ATUOP_INPROGRESS | + MV_ATUOP_FLUSH_ALL + ); + + /* wait for operation to complete */ + mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0); + + return 0; +} + +static int +mvswitch_aneg_done(struct phy_device *phydev) +{ + return 1; /* Return any positive value */ +} + +static int +mvswitch_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static void +mvswitch_detach(struct phy_device *pdev) +{ + struct mvswitch_priv *priv = to_mvsw(pdev); + struct net_device *dev = pdev->attached_dev; + + if (!dev) + return; + + dev->phy_ptr = NULL; + dev->eth_mangle_rx = NULL; + dev->eth_mangle_tx = NULL; + dev->features = priv->orig_features; + dev->priv_flags &= ~IFF_NO_IP_ALIGN; +} + +static void +mvswitch_remove(struct phy_device *pdev) +{ + struct mvswitch_priv *priv = to_mvsw(pdev); + + kfree(priv); +} + +static int +mvswitch_probe(struct phy_device *pdev) +{ + struct mvswitch_priv *priv; + + priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + pdev->priv = priv; + + return 0; +} + +static int +mvswitch_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->mdio.bus; + u16 reg; + + if (dev->mdio.addr != 0x10) + return 0; + + reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK; + if (reg != MV_IDENT_VALUE) + return 0; + + dev->phy_id = MVSWITCH_MAGIC; + return 0; +} + + +static struct phy_driver mvswitch_driver = { + .name = "Marvell 88E6060", + .phy_id = MVSWITCH_MAGIC, + .phy_id_mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .probe = &mvswitch_probe, + .remove = &mvswitch_remove, + .detach = &mvswitch_detach, + .config_init = &mvswitch_config_init, + .config_aneg = &mvswitch_config_aneg, + .aneg_done = &mvswitch_aneg_done, + .read_status = &mvswitch_read_status, +}; + +static int __init +mvswitch_init(void) +{ + phy_register_fixup_for_id(PHY_ANY_ID, mvswitch_fixup); + return phy_driver_register(&mvswitch_driver, THIS_MODULE); +} + +static void __exit +mvswitch_exit(void) +{ + phy_driver_unregister(&mvswitch_driver); +} + +module_init(mvswitch_init); +module_exit(mvswitch_exit); diff --git a/lede/target/linux/generic/files/drivers/net/phy/mvswitch.h b/lede/target/linux/generic/files/drivers/net/phy/mvswitch.h new file mode 100644 index 0000000000..ab2a1a126e --- /dev/null +++ b/lede/target/linux/generic/files/drivers/net/phy/mvswitch.h @@ -0,0 +1,145 @@ +/* + * Marvell 88E6060 switch driver + * Copyright (c) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#ifndef __MVSWITCH_H +#define __MVSWITCH_H + +#define MV_HEADER_SIZE 2 +#define MV_HEADER_PORTS_M 0x001f +#define MV_HEADER_PORTS_S 0 +#define MV_HEADER_VLAN_M 0xf000 +#define MV_HEADER_VLAN_S 12 + +#define MV_TRAILER_SIZE 4 +#define MV_TRAILER_PORTS_M 0x1f +#define MV_TRAILER_PORTS_S 16 +#define MV_TRAILER_FLAGS_S 24 +#define MV_TRAILER_OVERRIDE 0x80 + + +#define MV_PORTS 5 +#define MV_WANPORT 4 +#define MV_CPUPORT 5 + +#define MV_BASE 0x10 + +#define MV_PHYPORT_BASE (MV_BASE + 0x0) +#define MV_PHYPORT(_n) (MV_PHYPORT_BASE + (_n)) +#define MV_SWITCHPORT_BASE (MV_BASE + 0x8) +#define MV_SWITCHPORT(_n) (MV_SWITCHPORT_BASE + (_n)) +#define MV_SWITCHREGS (MV_BASE + 0xf) + +enum { + MV_PHY_CONTROL = 0x00, + MV_PHY_STATUS = 0x01, + MV_PHY_IDENT0 = 0x02, + MV_PHY_IDENT1 = 0x03, + MV_PHY_ANEG = 0x04, + MV_PHY_LINK_ABILITY = 0x05, + MV_PHY_ANEG_EXPAND = 0x06, + MV_PHY_XMIT_NEXTP = 0x07, + MV_PHY_LINK_NEXTP = 0x08, + MV_PHY_CONTROL1 = 0x10, + MV_PHY_STATUS1 = 0x11, + MV_PHY_INTR_EN = 0x12, + MV_PHY_INTR_STATUS = 0x13, + MV_PHY_INTR_PORT = 0x14, + MV_PHY_RECV_COUNTER = 0x16, + MV_PHY_LED_PARALLEL = 0x16, + MV_PHY_LED_STREAM = 0x17, + MV_PHY_LED_CTRL = 0x18, + MV_PHY_LED_OVERRIDE = 0x19, + MV_PHY_VCT_CTRL = 0x1a, + MV_PHY_VCT_STATUS = 0x1b, + MV_PHY_CONTROL2 = 0x1e +}; +#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type + +enum { + MV_PORT_STATUS = 0x00, + MV_PORT_IDENT = 0x03, + MV_PORT_CONTROL = 0x04, + MV_PORT_VLANMAP = 0x06, + MV_PORT_ASSOC = 0x0b, + MV_PORT_RXCOUNT = 0x10, + MV_PORT_TXCOUNT = 0x11, +}; +#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type + +enum { + MV_PORTCTRL_BLOCK = (1 << 0), + MV_PORTCTRL_LEARN = (2 << 0), + MV_PORTCTRL_ENABLED = (3 << 0), + MV_PORTCTRL_VLANTUN = (1 << 7), /* Enforce VLANs on packets */ + MV_PORTCTRL_RXTR = (1 << 8), /* Enable Marvell packet trailer for ingress */ + MV_PORTCTRL_HEADER = (1 << 11), /* Enable Marvell packet header mode for port */ + MV_PORTCTRL_TXTR = (1 << 14), /* Enable Marvell packet trailer for egress */ + MV_PORTCTRL_FORCEFL = (1 << 15), /* force flow control */ +}; + +#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12) +#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f) + +#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f) +#define MV_PORTASSOC_MONITOR (1 << 15) + +enum { + MV_SWITCH_MAC0 = 0x01, + MV_SWITCH_MAC1 = 0x02, + MV_SWITCH_MAC2 = 0x03, + MV_SWITCH_CTRL = 0x04, + MV_SWITCH_ATU_CTRL = 0x0a, + MV_SWITCH_ATU_OP = 0x0b, + MV_SWITCH_ATU_DATA = 0x0c, + MV_SWITCH_ATU_MAC0 = 0x0d, + MV_SWITCH_ATU_MAC1 = 0x0e, + MV_SWITCH_ATU_MAC2 = 0x0f, +}; +#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type + +enum { + MV_SWITCHCTL_EEIE = (1 << 0), /* EEPROM interrupt enable */ + MV_SWITCHCTL_PHYIE = (1 << 1), /* PHY interrupt enable */ + MV_SWITCHCTL_ATUDONE= (1 << 2), /* ATU done interrupt enable */ + MV_SWITCHCTL_ATUIE = (1 << 3), /* ATU interrupt enable */ + MV_SWITCHCTL_CTRMODE= (1 << 8), /* statistics for rx and tx errors */ + MV_SWITCHCTL_RELOAD = (1 << 9), /* reload registers from eeprom */ + MV_SWITCHCTL_MSIZE = (1 << 10), /* increase maximum frame size */ + MV_SWITCHCTL_DROP = (1 << 13), /* discard frames with excessive collisions */ +}; + +enum { +#define MV_ATUCTL_AGETIME_MIN 16 +#define MV_ATUCTL_AGETIME_MAX 4080 +#define MV_ATUCTL_AGETIME(_n) ((((_n) / 16) & 0xff) << 4) + MV_ATUCTL_ATU_256 = (0 << 12), + MV_ATUCTL_ATU_512 = (1 << 12), + MV_ATUCTL_ATU_1K = (2 << 12), + MV_ATUCTL_ATUMASK = (3 << 12), + MV_ATUCTL_NO_LEARN = (1 << 14), + MV_ATUCTL_RESET = (1 << 15), +}; + +enum { +#define MV_ATUOP_DBNUM(_n) ((_n) & 0x0f) + + MV_ATUOP_NOOP = (0 << 12), + MV_ATUOP_FLUSH_ALL = (1 << 12), + MV_ATUOP_FLUSH_U = (2 << 12), + MV_ATUOP_LOAD_DB = (3 << 12), + MV_ATUOP_GET_NEXT = (4 << 12), + MV_ATUOP_FLUSH_DB = (5 << 12), + MV_ATUOP_FLUSH_DB_UU= (6 << 12), + + MV_ATUOP_INPROGRESS = (1 << 15), +}; + +#define MV_IDENT_MASK 0xfff0 +#define MV_IDENT_VALUE 0x0600 + +#endif diff --git a/lede/target/linux/generic/files/drivers/net/phy/psb6970.c b/lede/target/linux/generic/files/drivers/net/phy/psb6970.c index 2587b99913..fb6ed0e204 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/psb6970.c +++ b/lede/target/linux/generic/files/drivers/net/phy/psb6970.c @@ -60,13 +60,11 @@ struct psb6970_priv { struct mutex reg_mutex; /* all fields below are cleared on reset */ - struct_group(psb6970_priv_volatile, - bool vlan; - u16 vlan_id[PSB6970_MAX_VLANS]; - u8 vlan_table[PSB6970_MAX_VLANS]; - u8 vlan_tagged; - u16 pvid[PSB6970_NUM_PORTS]; - ); + bool vlan; + u16 vlan_id[PSB6970_MAX_VLANS]; + u8 vlan_table[PSB6970_MAX_VLANS]; + u8 vlan_tagged; + u16 pvid[PSB6970_NUM_PORTS]; }; #define to_psb6970(_dev) container_of(_dev, struct psb6970_priv, dev) @@ -274,8 +272,8 @@ static int psb6970_reset_switch(struct switch_dev *dev) mutex_lock(&priv->reg_mutex); - memset(&priv->psb6970_priv_volatile, 0, - sizeof(priv->psb6970_priv_volatile)); + memset(&priv->vlan, 0, sizeof(struct psb6970_priv) - + offsetof(struct psb6970_priv, vlan)); for (i = 0; i < PSB6970_MAX_VLANS; i++) priv->vlan_id[i] = i; @@ -309,6 +307,7 @@ static const struct switch_dev_ops psb6970_ops = { static int psb6970_config_init(struct phy_device *pdev) { struct psb6970_priv *priv; + struct net_device *dev = pdev->attached_dev; struct switch_dev *swdev; int ret; diff --git a/lede/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c b/lede/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c index a26fd204cb..e8375e5147 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c +++ b/lede/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c @@ -256,7 +256,7 @@ static int __rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) int __rtl8366_mdio_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) { - u32 phy_id = smi->phy_id; + u32 phy_id = MDC_REALTEK_PHY_ADDR; struct mii_bus *mbus = smi->ext_mbus; BUG_ON(in_interrupt()); @@ -293,7 +293,7 @@ int __rtl8366_mdio_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) static int __rtl8366_mdio_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) { - u32 phy_id = smi->phy_id; + u32 phy_id = MDC_REALTEK_PHY_ADDR; struct mii_bus *mbus = smi->ext_mbus; BUG_ON(in_interrupt()); @@ -590,7 +590,7 @@ static int rtl8366_set_pvid(struct rtl8366_smi *smi, unsigned port, return -ENOSPC; } -static int rtl8366_smi_enable_vlan(struct rtl8366_smi *smi, int enable) +int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable) { int err; @@ -607,8 +607,9 @@ static int rtl8366_smi_enable_vlan(struct rtl8366_smi *smi, int enable) return err; } +EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); -static int rtl8366_smi_enable_vlan4k(struct rtl8366_smi *smi, int enable) +static int rtl8366_enable_vlan4k(struct rtl8366_smi *smi, int enable) { int err; @@ -628,7 +629,7 @@ static int rtl8366_smi_enable_vlan4k(struct rtl8366_smi *smi, int enable) return 0; } -static int rtl8366_smi_enable_all_ports(struct rtl8366_smi *smi, int enable) +int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable) { int port; int err; @@ -641,15 +642,16 @@ static int rtl8366_smi_enable_all_ports(struct rtl8366_smi *smi, int enable) return 0; } +EXPORT_SYMBOL_GPL(rtl8366_enable_all_ports); -static int rtl8366_smi_reset_vlan(struct rtl8366_smi *smi) +int rtl8366_reset_vlan(struct rtl8366_smi *smi) { struct rtl8366_vlan_mc vlanmc; int err; int i; - rtl8366_smi_enable_vlan(smi, 0); - rtl8366_smi_enable_vlan4k(smi, 0); + rtl8366_enable_vlan(smi, 0); + rtl8366_enable_vlan4k(smi, 0); /* clear VLAN member configurations */ vlanmc.vid = 0; @@ -665,13 +667,14 @@ static int rtl8366_smi_reset_vlan(struct rtl8366_smi *smi) return 0; } +EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); static int rtl8366_init_vlan(struct rtl8366_smi *smi) { int port; int err; - err = rtl8366_smi_reset_vlan(smi); + err = rtl8366_reset_vlan(smi); if (err) return err; @@ -692,7 +695,7 @@ static int rtl8366_init_vlan(struct rtl8366_smi *smi) return err; } - return rtl8366_smi_enable_vlan(smi, 1); + return rtl8366_enable_vlan(smi, 1); } #ifdef CONFIG_RTL8366_SMI_DEBUG_FS @@ -1070,15 +1073,15 @@ int rtl8366_sw_reset_switch(struct switch_dev *dev) if (err) return err; - err = rtl8366_smi_reset_vlan(smi); + err = rtl8366_reset_vlan(smi); if (err) return err; - err = rtl8366_smi_enable_vlan(smi, 1); + err = rtl8366_enable_vlan(smi, 1); if (err) return err; - return rtl8366_smi_enable_all_ports(smi, 1); + return rtl8366_enable_all_ports(smi, 1); } EXPORT_SYMBOL_GPL(rtl8366_sw_reset_switch); @@ -1340,9 +1343,9 @@ int rtl8366_sw_set_vlan_enable(struct switch_dev *dev, return -EINVAL; if (attr->ofs == 1) - err = rtl8366_smi_enable_vlan(smi, val->value.i); + err = rtl8366_enable_vlan(smi, val->value.i); else - err = rtl8366_smi_enable_vlan4k(smi, val->value.i); + err = rtl8366_enable_vlan4k(smi, val->value.i); return err; } @@ -1491,7 +1494,7 @@ int rtl8366_smi_init(struct rtl8366_smi *smi) goto err_free_sck; } - err = rtl8366_smi_enable_all_ports(smi, 1); + err = rtl8366_enable_all_ports(smi, 1); if (err) goto err_free_sck; @@ -1547,9 +1550,6 @@ int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi) goto try_gpio; } - if (of_property_read_u32(np, "phy-id", &smi->phy_id)) - smi->phy_id = MDC_REALTEK_PHY_ADDR; - return 0; try_gpio: @@ -1589,7 +1589,6 @@ int rtl8366_smi_probe_plat(struct platform_device *pdev, struct rtl8366_smi *smi smi->gpio_sda = pdata->gpio_sda; smi->gpio_sck = pdata->gpio_sck; smi->hw_reset = pdata->hw_reset; - smi->phy_id = MDC_REALTEK_PHY_ADDR; return 0; } diff --git a/lede/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h b/lede/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h index 3fcae81fa4..d1d988a372 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h +++ b/lede/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h @@ -63,7 +63,6 @@ struct rtl8366_smi { u16 dbg_reg; u8 dbg_vlan_4k_page; #endif - u32 phy_id; struct mii_bus *ext_mbus; }; @@ -116,6 +115,10 @@ int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data); int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data); int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data); +int rtl8366_reset_vlan(struct rtl8366_smi *smi); +int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable); +int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable); + #ifdef CONFIG_RTL8366_SMI_DEBUG_FS int rtl8366_debugfs_open(struct inode *inode, struct file *file); #endif diff --git a/lede/target/linux/generic/files/drivers/net/phy/rtl8367.c b/lede/target/linux/generic/files/drivers/net/phy/rtl8367.c index b14b63e036..7f0569d038 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/rtl8367.c +++ b/lede/target/linux/generic/files/drivers/net/phy/rtl8367.c @@ -1641,7 +1641,7 @@ static int rtl8367_switch_init(struct rtl8366_smi *smi) int err; dev->name = "RTL8367"; - dev->cpu_port = smi->cpu_port; + dev->cpu_port = RTL8367_CPU_PORT_NUM; dev->ports = RTL8367_NUM_PORTS; dev->vlans = RTL8367_NUM_VIDS; dev->ops = &rtl8367_sw_ops; @@ -1722,11 +1722,6 @@ static int rtl8367_detect(struct rtl8366_smi *smi) dev_info(smi->parent, "RTL%s ver. %u chip found\n", chip_name, rtl_ver & RTL8367_RTL_VER_MASK); - if (of_property_present(smi->parent->of_node, "realtek,extif1")) - smi->cpu_port = RTL8367_CPU_PORT_NUM - 1; - - dev_info(smi->parent, "CPU port: %u\n", smi->cpu_port); - return 0; } diff --git a/lede/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/lede/target/linux/generic/files/drivers/net/phy/rtl8367b.c index 04c790e924..cd0d58cbfa 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/rtl8367b.c +++ b/lede/target/linux/generic/files/drivers/net/phy/rtl8367b.c @@ -1583,13 +1583,6 @@ static int rtl8367b_detect(struct rtl8366_smi *smi) dev_info(smi->parent, "RTL%s chip found\n", chip_name); - if (of_property_present(smi->parent->of_node, "realtek,extif2")) - smi->cpu_port = RTL8367B_CPU_PORT_NUM + 2; - else if (of_property_present(smi->parent->of_node, "realtek,extif1") && (chip_ver != 0x1010)) /* for the RTL8367R-VB chip, extif1 corresponds to cpu_port 5 */ - smi->cpu_port = RTL8367B_CPU_PORT_NUM + 1; - - dev_info(smi->parent, "CPU port: %u\n", smi->cpu_port); - return 0; } @@ -1628,7 +1621,9 @@ static int rtl8367b_probe(struct platform_device *pdev) smi->cmd_write = 0xb8; smi->ops = &rtl8367b_smi_ops; smi->num_ports = RTL8367B_NUM_PORTS; - smi->cpu_port = RTL8367B_CPU_PORT_NUM; + if (of_property_read_u32(pdev->dev.of_node, "cpu_port", &smi->cpu_port) + || smi->cpu_port >= smi->num_ports) + smi->cpu_port = RTL8367B_CPU_PORT_NUM; smi->num_vlan_mc = RTL8367B_NUM_VLANS; smi->mib_counters = rtl8367b_mib_counters; smi->num_mib_counters = ARRAY_SIZE(rtl8367b_mib_counters); diff --git a/lede/target/linux/generic/files/drivers/net/phy/swconfig.c b/lede/target/linux/generic/files/drivers/net/phy/swconfig.c index 5fa2b147c6..a734e57608 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/swconfig.c +++ b/lede/target/linux/generic/files/drivers/net/phy/swconfig.c @@ -1054,9 +1054,6 @@ static struct genl_family switch_fam = { .module = THIS_MODULE, .ops = swconfig_ops, .n_ops = ARRAY_SIZE(swconfig_ops), -#if LINUX_VERSION_CODE > KERNEL_VERSION(6,0,0) - .resv_start_op = SWITCH_CMD_SET_VLAN + 1, -#endif }; #ifdef CONFIG_OF diff --git a/lede/target/linux/generic/files/drivers/net/phy/swconfig_leds.c b/lede/target/linux/generic/files/drivers/net/phy/swconfig_leds.c index 1d309c046c..767d9221b4 100644 --- a/lede/target/linux/generic/files/drivers/net/phy/swconfig_leds.c +++ b/lede/target/linux/generic/files/drivers/net/phy/swconfig_leds.c @@ -85,7 +85,7 @@ swconfig_trig_update_port_mask(struct led_trigger *trigger) sw_trig = (void *) trigger; port_mask = 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) spin_lock(&trigger->leddev_list_lock); #else read_lock(&trigger->leddev_list_lock); @@ -102,12 +102,11 @@ swconfig_trig_update_port_mask(struct led_trigger *trigger) read_unlock(&trig_data->lock); } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) spin_unlock(&trigger->leddev_list_lock); #else read_unlock(&trigger->leddev_list_lock); #endif - sw_trig->port_mask = port_mask; if (port_mask) @@ -426,7 +425,7 @@ swconfig_trig_update_leds(struct switch_led_trigger *sw_trig) struct led_trigger *trigger; trigger = &sw_trig->trig; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) spin_lock(&trigger->leddev_list_lock); #else read_lock(&trigger->leddev_list_lock); @@ -437,7 +436,7 @@ swconfig_trig_update_leds(struct switch_led_trigger *sw_trig) led_cdev = list_entry(entry, struct led_classdev, trig_list); swconfig_trig_led_event(sw_trig, led_cdev); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) spin_unlock(&trigger->leddev_list_lock); #else read_unlock(&trigger->leddev_list_lock); diff --git a/lede/target/linux/generic/files/drivers/platform/mikrotik/Kconfig b/lede/target/linux/generic/files/drivers/platform/mikrotik/Kconfig index 32ef8f29de..7499ba1e1c 100644 --- a/lede/target/linux/generic/files/drivers/platform/mikrotik/Kconfig +++ b/lede/target/linux/generic/files/drivers/platform/mikrotik/Kconfig @@ -1,5 +1,6 @@ menuconfig MIKROTIK bool "Platform support for MikroTik RouterBoard virtual devices" + default n help Say Y here to get to see options for the MikroTik RouterBoard platform. This option alone does not add any kernel code. @@ -15,10 +16,4 @@ config MIKROTIK_RB_SYSFS help This driver exposes RouterBoot configuration in sysfs. -config NVMEM_LAYOUT_MIKROTIK - tristate "RouterBoot NVMEM layout support" - depends on NVMEM_LAYOUTS - help - This driver exposes MikroTik hard_config via NVMEM layout. - endif # MIKROTIK diff --git a/lede/target/linux/generic/files/drivers/platform/mikrotik/Makefile b/lede/target/linux/generic/files/drivers/platform/mikrotik/Makefile index 164b23b701..a232e1a9e8 100644 --- a/lede/target/linux/generic/files/drivers/platform/mikrotik/Makefile +++ b/lede/target/linux/generic/files/drivers/platform/mikrotik/Makefile @@ -2,4 +2,3 @@ # Makefile for MikroTik RouterBoard platform specific drivers # obj-$(CONFIG_MIKROTIK_RB_SYSFS) += routerboot.o rb_hardconfig.o rb_softconfig.o -obj-$(CONFIG_NVMEM_LAYOUT_MIKROTIK) += rb_nvmem.o diff --git a/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c b/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c index 78e39a7f94..e6a6928896 100644 --- a/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c +++ b/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c @@ -37,12 +37,29 @@ #include #include -#include "rb_hardconfig.h" #include "routerboot.h" -#define RB_HARDCONFIG_VER "0.07" +#define RB_HARDCONFIG_VER "0.06" #define RB_HC_PR_PFX "[rb_hardconfig] " +/* ID values for hardware settings */ +#define RB_ID_FLASH_INFO 0x03 +#define RB_ID_MAC_ADDRESS_PACK 0x04 +#define RB_ID_BOARD_PRODUCT_CODE 0x05 +#define RB_ID_BIOS_VERSION 0x06 +#define RB_ID_SDRAM_TIMINGS 0x08 +#define RB_ID_DEVICE_TIMINGS 0x09 +#define RB_ID_SOFTWARE_ID 0x0A +#define RB_ID_SERIAL_NUMBER 0x0B +#define RB_ID_MEMORY_SIZE 0x0D +#define RB_ID_MAC_ADDRESS_COUNT 0x0E +#define RB_ID_HW_OPTIONS 0x15 +#define RB_ID_WLAN_DATA 0x16 +#define RB_ID_BOARD_IDENTIFIER 0x17 +#define RB_ID_PRODUCT_NAME 0x21 +#define RB_ID_DEFCONF 0x26 +#define RB_ID_BOARD_REVISION 0x27 + /* Bit definitions for hardware options */ #define RB_HW_OPT_NO_UART BIT(0) #define RB_HW_OPT_HAS_VOLTAGE BIT(1) @@ -659,9 +676,10 @@ static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj, return count; } -int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) +int __init rb_hardconfig_init(struct kobject *rb_kobj) { struct kobject *hc_wlan_kobj; + struct mtd_info *mtd; size_t bytes_read, buflen, outlen; const u8 *buf; void *outbuf; @@ -672,19 +690,20 @@ int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) hc_kobj = NULL; hc_wlan_kobj = NULL; - ret = __get_mtd_device(mtd); - if (ret) + // TODO allow override + mtd = get_mtd_device_nm(RB_MTD_HARD_CONFIG); + if (IS_ERR(mtd)) return -ENODEV; hc_buflen = mtd->size; hc_buf = kmalloc(hc_buflen, GFP_KERNEL); if (!hc_buf) { - __put_mtd_device(mtd); + put_mtd_device(mtd); return -ENOMEM; } ret = mtd_read(mtd, 0, hc_buflen, &bytes_read, hc_buf); - __put_mtd_device(mtd); + put_mtd_device(mtd); if (ret) goto fail; @@ -799,10 +818,8 @@ fail: return ret; } -void rb_hardconfig_exit(void) +void __exit rb_hardconfig_exit(void) { kobject_put(hc_kobj); - hc_kobj = NULL; kfree(hc_buf); - hc_buf = NULL; } diff --git a/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.h b/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.h deleted file mode 100644 index 328f4fe3c3..0000000000 --- a/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.h +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Common definitions for MikroTik RouterBoot hard config data. - * - * Copyright (C) 2020 Thibaut VARÈNE - * - * Some constant defines extracted from routerboot.{c,h} by Gabor Juhos - * - */ - -#ifndef _ROUTERBOOT_HARD_CONFIG_H_ -#define _ROUTERBOOT_HARD_CONFIG_H_ - -/* ID values for hardware settings */ -#define RB_ID_FLASH_INFO 0x03 -#define RB_ID_MAC_ADDRESS_PACK 0x04 -#define RB_ID_BOARD_PRODUCT_CODE 0x05 -#define RB_ID_BIOS_VERSION 0x06 -#define RB_ID_SDRAM_TIMINGS 0x08 -#define RB_ID_DEVICE_TIMINGS 0x09 -#define RB_ID_SOFTWARE_ID 0x0A -#define RB_ID_SERIAL_NUMBER 0x0B -#define RB_ID_MEMORY_SIZE 0x0D -#define RB_ID_MAC_ADDRESS_COUNT 0x0E -#define RB_ID_HW_OPTIONS 0x15 -#define RB_ID_WLAN_DATA 0x16 -#define RB_ID_BOARD_IDENTIFIER 0x17 -#define RB_ID_PRODUCT_NAME 0x21 -#define RB_ID_DEFCONF 0x26 -#define RB_ID_BOARD_REVISION 0x27 - -#endif /* _ROUTERBOOT_HARD_CONFIG_H_ */ diff --git a/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_nvmem.c b/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_nvmem.c deleted file mode 100644 index 6f785ce7d1..0000000000 --- a/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_nvmem.c +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * NVMEM layout driver for MikroTik Routerboard hard config cells - * - * Copyright (C) 2024 Robert Marko - * Based on the sysfs hard config driver by Thibaut VARÈNE - * Comments documenting the format carried over from routerboot.c - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "rb_hardconfig.h" -#include "routerboot.h" - -#define TLV_TAG_MASK GENMASK(15, 0) -#define TLV_LEN_MASK GENMASK(31, 16) - -static const char *rb_tlv_cell_name(u16 tag) -{ - switch (tag) { - case RB_ID_FLASH_INFO: - return "flash-info"; - case RB_ID_MAC_ADDRESS_PACK: - return "base-mac-address"; - case RB_ID_BOARD_PRODUCT_CODE: - return "board-product-code"; - case RB_ID_BIOS_VERSION: - return "booter-version"; - case RB_ID_SERIAL_NUMBER: - return "board-serial"; - case RB_ID_MEMORY_SIZE: - return "mem-size"; - case RB_ID_MAC_ADDRESS_COUNT: - return "mac-count"; - case RB_ID_HW_OPTIONS: - return "hw-options"; - case RB_ID_WLAN_DATA: - return "wlan-data"; - case RB_ID_BOARD_IDENTIFIER: - return "board-identifier"; - case RB_ID_PRODUCT_NAME: - return "product-name"; - case RB_ID_DEFCONF: - return "defconf"; - case RB_ID_BOARD_REVISION: - return "board-revision"; - default: - break; - } - - return NULL; -} - -static int rb_tlv_mac_read_cb(void *priv, const char *id, int index, - unsigned int offset, void *buf, - size_t bytes) -{ - if (index < 0) - return -EINVAL; - - if (!is_valid_ether_addr(buf)) - return -EINVAL; - - eth_addr_add(buf, index); - - return 0; -} - -static nvmem_cell_post_process_t rb_tlv_read_cb(u16 tag) -{ - switch (tag) { - case RB_ID_MAC_ADDRESS_PACK: - return &rb_tlv_mac_read_cb; - default: - break; - } - - return NULL; -} - -static int rb_add_cells(struct device *dev, struct nvmem_device *nvmem, - const size_t data_len, u8 *data) -{ - u32 node, offset = sizeof(RB_MAGIC_HARD); - struct nvmem_cell_info cell = {}; - struct device_node *layout; - u16 tlv_tag, tlv_len; - int ret; - - layout = of_nvmem_layout_get_container(nvmem); - if (!layout) - return -ENOENT; - - /* - * Routerboot tag nodes are u32 values: - * - The low nibble is the tag identification number, - * - The high nibble is the tag payload length (node excluded) in bytes. - * Tag nodes are CPU-endian. - * Tag nodes are 32bit-aligned. - * - * The payload immediately follows the tag node. - * Payload offset will always be aligned. while length may not end on 32bit - * boundary (the only known case is when parsing ERD data). - * The payload is CPU-endian when applicable. - * Tag nodes are not ordered (by ID) on flash. - */ - while ((offset + sizeof(node)) <= data_len) { - node = *((const u32 *) (data + offset)); - /* Tag list ends with null node */ - if (!node) - break; - - tlv_tag = FIELD_GET(TLV_TAG_MASK, node); - tlv_len = FIELD_GET(TLV_LEN_MASK, node); - - offset += sizeof(node); - if (offset + tlv_len > data_len) { - dev_err(dev, "Out of bounds field (0x%x bytes at 0x%x)\n", - tlv_len, offset); - break; - } - - cell.name = rb_tlv_cell_name(tlv_tag); - if (!cell.name) - goto skip; - - cell.offset = offset; - /* - * MikroTik stores MAC-s with length of 8 bytes, - * but kernel expects it to be ETH_ALEN (6 bytes), - * so we need to make sure that is the case. - */ - if (tlv_tag == RB_ID_MAC_ADDRESS_PACK) - cell.bytes = ETH_ALEN; - else - cell.bytes = tlv_len; - cell.np = of_get_child_by_name(layout, cell.name); - cell.read_post_process = rb_tlv_read_cb(tlv_tag); - - ret = nvmem_add_one_cell(nvmem, &cell); - if (ret) { - of_node_put(layout); - return ret; - } - - /* - * The only known situation where len may not end on 32bit - * boundary is within ERD data. Since we're only extracting - * one tag (the first and only one) from that data, we should - * never need to forcefully ALIGN(). Do it anyway, this is not a - * performance path. - */ -skip: - offset += ALIGN(tlv_len, sizeof(offset)); - } - - of_node_put(layout); - - return 0; -} - -static int rb_parse_table(struct nvmem_layout *layout) -{ - struct nvmem_device *nvmem = layout->nvmem; - struct device *dev = &layout->dev; - size_t mtd_size; - u8 *data; - u32 hdr; - int ret; - - ret = nvmem_device_read(nvmem, 0, sizeof(hdr), &hdr); - if (ret < 0) - return ret; - - if (hdr != RB_MAGIC_HARD) { - dev_err(dev, "Invalid header\n"); - return -EINVAL; - } - - mtd_size = nvmem_dev_size(nvmem); - - data = devm_kmalloc(dev, mtd_size, GFP_KERNEL); - if (!data) - return -ENOMEM; - - ret = nvmem_device_read(nvmem, 0, mtd_size, data); - if (ret != mtd_size) - return ret; - - return rb_add_cells(dev, nvmem, mtd_size, data); -} - -static int rb_nvmem_probe(struct nvmem_layout *layout) -{ - layout->add_cells = rb_parse_table; - - return nvmem_layout_register(layout); -} - -static void rb_nvmem_remove(struct nvmem_layout *layout) -{ - nvmem_layout_unregister(layout); -} - -static const struct of_device_id rb_nvmem_of_match_table[] = { - { .compatible = "mikrotik,routerboot-nvmem", }, - {}, -}; -MODULE_DEVICE_TABLE(of, rb_nvmem_of_match_table); - -static struct nvmem_layout_driver rb_nvmem_layout = { - .probe = rb_nvmem_probe, - .remove = rb_nvmem_remove, - .driver = { - .owner = THIS_MODULE, - .name = "rb_nvmem", - .of_match_table = rb_nvmem_of_match_table, - }, -}; -module_nvmem_layout_driver(rb_nvmem_layout); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Robert Marko "); -MODULE_DESCRIPTION("NVMEM layout driver for MikroTik Routerboard hard config cells"); diff --git a/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c b/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c index 5acff6aa91..070bd32d5a 100644 --- a/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c +++ b/lede/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c @@ -56,12 +56,23 @@ #include "routerboot.h" -#define RB_SOFTCONFIG_VER "0.05" +#define RB_SOFTCONFIG_VER "0.03" #define RB_SC_PR_PFX "[rb_softconfig] " -#define RB_SC_HAS_WRITE_SUPPORT true -#define RB_SC_WMODE S_IWUSR -#define RB_SC_RMODE S_IRUSR +/* + * mtd operations before 4.17 are asynchronous, not handled by this code + * Also make the driver act read-only if 4K_SECTORS are not enabled, since they + * are require to handle partial erasing of the small soft_config partition. + */ +#if defined(CONFIG_MTD_SPI_NOR_USE_4K_SECTORS) + #define RB_SC_HAS_WRITE_SUPPORT true + #define RB_SC_WMODE S_IWUSR + #define RB_SC_RMODE S_IRUSR +#else + #define RB_SC_HAS_WRITE_SUPPORT false + #define RB_SC_WMODE 0 + #define RB_SC_RMODE S_IRUSR +#endif /* ID values for software settings */ #define RB_SCID_UART_SPEED 0x01 // u32*1 @@ -694,8 +705,9 @@ mtdfail: static struct kobj_attribute sc_kattrcommit = __ATTR(commit, RB_SC_RMODE|RB_SC_WMODE, sc_commit_show, sc_commit_store); -int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) +int __init rb_softconfig_init(struct kobject *rb_kobj) { + struct mtd_info *mtd; size_t bytes_read, buflen; const u8 *buf; int i, ret; @@ -704,19 +716,20 @@ int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) sc_buf = NULL; sc_kobj = NULL; - ret = __get_mtd_device(mtd); - if (ret) + // TODO allow override + mtd = get_mtd_device_nm(RB_MTD_SOFT_CONFIG); + if (IS_ERR(mtd)) return -ENODEV; sc_buflen = mtd->size; sc_buf = kmalloc(sc_buflen, GFP_KERNEL); if (!sc_buf) { - __put_mtd_device(mtd); + put_mtd_device(mtd); return -ENOMEM; } ret = mtd_read(mtd, 0, sc_buflen, &bytes_read, sc_buf); - __put_mtd_device(mtd); + put_mtd_device(mtd); if (ret) goto fail; @@ -786,10 +799,8 @@ fail: return ret; } -void rb_softconfig_exit(void) +void __exit rb_softconfig_exit(void) { kobject_put(sc_kobj); - sc_kobj = NULL; kfree(sc_buf); - sc_buf = NULL; } diff --git a/lede/target/linux/generic/files/drivers/platform/mikrotik/routerboot.c b/lede/target/linux/generic/files/drivers/platform/mikrotik/routerboot.c index 96f2460916..4c8c0bfac5 100644 --- a/lede/target/linux/generic/files/drivers/platform/mikrotik/routerboot.c +++ b/lede/target/linux/generic/files/drivers/platform/mikrotik/routerboot.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "routerboot.h" @@ -161,57 +160,25 @@ fail: return ret; } -static void routerboot_mtd_notifier_add(struct mtd_info *mtd) -{ - /* Currently routerboot is only known to live on NOR flash */ - if (mtd->type != MTD_NORFLASH) - return; - - /* - * We ignore the following return values and always register. - * These init() routines are designed so that their failed state is - * always manageable by the corresponding exit() calls. - * Notifier is called with MTD mutex held: use __get/__put variants. - * TODO: allow partition names override - */ - if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG)) - rb_hardconfig_init(rb_kobj, mtd); - else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG)) - rb_softconfig_init(rb_kobj, mtd); -} - -static void routerboot_mtd_notifier_remove(struct mtd_info *mtd) -{ - if (mtd->type != MTD_NORFLASH) - return; - - if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG)) - rb_hardconfig_exit(); - else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG)) - rb_softconfig_exit(); -} - -/* Note: using a notifier prevents qualifying init()/exit() functions with __init/__exit */ -static struct mtd_notifier routerboot_mtd_notifier = { - .add = routerboot_mtd_notifier_add, - .remove = routerboot_mtd_notifier_remove, -}; - static int __init routerboot_init(void) { rb_kobj = kobject_create_and_add("mikrotik", firmware_kobj); if (!rb_kobj) return -ENOMEM; - register_mtd_user(&routerboot_mtd_notifier); + /* + * We ignore the following return values and always register. + * These init() routines are designed so that their failed state is + * always manageable by the corresponding exit() calls. + */ + rb_hardconfig_init(rb_kobj); + rb_softconfig_init(rb_kobj); return 0; } static void __exit routerboot_exit(void) { - unregister_mtd_user(&routerboot_mtd_notifier); - /* Exit routines are idempotent */ rb_softconfig_exit(); rb_hardconfig_exit(); kobject_put(rb_kobj); // recursive afaict diff --git a/lede/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h b/lede/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h index e858a524af..67d89808d5 100644 --- a/lede/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h +++ b/lede/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h @@ -25,11 +25,11 @@ int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, u16 *pld_ofs, u16 *pld_len); int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen); -int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd); -void rb_hardconfig_exit(void); +int __init rb_hardconfig_init(struct kobject *rb_kobj); +void __exit rb_hardconfig_exit(void); -int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd); -void rb_softconfig_exit(void); +int __init rb_softconfig_init(struct kobject *rb_kobj); +void __exit rb_softconfig_exit(void); ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf); ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf); diff --git a/lede/target/linux/generic/pending-6.1/510-block-add-uImage.FIT-subimage-block-driver.patch b/lede/target/linux/generic/pending-6.1/510-block-add-uImage.FIT-subimage-block-driver.patch new file mode 100644 index 0000000000..7ee66b318c --- /dev/null +++ b/lede/target/linux/generic/pending-6.1/510-block-add-uImage.FIT-subimage-block-driver.patch @@ -0,0 +1,732 @@ +From 6173a065cb395d4a9528c4e49810af127db68141 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 16 Nov 2022 12:49:52 +0000 +Subject: [PATCH 1/2] block: add uImage.FIT subimage block driver + +Add a small block driver which exposes filesystem sub-images contained +in U-Boot uImage.FIT images as block devices. + +The uImage.FIT image has to be stored directly on a block device or +partition, MTD device or partition, or UBI volume. + +The driver is intended for systems using the U-Boot bootloader and +uses the root device hint left by the bootloader (or the user) in +the 'chosen' section of the device-tree. + +Example: +/dts-v1/; +/ { + chosen { + rootdisk = <&mmc0_part3>; + }; +}; + +Signed-off-by: Daniel Golle +--- + MAINTAINERS | 6 + + drivers/block/Kconfig | 12 + + drivers/block/Makefile | 2 + + drivers/block/fitblk.c | 658 ++++++++++++++++++++++++++++++++++++ + drivers/block/open | 4 + + include/uapi/linux/fitblk.h | 10 + + 6 files changed, 692 insertions(+) + create mode 100644 drivers/block/fitblk.c + create mode 100644 drivers/block/open + create mode 100644 include/uapi/linux/fitblk.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -21052,6 +21052,12 @@ F: Documentation/filesystems/ubifs-authe + F: Documentation/filesystems/ubifs.rst + F: fs/ubifs/ + ++U-BOOT UIMAGE.FIT PARSER ++M: Daniel Golle ++L: linux-block@vger.kernel.org ++S: Maintained ++F: drivers/block/fitblk.c ++ + UBLK USERSPACE BLOCK DRIVER + M: Ming Lei + L: linux-block@vger.kernel.org +--- a/drivers/block/Kconfig ++++ b/drivers/block/Kconfig +@@ -383,6 +383,18 @@ config VIRTIO_BLK + This is the virtual block driver for virtio. It can be used with + QEMU based VMMs (like KVM or Xen). Say Y or M. + ++config UIMAGE_FIT_BLK ++ bool "uImage.FIT block driver" ++ help ++ This driver allows using filesystems contained in uImage.FIT images ++ by mapping them as block devices. ++ ++ It can currently not be built as a module due to libfdt symbols not ++ being exported. ++ ++ Say Y if you want to mount filesystems sub-images of a uImage.FIT ++ stored in a block device partition, mtdblock or ubiblock device. ++ + config BLK_DEV_RBD + tristate "Rados block device (RBD)" + depends on INET && BLOCK +--- a/drivers/block/Makefile ++++ b/drivers/block/Makefile +@@ -39,4 +39,6 @@ obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_b + + obj-$(CONFIG_BLK_DEV_UBLK) += ublk_drv.o + ++obj-$(CONFIG_UIMAGE_FIT_BLK) += fitblk.o ++ + swim_mod-y := swim.o swim_asm.o +--- /dev/null ++++ b/drivers/block/fitblk.c +@@ -0,0 +1,635 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * uImage.FIT virtual block device driver. ++ * ++ * Copyright (C) 2023 Daniel Golle ++ * Copyright (C) 2007 Nick Piggin ++ * Copyright (C) 2007 Novell Inc. ++ * ++ * Initially derived from drivers/block/brd.c which is in parts derived from ++ * drivers/block/rd.c, and drivers/block/loop.c, copyright of their respective ++ * owners. ++ * ++ * uImage.FIT headers extracted from Das U-Boot ++ * (C) Copyright 2008 Semihalf ++ * (C) Copyright 2000-2005 ++ * Wolfgang Denk, DENX Software Engineering, wd@denx.de. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define FIT_DEVICE_PREFIX "fit" ++ ++/* maximum number of pages used for the uImage.FIT index structure */ ++#define FIT_MAX_PAGES 1024 ++ ++/* minimum free sectors to map as read-write "remainder" volume */ ++#define MIN_FREE_SECT 16 ++ ++/* maximum number of mapped loadables */ ++#define MAX_FIT_LOADABLES 16 ++ ++/* constants for uImage.FIT structrure traversal */ ++#define FIT_IMAGES_PATH "/images" ++#define FIT_CONFS_PATH "/configurations" ++ ++/* hash/signature/key node */ ++#define FIT_HASH_NODENAME "hash" ++#define FIT_ALGO_PROP "algo" ++#define FIT_VALUE_PROP "value" ++#define FIT_IGNORE_PROP "uboot-ignore" ++#define FIT_SIG_NODENAME "signature" ++#define FIT_KEY_REQUIRED "required" ++#define FIT_KEY_HINT "key-name-hint" ++ ++/* cipher node */ ++#define FIT_CIPHER_NODENAME "cipher" ++#define FIT_ALGO_PROP "algo" ++ ++/* image node */ ++#define FIT_DATA_PROP "data" ++#define FIT_DATA_POSITION_PROP "data-position" ++#define FIT_DATA_OFFSET_PROP "data-offset" ++#define FIT_DATA_SIZE_PROP "data-size" ++#define FIT_TIMESTAMP_PROP "timestamp" ++#define FIT_DESC_PROP "description" ++#define FIT_ARCH_PROP "arch" ++#define FIT_TYPE_PROP "type" ++#define FIT_OS_PROP "os" ++#define FIT_COMP_PROP "compression" ++#define FIT_ENTRY_PROP "entry" ++#define FIT_LOAD_PROP "load" ++ ++/* configuration node */ ++#define FIT_KERNEL_PROP "kernel" ++#define FIT_FILESYSTEM_PROP "filesystem" ++#define FIT_RAMDISK_PROP "ramdisk" ++#define FIT_FDT_PROP "fdt" ++#define FIT_LOADABLE_PROP "loadables" ++#define FIT_DEFAULT_PROP "default" ++#define FIT_SETUP_PROP "setup" ++#define FIT_FPGA_PROP "fpga" ++#define FIT_FIRMWARE_PROP "firmware" ++#define FIT_STANDALONE_PROP "standalone" ++ ++/* fitblk driver data */ ++static const char *_fitblk_claim_ptr = "I belong to fitblk"; ++static const char *ubootver; ++struct device_node *rootdisk; ++static struct platform_device *pdev; ++static LIST_HEAD(fitblk_devices); ++static DEFINE_MUTEX(devices_mutex); ++refcount_t num_devs; ++ ++struct fitblk { ++ struct platform_device *pdev; ++ struct block_device *lower_bdev; ++ sector_t start_sect; ++ struct gendisk *disk; ++ struct work_struct remove_work; ++ struct list_head list; ++ bool dead; ++}; ++ ++static int fitblk_open(struct block_device *bdev, fmode_t mode) ++{ ++ struct fitblk *fitblk = bdev->bd_disk->private_data; ++ ++ if (fitblk->dead) ++ return -ENOENT; ++ ++ return 0; ++} ++ ++static void fitblk_release(struct gendisk *disk, fmode_t mode) ++{ ++ return; ++} ++ ++static void fitblk_submit_bio(struct bio *orig_bio) ++{ ++ struct bio *bio = orig_bio; ++ struct fitblk *fitblk = bio->bi_bdev->bd_disk->private_data; ++ ++ if (fitblk->dead) ++ return; ++ ++ /* mangle bio and re-submit */ ++ while (bio) { ++ bio->bi_iter.bi_sector += fitblk->start_sect; ++ bio->bi_bdev = fitblk->lower_bdev; ++ bio = bio->bi_next; ++ } ++ submit_bio(orig_bio); ++} ++ ++static void fitblk_remove(struct fitblk *fitblk) ++{ ++ blk_mark_disk_dead(fitblk->disk); ++ mutex_lock(&devices_mutex); ++ fitblk->dead = true; ++ list_del(&fitblk->list); ++ mutex_unlock(&devices_mutex); ++ ++ schedule_work(&fitblk->remove_work); ++} ++ ++static int fitblk_ioctl(struct block_device *bdev, fmode_t mode, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct fitblk *fitblk = bdev->bd_disk->private_data; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EACCES; ++ ++ if (fitblk->dead) ++ return -ENOENT; ++ ++ switch (cmd) { ++ case FITBLK_RELEASE: ++ fitblk_remove(fitblk); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct block_device_operations fitblk_fops = { ++ .owner = THIS_MODULE, ++ .ioctl = fitblk_ioctl, ++ .open = fitblk_open, ++ .release = fitblk_release, ++ .submit_bio = fitblk_submit_bio, ++}; ++ ++static void fitblk_purge(struct work_struct *work) ++{ ++ struct fitblk *fitblk = container_of(work, struct fitblk, remove_work); ++ ++ //del_gendisk(fitblk->disk); // causes crash, not doing it doesn't matter ++ refcount_dec(&num_devs); ++ platform_device_del(fitblk->pdev); ++ platform_device_put(fitblk->pdev); ++ ++ if (refcount_dec_if_one(&num_devs)) { ++ sysfs_remove_link(&pdev->dev.kobj, "lower_dev"); ++ blkdev_put(fitblk->lower_bdev, FMODE_READ | FMODE_EXCL); ++ } ++ ++ kfree(fitblk); ++} ++ ++static int add_fit_subimage_device(struct block_device *lower_bdev, ++ unsigned int slot, sector_t start_sect, ++ sector_t nr_sect, bool readonly) ++{ ++ struct fitblk *fitblk; ++ struct gendisk *disk; ++ int err; ++ ++ mutex_lock(&devices_mutex); ++ if (!refcount_inc_not_zero(&num_devs)) ++ return -EBADF; ++ ++ fitblk = kzalloc(sizeof(struct fitblk), GFP_KERNEL); ++ if (!fitblk) { ++ err = -ENOMEM; ++ goto out_unlock; ++ } ++ ++ fitblk->lower_bdev = lower_bdev; ++ fitblk->start_sect = start_sect; ++ INIT_WORK(&fitblk->remove_work, fitblk_purge); ++ ++ disk = blk_alloc_disk(NUMA_NO_NODE); ++ if (!disk) { ++ err = -ENOMEM; ++ goto out_free_fitblk; ++ } ++ ++ disk->first_minor = 0; ++ disk->flags = lower_bdev->bd_disk->flags | GENHD_FL_NO_PART; ++ disk->fops = &fitblk_fops; ++ disk->private_data = fitblk; ++ if (readonly) { ++ set_disk_ro(disk, 1); ++ snprintf(disk->disk_name, sizeof(disk->disk_name), FIT_DEVICE_PREFIX "%u", slot); ++ } else { ++ strcpy(disk->disk_name, FIT_DEVICE_PREFIX "rw"); ++ } ++ ++ set_capacity(disk, nr_sect); ++ ++ disk->queue->queue_flags = lower_bdev->bd_disk->queue->queue_flags; ++ memcpy(&disk->queue->limits, &lower_bdev->bd_disk->queue->limits, ++ sizeof(struct queue_limits)); ++ ++ fitblk->disk = disk; ++ fitblk->pdev = platform_device_alloc(disk->disk_name, PLATFORM_DEVID_NONE); ++ if (!fitblk->pdev) { ++ err = -ENOMEM; ++ goto out_cleanup_disk; ++ } ++ ++ fitblk->pdev->dev.parent = &pdev->dev; ++ err = platform_device_add(fitblk->pdev); ++ if (err) ++ goto out_put_pdev; ++ ++ err = device_add_disk(&fitblk->pdev->dev, disk, NULL); ++ if (err) ++ goto out_del_pdev; ++ ++ if (!ROOT_DEV) ++ ROOT_DEV = disk->part0->bd_dev; ++ ++ list_add_tail(&fitblk->list, &fitblk_devices); ++ ++ mutex_unlock(&devices_mutex); ++ ++ return 0; ++ ++out_del_pdev: ++ platform_device_del(fitblk->pdev); ++out_put_pdev: ++ platform_device_put(fitblk->pdev); ++out_cleanup_disk: ++ put_disk(disk); ++out_free_fitblk: ++ kfree(fitblk); ++out_unlock: ++ refcount_dec(&num_devs); ++ mutex_unlock(&devices_mutex); ++ return err; ++} ++ ++static int parse_fit_on_dev(struct device *dev) ++{ ++ struct block_device *bdev; ++ struct address_space *mapping; ++ struct folio *folio; ++ pgoff_t f_index = 0; ++ size_t bytes_left, bytes_to_copy; ++ void *pre_fit, *fit, *fit_c; ++ u64 dsize, dsectors, imgmaxsect = 0; ++ u32 size, image_pos, image_len; ++ const __be32 *image_offset_be, *image_len_be, *image_pos_be; ++ int ret = 0, node, images, config; ++ const char *image_name, *image_type, *image_description, ++ *config_default, *config_description, *config_loadables; ++ u32 image_name_len, image_type_len, image_description_len, ++ bootconf_len, config_default_len, config_description_len, ++ config_loadables_len; ++ sector_t start_sect, nr_sects; ++ struct device_node *np = NULL; ++ const char *bootconf_c; ++ const char *loadable; ++ char *bootconf = NULL, *bootconf_term; ++ bool found; ++ int loadables_rem_len, loadable_len; ++ u16 loadcnt; ++ unsigned int slot = 0; ++ ++ /* Exclusive open the block device to receive holder notifications */ ++ bdev = blkdev_get_by_dev(dev->devt, FMODE_READ | FMODE_EXCL, &_fitblk_claim_ptr); ++ if (!bdev) ++ return -ENODEV; ++ ++ if (IS_ERR(bdev)) ++ return PTR_ERR(bdev); ++ ++ mapping = bdev->bd_inode->i_mapping; ++ ++ /* map first page */ ++ folio = read_mapping_folio(mapping, f_index++, NULL); ++ if (IS_ERR(folio)) { ++ ret = PTR_ERR(folio); ++ goto out_blkdev; ++ } ++ pre_fit = folio_address(folio) + offset_in_folio(folio, 0); ++ ++ /* uImage.FIT is based on flattened device tree structure */ ++ if (fdt_check_header(pre_fit)) { ++ ret = -EINVAL; ++ folio_put(folio); ++ goto out_blkdev; ++ } ++ ++ size = fdt_totalsize(pre_fit); ++ ++ if (size > PAGE_SIZE * FIT_MAX_PAGES) { ++ ret = -EOPNOTSUPP; ++ folio_put(folio); ++ goto out_blkdev; ++ } ++ ++ /* acquire disk size */ ++ dsectors = bdev_nr_sectors(bdev); ++ dsize = dsectors << SECTOR_SHIFT; ++ ++ /* abort if FIT structure is larger than disk or partition size */ ++ if (size >= dsize) { ++ ret = -EFBIG; ++ folio_put(folio); ++ goto out_blkdev; ++ } ++ ++ fit = kmalloc(size, GFP_KERNEL); ++ if (!fit) { ++ ret = -ENOMEM; ++ folio_put(folio); ++ goto out_blkdev; ++ } ++ ++ bytes_left = size; ++ fit_c = fit; ++ while (bytes_left > 0) { ++ bytes_to_copy = min(bytes_left, folio_size(folio) - offset_in_folio(folio, 0)); ++ memcpy(fit_c, pre_fit, bytes_to_copy); ++ fit_c += bytes_to_copy; ++ bytes_left -= bytes_to_copy; ++ if (bytes_left) { ++ folio_put(folio); ++ folio = read_mapping_folio(mapping, f_index++, NULL); ++ if (IS_ERR(folio)) { ++ ret = PTR_ERR(folio); ++ goto out_blkdev; ++ }; ++ pre_fit = folio_address(folio) + offset_in_folio(folio, 0); ++ } ++ } ++ folio_put(folio); ++ ++ /* set boot config node name U-Boot may have added to the device tree */ ++ np = of_find_node_by_path("/chosen"); ++ if (np) { ++ bootconf_c = of_get_property(np, "u-boot,bootconf", &bootconf_len); ++ if (bootconf_c && bootconf_len) ++ bootconf = kmemdup_nul(bootconf_c, bootconf_len, GFP_KERNEL); ++ } ++ ++ if (bootconf) { ++ bootconf_term = strchr(bootconf, '#'); ++ if (bootconf_term) ++ *bootconf_term = '\0'; ++ } ++ ++ /* find configuration path in uImage.FIT */ ++ config = fdt_path_offset(fit, FIT_CONFS_PATH); ++ if (config < 0) { ++ pr_err("FIT: Cannot find %s node: %d\n", ++ FIT_CONFS_PATH, config); ++ ret = -ENOENT; ++ goto out_bootconf; ++ } ++ ++ /* get default configuration node name */ ++ config_default = ++ fdt_getprop(fit, config, FIT_DEFAULT_PROP, &config_default_len); ++ ++ /* make sure we got either default or selected boot config node name */ ++ if (!config_default && !bootconf) { ++ pr_err("FIT: Cannot find default configuration\n"); ++ ret = -ENOENT; ++ goto out_bootconf; ++ } ++ ++ /* find selected boot config node, fallback on default config node */ ++ node = fdt_subnode_offset(fit, config, bootconf ?: config_default); ++ if (node < 0) { ++ pr_err("FIT: Cannot find %s node: %d\n", ++ bootconf ?: config_default, node); ++ ret = -ENOENT; ++ goto out_bootconf; ++ } ++ ++ pr_info("FIT: Detected U-Boot %s\n", ubootver); ++ ++ /* get selected configuration data */ ++ config_description = ++ fdt_getprop(fit, node, FIT_DESC_PROP, &config_description_len); ++ config_loadables = fdt_getprop(fit, node, FIT_LOADABLE_PROP, ++ &config_loadables_len); ++ ++ pr_info("FIT: %s configuration: \"%.*s\"%s%.*s%s\n", ++ bootconf ? "Selected" : "Default", ++ bootconf ? bootconf_len : config_default_len, ++ bootconf ?: config_default, ++ config_description ? " (" : "", ++ config_description ? config_description_len : 0, ++ config_description ?: "", ++ config_description ? ")" : ""); ++ ++ if (!config_loadables || !config_loadables_len) { ++ pr_err("FIT: No loadables configured in \"%s\"\n", ++ bootconf ?: config_default); ++ ret = -ENOENT; ++ goto out_bootconf; ++ } ++ ++ /* get images path in uImage.FIT */ ++ images = fdt_path_offset(fit, FIT_IMAGES_PATH); ++ if (images < 0) { ++ pr_err("FIT: Cannot find %s node: %d\n", FIT_IMAGES_PATH, images); ++ ret = -EINVAL; ++ goto out_bootconf; ++ } ++ ++ /* iterate over images in uImage.FIT */ ++ fdt_for_each_subnode(node, fit, images) { ++ image_name = fdt_get_name(fit, node, &image_name_len); ++ image_type = fdt_getprop(fit, node, FIT_TYPE_PROP, &image_type_len); ++ image_offset_be = fdt_getprop(fit, node, FIT_DATA_OFFSET_PROP, NULL); ++ image_pos_be = fdt_getprop(fit, node, FIT_DATA_POSITION_PROP, NULL); ++ image_len_be = fdt_getprop(fit, node, FIT_DATA_SIZE_PROP, NULL); ++ ++ if (!image_name || !image_type || !image_len_be || ++ !image_name_len || !image_type_len) ++ continue; ++ ++ image_len = be32_to_cpu(*image_len_be); ++ if (!image_len) ++ continue; ++ ++ if (image_offset_be) ++ image_pos = be32_to_cpu(*image_offset_be) + size; ++ else if (image_pos_be) ++ image_pos = be32_to_cpu(*image_pos_be); ++ else ++ continue; ++ ++ image_description = fdt_getprop(fit, node, FIT_DESC_PROP, ++ &image_description_len); ++ ++ pr_info("FIT: %16s sub-image 0x%08x..0x%08x \"%.*s\"%s%.*s%s\n", ++ image_type, image_pos, image_pos + image_len - 1, ++ image_name_len, image_name, image_description ? " (" : "", ++ image_description ? image_description_len : 0, ++ image_description ?: "", image_description ? ") " : ""); ++ ++ /* only 'filesystem' images should be mapped as partitions */ ++ if (strncmp(image_type, FIT_FILESYSTEM_PROP, image_type_len)) ++ continue; ++ ++ /* check if sub-image is part of configured loadables */ ++ found = false; ++ loadable = config_loadables; ++ loadables_rem_len = config_loadables_len; ++ for (loadcnt = 0; loadables_rem_len > 1 && ++ loadcnt < MAX_FIT_LOADABLES; ++loadcnt) { ++ loadable_len = ++ strnlen(loadable, loadables_rem_len - 1) + 1; ++ loadables_rem_len -= loadable_len; ++ if (!strncmp(image_name, loadable, loadable_len)) { ++ found = true; ++ break; ++ } ++ loadable += loadable_len; ++ } ++ if (!found) ++ continue; ++ ++ if (image_pos % (1 << PAGE_SHIFT)) { ++ dev_err(dev, "FIT: image %.*s start not aligned to page boundaries, skipping\n", ++ image_name_len, image_name); ++ continue; ++ } ++ ++ if (image_len % (1 << PAGE_SHIFT)) { ++ dev_err(dev, "FIT: sub-image %.*s end not aligned to page boundaries, skipping\n", ++ image_name_len, image_name); ++ continue; ++ } ++ ++ start_sect = image_pos >> SECTOR_SHIFT; ++ nr_sects = image_len >> SECTOR_SHIFT; ++ imgmaxsect = max_t(sector_t, imgmaxsect, start_sect + nr_sects); ++ ++ if (start_sect + nr_sects > dsectors) { ++ dev_err(dev, "FIT: sub-image %.*s disk access beyond EOD\n", ++ image_name_len, image_name); ++ continue; ++ } ++ ++ if (!slot) { ++ ret = sysfs_create_link_nowarn(&pdev->dev.kobj, bdev_kobj(bdev), "lower_dev"); ++ if (ret && ret != -EEXIST) ++ goto out_bootconf; ++ ++ ret = 0; ++ } ++ ++ add_fit_subimage_device(bdev, slot++, start_sect, nr_sects, true); ++ } ++ ++ if (!found || !slot) ++ goto out_bootconf; ++ ++ dev_info(dev, "mapped %u uImage.FIT filesystem sub-image%s as /dev/fit%s%u%s\n", ++ slot, (slot > 1)?"s":"", (slot > 1)?"[0...":"", slot - 1, ++ (slot > 1)?"]":""); ++ ++ /* in case uImage.FIT is stored in a partition, map the remaining space */ ++ if (!bdev->bd_read_only && bdev_is_partition(bdev) && ++ (imgmaxsect + MIN_FREE_SECT) < dsectors) { ++ add_fit_subimage_device(bdev, slot++, imgmaxsect, ++ dsectors - imgmaxsect, false); ++ dev_info(dev, "mapped remaing space as /dev/fitrw\n"); ++ } ++ ++out_bootconf: ++ kfree(bootconf); ++ kfree(fit); ++out_blkdev: ++ if (!found || ret) ++ blkdev_put(bdev, FMODE_READ | FMODE_EXCL); ++ ++ return ret; ++} ++ ++static int fitblk_match_of_node(struct device *dev, const void *np) ++{ ++ int ret; ++ ++ ret = device_match_of_node(dev, np); ++ if (ret) ++ return ret; ++ ++ /* ++ * To match ubiblock and mtdblock devices by their parent ubi ++ * or mtd device, also consider block device parent ++ */ ++ if (!dev->parent) ++ return 0; ++ ++ return device_match_of_node(dev->parent, np); ++} ++ ++static int fitblk_probe(struct platform_device *pdev) ++{ ++ struct device *dev; ++ ++ dev = class_find_device(&block_class, NULL, rootdisk, fitblk_match_of_node); ++ if (!dev) ++ return -EPROBE_DEFER; ++ ++ return parse_fit_on_dev(dev); ++} ++ ++static struct platform_driver fitblk_driver = { ++ .probe = fitblk_probe, ++ .driver = { ++ .name = "fitblk", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init fitblk_init(void) ++{ ++ /* detect U-Boot firmware */ ++ ubootver = of_get_property(of_chosen, "u-boot,version", NULL); ++ if (!ubootver) ++ return 0; ++ ++ /* parse 'rootdisk' property phandle */ ++ rootdisk = of_parse_phandle(of_chosen, "rootdisk", 0); ++ if (!rootdisk) ++ return 0; ++ ++ if (platform_driver_register(&fitblk_driver)) ++ return -ENODEV; ++ ++ refcount_set(&num_devs, 1); ++ pdev = platform_device_register_simple("fitblk", -1, NULL, 0); ++ if (IS_ERR(pdev)) ++ return PTR_ERR(pdev); ++ ++ return 0; ++} ++device_initcall(fitblk_init); +--- /dev/null ++++ b/include/uapi/linux/fitblk.h +@@ -0,0 +1,10 @@ ++/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ ++#ifndef _UAPI_LINUX_FITBLK_H ++#define _UAPI_LINUX_FITBLK_H ++ ++/* ++ * IOCTL commands --- we will commandeer 0x46 ('F') ++ */ ++#define FITBLK_RELEASE 0x4600 ++ ++#endif /* _UAPI_LINUX_FITBLK_H */ diff --git a/lede/target/linux/generic/pending-6.1/511-init-bypass-device-lookup-for-dev-fit-rootfs.patch b/lede/target/linux/generic/pending-6.1/511-init-bypass-device-lookup-for-dev-fit-rootfs.patch new file mode 100644 index 0000000000..685a5f9da5 --- /dev/null +++ b/lede/target/linux/generic/pending-6.1/511-init-bypass-device-lookup-for-dev-fit-rootfs.patch @@ -0,0 +1,25 @@ +From 5ede3f8aed9a1a579bf7304142600d1f3500add9 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 12 Jun 2023 03:58:42 +0100 +Subject: [PATCH 2/2] init: bypass device lookup for /dev/fit* rootfs + +Allow 'rootwait' as /dev/fit* can show up late if the underlaying +device is probed late. + +Signed-off-by: Daniel Golle +--- + init/do_mounts.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -645,7 +645,8 @@ void __init prepare_namespace(void) + + if (saved_root_name[0]) { + root_device_name = saved_root_name; +- if (!strncmp(root_device_name, "mtd", 3) || ++ if (!strncmp(root_device_name, "fit", 3) || ++ !strncmp(root_device_name, "mtd", 3) || + !strncmp(root_device_name, "ubi", 3)) { + mount_block_root(root_device_name, root_mountflags); + goto out; diff --git a/lede/target/linux/mediatek/Makefile b/lede/target/linux/mediatek/Makefile index b60b94de69..0175e62c17 100644 --- a/lede/target/linux/mediatek/Makefile +++ b/lede/target/linux/mediatek/Makefile @@ -8,8 +8,8 @@ BOARDNAME:=MediaTek Ralink ARM SUBTARGETS:=mt7622 mt7623 mt7629 filogic FEATURES:=dt-overlay emmc fpu gpio nand pci pcie rootfs-part separate_ramdisk squashfs usb -KERNEL_PATCHVER:=6.6 -KERNEL_TESTING_PATCHVER:=6.1 +KERNEL_PATCHVER:=6.1 +KERNEL_TESTING_PATCHVER:=6.6 include $(INCLUDE_DIR)/target.mk DEFAULT_PACKAGES += \ diff --git a/lede/target/linux/mediatek/base-files/etc/uci-defaults/99_fwenv-store-ethaddr.sh b/lede/target/linux/mediatek/base-files/etc/uci-defaults/99_fwenv-store-ethaddr.sh index e9cb4f921d..276ec1b19a 100644 --- a/lede/target/linux/mediatek/base-files/etc/uci-defaults/99_fwenv-store-ethaddr.sh +++ b/lede/target/linux/mediatek/base-files/etc/uci-defaults/99_fwenv-store-ethaddr.sh @@ -10,7 +10,6 @@ unielec,u7623-02) fw_setenv ethaddr "$(cat /sys/class/net/eth0/address)" ;; bananapi,bpi-r3|\ -bananapi,bpi-r3-mini|\ bananapi,bpi-r4|\ bananapi,bpi-r4-poe) [ -z "$(fw_printenv -n ethaddr 2>/dev/null)" ] && diff --git a/lede/target/linux/mediatek/dts/mt7986a-hf-m7986r1-emmc.dts b/lede/target/linux/mediatek/dts/mt7986a-hf-m7986r1-emmc.dts index eeeb632417..2fa31817f1 100644 --- a/lede/target/linux/mediatek/dts/mt7986a-hf-m7986r1-emmc.dts +++ b/lede/target/linux/mediatek/dts/mt7986a-hf-m7986r1-emmc.dts @@ -10,91 +10,5 @@ chosen { bootargs = "root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs"; }; - - reg_1p8v: regulator-1p8v { - compatible = "regulator-fixed"; - regulator-name = "fixed-1.8V"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-always-on; - }; }; -&mmc0 { - bus-width = <8>; - cap-mmc-highspeed; - hs400-ds-delay = <0x14014>; - max-frequency = <200000000>; - mmc-hs200-1_8v; - mmc-hs400-1_8v; - no-sd; - no-sdio; - non-removable; - pinctrl-names = "default", "state_uhs"; - pinctrl-0 = <&mmc0_pins_default>; - pinctrl-1 = <&mmc0_pins_uhs>; - vmmc-supply = <®_3p3v>; - vqmmc-supply = <®_1p8v>; - status = "okay"; -}; - -&pio { - mmc0_pins_default: mmc0-pins-default { - mux { - function = "emmc"; - groups = "emmc_51"; - }; - conf-cmd-dat { - pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", - "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", - "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; - input-enable; - drive-strength = <4>; - mediatek,pull-up-adv = <1>; - }; - conf-clk { - pins = "EMMC_CK"; - drive-strength = <6>; - mediatek,pull-down-adv = <2>; - }; - conf-ds { - pins = "EMMC_DSL"; - mediatek,pull-down-adv = <2>; - }; - conf-rst { - pins = "EMMC_RSTB"; - drive-strength = <4>; - mediatek,pull-up-adv = <1>; - }; - }; - - mmc0_pins_uhs: mmc0-uhs-pins { - mux { - function = "emmc"; - groups = "emmc_51"; - }; - conf-cmd-dat { - pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", - "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", - "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; - input-enable; - drive-strength = <4>; - mediatek,pull-up-adv = <1>; - }; - conf-clk { - pins = "EMMC_CK"; - drive-strength = <6>; - mediatek,pull-down-adv = <2>; - }; - conf-ds { - pins = "EMMC_DSL"; - mediatek,pull-down-adv = <2>; - }; - conf-rst { - pins = "EMMC_RSTB"; - drive-strength = <4>; - mediatek,pull-up-adv = <1>; - }; - }; -}; diff --git a/lede/target/linux/mediatek/dts/mt7986a-hf-m7986r1.dtsi b/lede/target/linux/mediatek/dts/mt7986a-hf-m7986r1.dtsi index f4c58812ce..81011c59a7 100644 --- a/lede/target/linux/mediatek/dts/mt7986a-hf-m7986r1.dtsi +++ b/lede/target/linux/mediatek/dts/mt7986a-hf-m7986r1.dtsi @@ -86,6 +86,15 @@ regulator-boot-on; regulator-always-on; }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; }; &crypto { @@ -185,6 +194,64 @@ output-low; }; }; + + mmc0_pins_default: mmc0-pins-default { + mux { + function = "emmc"; + groups = "emmc_51"; + }; + conf-cmd-dat { + pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", + "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", + "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; + input-enable; + drive-strength = <4>; + mediatek,pull-up-adv = <1>; + }; + conf-clk { + pins = "EMMC_CK"; + drive-strength = <6>; + mediatek,pull-down-adv = <2>; + }; + conf-ds { + pins = "EMMC_DSL"; + mediatek,pull-down-adv = <2>; + }; + conf-rst { + pins = "EMMC_RSTB"; + drive-strength = <4>; + mediatek,pull-up-adv = <1>; + }; + }; + + mmc0_pins_uhs: mmc0-uhs-pins { + mux { + function = "emmc"; + groups = "emmc_51"; + }; + conf-cmd-dat { + pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", + "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", + "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; + input-enable; + drive-strength = <4>; + mediatek,pull-up-adv = <1>; + }; + conf-clk { + pins = "EMMC_CK"; + drive-strength = <6>; + mediatek,pull-down-adv = <2>; + }; + conf-ds { + pins = "EMMC_DSL"; + mediatek,pull-down-adv = <2>; + }; + conf-rst { + pins = "EMMC_RSTB"; + drive-strength = <4>; + mediatek,pull-up-adv = <1>; + }; + }; }; &ssusb { @@ -249,3 +316,22 @@ &watchdog { status = "okay"; }; + +&mmc0 { + bus-width = <8>; + cap-mmc-highspeed; + hs400-ds-delay = <0x14014>; + max-frequency = <200000000>; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + no-sd; + no-sdio; + non-removable; + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_default>; + pinctrl-1 = <&mmc0_pins_uhs>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; + status = "okay"; +}; + diff --git a/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso new file mode 100644 index 0000000000..4945185d69 --- /dev/null +++ b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2021 MediaTek Inc. + * Author: Frank Wunderlich + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; + + fragment@0 { + target-path = "/soc/mmc@11230000"; + __overlay__ { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_emmc_51>; + pinctrl-1 = <&mmc0_pins_emmc_51>; + bus-width = <8>; + max-frequency = <200000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + hs400-ds-delay = <0x12814>; + vqmmc-supply = <®_1p8v>; + vmmc-supply = <®_3p3v>; + non-removable; + no-sd; + no-sdio; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + block { + compatible = "block-device"; + partitions { + block-partition-env { + partname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-layout"; + }; + }; + emmc_rootfs: block-partition-production { + partname = "production"; + }; + }; + }; + }; + }; + }; + + fragment@2 { + target-path = "/chosen"; + __overlay__ { + rootdisk-emmc = <&emmc_rootfs>; + }; + }; +}; diff --git a/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-poe.dts b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-poe.dts new file mode 100644 index 0000000000..58f0bf3f7d --- /dev/null +++ b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-poe.dts @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +#include "mt7988a-bananapi-bpi-r4.dts" + +/ { + model = "Bananapi BPI-R4 2.5GE PoE"; + compatible = "bananapi,bpi-r4-poe", + "mediatek,mt7988a"; +}; + +&gmac1 { + phy-mode = "internal"; + phy-connection-type = "internal"; + phy = <&int_2p5g_phy>; + status = "okay"; +}; + +&int_2p5g_phy { + pinctrl-names = "i2p5gbe-led"; + pinctrl-0 = <&i2p5gbe_led0_pins>; +}; diff --git a/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso new file mode 100644 index 0000000000..39910b8cfe --- /dev/null +++ b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 + * Author: Daniel Golle + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; + + fragment@0 { + target = <&pcf8563>; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso new file mode 100644 index 0000000000..1f5e1491a4 --- /dev/null +++ b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 MediaTek Inc. + * Author: Frank Wunderlich + */ + +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; + + fragment@1 { + target-path = "/soc/mmc@11230000"; + __overlay__ { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_sdcard>; + pinctrl-1 = <&mmc0_pins_sdcard>; + cd-gpios = <&pio 12 GPIO_ACTIVE_LOW>; + bus-width = <4>; + max-frequency = <52000000>; + cap-sd-highspeed; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; + no-mmc; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + block { + compatible = "block-device"; + partitions { + block-partition-env { + partname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-layout"; + }; + }; + sd_rootfs: block-partition-production { + partname = "production"; + }; + }; + }; + }; + }; + }; + + fragment@2 { + target-path = "/chosen"; + __overlay__ { + rootdisk-sd = <&sd_rootfs>; + }; + }; +}; diff --git a/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-wifi-mt7996a.dtso b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-wifi-mt7996a.dtso new file mode 100644 index 0000000000..8a029b149f --- /dev/null +++ b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-wifi-mt7996a.dtso @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; + + fragment@0 { + target-path = "/"; + __overlay__ { + wifi_12v: regulator-wifi-12v { + compatible = "regulator-fixed"; + regulator-name = "wifi"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + gpio = <&pio 4 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + }; + }; + }; + + fragment@1 { + target = <&i2c_wifi>; + __overlay__ { + // 5G WIFI MAC Address EEPROM + wifi_eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + address-bits = <8>; + page-size = <8>; + size = <256>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_5g: macaddr@0 { + reg = <0x0 0x6>; + }; + }; + }; + + // 6G WIFI MAC Address EEPROM + wifi_eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + address-bits = <8>; + page-size = <8>; + size = <256>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_6g: macaddr@0 { + reg = <0x0 0x6>; + }; + }; + }; + }; + }; + + fragment@2 { + target = <&pcie0>; + __overlay__ { + pcie@0,0 { + reg = <0x0000 0 0 0 0>; + + wifi@0,0 { + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + nvmem-cell-names = "mac-address"; + nvmem-cells = <&macaddr_5g>; + }; + }; + }; + }; + + fragment@3 { + target = <&pcie1>; + __overlay__ { + pcie@0,0 { + reg = <0x0000 0 0 0 0>; + + wifi@0,0 { + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + nvmem-cell-names = "mac-address"; + nvmem-cells = <&macaddr_6g>; + }; + }; + }; + }; +}; diff --git a/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts new file mode 100644 index 0000000000..b4bf3400ff --- /dev/null +++ b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +#include "mt7988a.dtsi" +#include +#include +#include +#include + +/ { + model = "Bananapi BPI-R4"; + compatible = "bananapi,bpi-r4", + "mediatek,mt7988"; + + aliases { + serial0 = &uart0; + led-boot = &led_green; + led-failsafe = &led_green; + led-running = &led_green; + led-upgrade = &led_green; + }; + + chosen { + stdout-path = &uart0; + bootargs = "console=ttyS0,115200n1 loglevel=8 pci=pcie_bus_perf ubi.block=0,fit root=/dev/fit0"; + rootdisk-spim-nand = <&ubi_rootfs>; + }; + + memory { + reg = <0x00 0x40000000 0x00 0x10000000>; + }; + + /* SFP1 cage (WAN) */ + sfp1: sfp1 { + compatible = "sff,sfp"; + i2c-bus = <&i2c_sfp1>; + los-gpios = <&pio 54 GPIO_ACTIVE_HIGH>; + mod-def0-gpios = <&pio 82 GPIO_ACTIVE_LOW>; + tx-disable-gpios = <&pio 70 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&pio 69 GPIO_ACTIVE_HIGH>; + rate-select0-gpios = <&pio 21 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <3000>; + }; + + /* SFP2 cage (LAN) */ + sfp2: sfp2 { + compatible = "sff,sfp"; + i2c-bus = <&i2c_sfp2>; + los-gpios = <&pio 2 GPIO_ACTIVE_HIGH>; + mod-def0-gpios = <&pio 83 GPIO_ACTIVE_LOW>; + tx-disable-gpios = <&pio 0 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&pio 1 GPIO_ACTIVE_HIGH>; + rate-select0-gpios = <&pio 3 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <3000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + + wps { + label = "WPS"; + linux,code = ; + gpios = <&pio 14 GPIO_ACTIVE_LOW>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + led_green: led-green { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&pio 79 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + led_blue: led-blue { + function = LED_FUNCTION_WPS; + color = ; + gpios = <&pio 63 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; +}; + +ð { + status = "okay"; +}; + +&gmac0 { + status = "okay"; +}; + +&gmac1 { + sfp = <&sfp2>; + managed = "in-band-status"; + phy-mode = "usxgmii"; + status = "okay"; +}; + +&gmac2 { + sfp = <&sfp1>; + managed = "in-band-status"; + phy-mode = "usxgmii"; + status = "okay"; +}; + +&switch { + status = "okay"; +}; + +&gsw_phy0 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe0_led0_pins>; +}; + +&gsw_port0 { + label = "wan"; +}; + +&gsw_phy0_led0 { + status = "okay"; + color = ; +}; + +&gsw_phy1 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe1_led0_pins>; +}; + +&gsw_phy1_led0 { + status = "okay"; + color = ; +}; + +&gsw_phy2 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe2_led0_pins>; +}; + +&gsw_phy2_led0 { + status = "okay"; + color = ; +}; + +&gsw_phy3 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe3_led0_pins>; +}; + +&gsw_phy3_led0 { + status = "okay"; + color = ; +}; + +&cpu0 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu1 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu2 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu3 { + proc-supply = <&rt5190_buck3>; +}; + +&cci { + proc-supply = <&rt5190_buck3>; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; + + rt5190a_64: rt5190a@64 { + compatible = "richtek,rt5190a"; + reg = <0x64>; + vin2-supply = <&rt5190_buck1>; + vin3-supply = <&rt5190_buck1>; + vin4-supply = <&rt5190_buck1>; + + regulators { + rt5190_buck1: buck1 { + regulator-name = "rt5190a-buck1"; + regulator-min-microvolt = <5090000>; + regulator-max-microvolt = <5090000>; + regulator-allowed-modes = + ; + regulator-boot-on; + regulator-always-on; + }; + buck2 { + regulator-name = "vcore"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + }; + rt5190_buck3: buck3 { + regulator-name = "vproc"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + }; + buck4 { + regulator-name = "rt5190a-buck4"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-allowed-modes = + ; + regulator-boot-on; + regulator-always-on; + }; + ldo { + regulator-name = "rt5190a-ldo"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_1_pins>; + status = "okay"; + + pca9545: i2c-switch@70 { + reg = <0x70>; + compatible = "nxp,pca9545"; + reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>; + #address-cells = <1>; + #size-cells = <0>; + + i2c_rtc: i2c@0 { //eeprom,rtc,ngff + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + address-bits = <8>; + page-size = <8>; + size = <256>; + }; + + eeprom@57 { + compatible = "atmel,24c02"; + reg = <0x57>; + address-bits = <8>; + page-size = <8>; + size = <256>; + }; + + pcf8563: rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + status = "disabled"; + }; + }; + + i2c_sfp1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c_sfp2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c_wifi: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +/* mPCIe SIM2 */ +&pcie0 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_pins>; + status = "okay"; +}; + +/* mPCIe SIM3 */ +&pcie1 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_pins>; + status = "okay"; +}; + +/* M.2 key-B SIM1 */ +&pcie2 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_pins>; + status = "okay"; +}; + +/* M.2 key-M SSD */ +&pcie3 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie3_pins>; + status = "okay"; +}; + +&ssusb1 { + status = "okay"; +}; + +&tphy { + status = "okay"; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_flash_pins>; + status = "okay"; + + spi_nand: spi_nand@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <52000000>; + spi-tx-buswidth = <4>; + spi-rx-buswidth = <4>; + }; +}; + +&spi_nand { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl2"; + reg = <0x0 0x200000>; + read-only; + }; + + partition@200000 { + label = "ubi"; + reg = <0x200000 0x7e00000>; + compatible = "linux,ubi"; + + volumes { + ubi-volume-ubootenv { + volname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool-layout"; + }; + }; + + ubi-volume-ubootenv2 { + volname = "ubootenv2"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool-layout"; + }; + }; + + ubi_rootfs: ubi-volume-fit { + volname = "fit"; + }; + }; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; + +&xphy { + status = "okay"; +}; diff --git a/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 7fed1e1384..50b04e7773 100644 --- a/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/lede/target/linux/mediatek/files-6.1/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -1158,28 +1158,28 @@ #address-cells = <1>; #size-cells = <0>; - port@0 { + gsw_port0: port@0 { reg = <0>; label = "lan0"; phy-mode = "internal"; phy-handle = <&gsw_phy0>; }; - port@1 { + gsw_port1: port@1 { reg = <1>; label = "lan1"; phy-mode = "internal"; phy-handle = <&gsw_phy1>; }; - port@2 { + gsw_port2: port@2 { reg = <2>; label = "lan2"; phy-mode = "internal"; phy-handle = <&gsw_phy2>; }; - port@3 { + gsw_port3: port@3 { reg = <3>; label = "lan3"; phy-mode = "internal"; diff --git a/lede/target/linux/mediatek/files/block/partitions/fit.c b/lede/target/linux/mediatek/files/block/partitions/fit.c index 463cd4e9ab..0d531f49a3 100644 --- a/lede/target/linux/mediatek/files/block/partitions/fit.c +++ b/lede/target/linux/mediatek/files/block/partitions/fit.c @@ -73,7 +73,11 @@ int parse_fit_partitions(struct parsed_partitions *state, u64 fit_start_sector, u64 sectors, int *slot, int add_remain) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) struct block_device *bdev = state->disk->part0; +#else + struct block_device *bdev = state->bdev; +#endif struct address_space *mapping = bdev->bd_inode->i_mapping; struct page *page; void *fit, *init_fit; @@ -100,11 +104,8 @@ int parse_fit_partitions(struct parsed_partitions *state, u64 fit_start_sector, return -ERANGE; page = read_mapping_page(mapping, fit_start_sector >> (PAGE_SHIFT - SECTOR_SHIFT), NULL); - if (IS_ERR(page)) - return -EFAULT; - - if (PageError(page)) - return -EFAULT; + if (!page) + return -ENOMEM; init_fit = page_address(page); @@ -223,8 +224,8 @@ int parse_fit_partitions(struct parsed_partitions *state, u64 fit_start_sector, image_description = fdt_getprop(fit, node, FIT_DESC_PROP, &image_description_len); - printk(KERN_DEBUG "FIT: %16s sub-image 0x%08x..0x%08x \"%s\" %s%s%s\n", - image_type, image_pos, image_pos + image_len - 1, image_name, + printk(KERN_DEBUG "FIT: %16s sub-image 0x%08x - 0x%08x \"%s\" %s%s%s\n", + image_type, image_pos, image_pos + image_len, image_name, image_description?"(":"", image_description?:"", image_description?") ":""); if (strcmp(image_type, FIT_FILESYSTEM_PROP)) diff --git a/lede/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds b/lede/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds index 52d7618052..aaaeba2bfe 100644 --- a/lede/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds +++ b/lede/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds @@ -9,7 +9,8 @@ case $board in abt,asr3000) ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth1" ;; -bananapi,bpi-r4) +bananapi,bpi-r4|\ +bananapi,bpi-r4-poe) ucidef_set_led_netdev "wan" "wan" "mt7530-0:00:green:lan" "wan" "link tx rx" ucidef_set_led_netdev "lan1" "lan1" "mt7530-0:01:green:lan" "lan1" "link tx rx" ucidef_set_led_netdev "lan2" "lan2" "mt7530-0:02:green:lan" "lan2" "link tx rx" diff --git a/lede/target/linux/mediatek/filogic/base-files/etc/board.d/02_network b/lede/target/linux/mediatek/filogic/base-files/etc/board.d/02_network index 5586a6a8b3..8082fa3620 100644 --- a/lede/target/linux/mediatek/filogic/base-files/etc/board.d/02_network +++ b/lede/target/linux/mediatek/filogic/base-files/etc/board.d/02_network @@ -24,7 +24,8 @@ mediatek_setup_interfaces() bananapi,bpi-r3) ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4 sfp2" "eth1 wan" ;; - bananapi,bpi-r4) + bananapi,bpi-r4|\ + bananapi,bpi-r4-poe) ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 eth1" "wan eth2" ;; cetron,ct3003*|\ @@ -82,7 +83,6 @@ mediatek_setup_macs() lan_mac="${addr}" ;; bananapi,bpi-r3|\ - bananapi,bpi-r3-mini|\ bananapi,bpi-r4) wan_mac=$(macaddr_add $(cat /sys/class/net/eth0/address) 1) ;; diff --git a/lede/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac b/lede/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac index a1e86697fd..b143d4ded5 100644 --- a/lede/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac +++ b/lede/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac @@ -29,7 +29,8 @@ case "$board" in [ "$PHYNBR" = "0" ] && macaddr_add $addr 2 > /sys${DEVPATH}/macaddress [ "$PHYNBR" = "1" ] && macaddr_add $addr 3 > /sys${DEVPATH}/macaddress ;; - bananapi,bpi-r4) + bananapi,bpi-r4|\ + bananapi,bpi-r4-poe) addr=$(cat /sys/class/net/eth0/address) [ "$PHYNBR" = "0" ] && macaddr_add $addr 2 > /sys${DEVPATH}/macaddress [ "$PHYNBR" = "1" ] && macaddr_add $addr 3 > /sys${DEVPATH}/macaddress diff --git a/lede/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh b/lede/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh index 218d16406b..52adac9c33 100755 --- a/lede/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh +++ b/lede/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh @@ -1,5 +1,4 @@ REQUIRE_IMAGE_METADATA=1 -RAMFS_COPY_BIN='fitblk' asus_initial_setup() { @@ -12,21 +11,6 @@ asus_initial_setup() ubimkvol /dev/ubi0 -N jffs2 -s 0x3e000 } -platform_get_bootdev() { - local rootdisk="$(cat /sys/firmware/devicetree/base/chosen/rootdisk)" - local handle bootdev - for handle in /sys/class/block/*/of_node/phandle /sys/class/block/*/device/of_node/phandle; do - [ ! -e "$handle" ] && continue - if [ "$rootdisk" = "$(cat $handle)" ]; then - bootdev="${handle%/of_node/phandle}" - bootdev="${bootdev%/device}" - bootdev="${bootdev#/sys/class/block/}" - echo "$bootdev" - break - fi - done -} - platform_do_upgrade() { local board=$(board_name) @@ -36,7 +20,9 @@ platform_do_upgrade() { CI_KERNPART="linux" nand_do_upgrade "$1" ;; - bananapi,bpi-r3) + bananapi,bpi-r3|\ + bananapi,bpi-r4|\ + bananapi,bpi-r4-poe) local rootdev="$(cmdline_get_var root)" rootdev="${rootdev##*/}" rootdev="${rootdev%p[0-9]*}" @@ -56,21 +42,6 @@ platform_do_upgrade() { ;; esac ;; - bananapi,bpi-r4) - [ -e /dev/fit0 ] && fitblk /dev/fit0 - [ -e /dev/fitrw ] && fitblk /dev/fitrw - bootdev="$(platform_get_bootdev)" - case "$bootdev" in - mmcblk*) - EMMC_KERN_DEV="/dev/$bootdev" - emmc_do_upgrade "$1" - ;; - ubiblock*) - CI_KERNPART="fit" - nand_do_upgrade "$1" - ;; - esac - ;; cmcc,rax3000m-emmc|\ glinet,gl-mt2500|\ glinet,gl-mt6000|\ @@ -95,7 +66,8 @@ platform_check_image() { case "$board" in bananapi,bpi-r3|\ - bananapi,bpi-r4) + bananapi,bpi-r4|\ + bananapi,bpi-r4-poe) [ "$magic" != "d00dfeed" ] && { echo "Invalid image type." return 1 @@ -113,20 +85,15 @@ platform_check_image() { platform_copy_config() { case "$(board_name)" in - bananapi,bpi-r3) + bananapi,bpi-r3|\ + bananapi,bpi-r4|\ + bananapi,bpi-r4-poe) case "$(cmdline_get_var root)" in /dev/mmc*) emmc_copy_config ;; esac ;; - bananapi,bpi-r4) - case "$(platform_get_bootdev)" in - mmcblk*) - emmc_copy_config - ;; - esac - ;; cmcc,rax3000m-emmc|\ glinet,gl-mt2500|\ glinet,gl-mt6000|\ @@ -134,8 +101,8 @@ platform_copy_config() { emmc_copy_config ;; esac - } - +} + platform_pre_upgrade() { local board=$(board_name) diff --git a/lede/target/linux/mediatek/filogic/config-6.1 b/lede/target/linux/mediatek/filogic/config-6.1 index 36cb9c1e4e..c66bba9c9d 100644 --- a/lede/target/linux/mediatek/filogic/config-6.1 +++ b/lede/target/linux/mediatek/filogic/config-6.1 @@ -1,6 +1,6 @@ CONFIG_64BIT=y # CONFIG_AHCI_MTK is not set -CONFIG_AQUANTIA_PHY=y +CONFIG_AIROHA_EN8801SC_PHY=y CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y CONFIG_ARCH_DMA_ADDR_T_64BIT=y @@ -44,6 +44,7 @@ CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_NVMEM=y CONFIG_BLK_PM=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y @@ -95,6 +96,7 @@ CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_CPU_RMAP=y CONFIG_CPU_THERMAL=y CONFIG_CRC16=y +CONFIG_CRC_CCITT=y CONFIG_CRYPTO_AES_ARM64=y CONFIG_CRYPTO_AES_ARM64_CE=y CONFIG_CRYPTO_AES_ARM64_CE_BLK=y @@ -250,6 +252,7 @@ CONFIG_MTD_UBI=y CONFIG_MTD_UBI_BEB_LIMIT=20 CONFIG_MTD_UBI_BLOCK=y CONFIG_MTD_UBI_FASTMAP=y +CONFIG_MTD_UBI_NVMEM=y CONFIG_MTD_UBI_WL_THRESHOLD=4096 # CONFIG_MTK_CMDQ is not set # CONFIG_MTK_CQDMA is not set @@ -283,6 +286,7 @@ CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y CONFIG_NR_CPUS=4 CONFIG_NVMEM=y +CONFIG_NVMEM_LAYOUTS=y CONFIG_NVMEM_MTK_EFUSE=y CONFIG_NVMEM_SYSFS=y CONFIG_OF=y @@ -453,6 +457,7 @@ CONFIG_TREE_RCU=y CONFIG_TREE_SRCU=y CONFIG_UBIFS_FS=y # CONFIG_UCLAMP_TASK is not set +CONFIG_UIMAGE_FIT_BLK=y # CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_USB_SUPPORT=y CONFIG_VMAP_STACK=y diff --git a/lede/target/linux/mediatek/filogic/config-6.6 b/lede/target/linux/mediatek/filogic/config-6.6 index f6c8ec6d9a..6d9d42853b 100644 --- a/lede/target/linux/mediatek/filogic/config-6.6 +++ b/lede/target/linux/mediatek/filogic/config-6.6 @@ -48,7 +48,6 @@ CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_MQ_PCI=y -CONFIG_BLK_NVMEM=y CONFIG_BLK_PM=y CONFIG_BLOCK_NOTIFIERS=y CONFIG_BSD_PROCESS_ACCT=y diff --git a/lede/target/linux/mediatek/filogic/target.mk b/lede/target/linux/mediatek/filogic/target.mk index 1c4843a98c..4e5cde3d6b 100644 --- a/lede/target/linux/mediatek/filogic/target.mk +++ b/lede/target/linux/mediatek/filogic/target.mk @@ -2,7 +2,7 @@ ARCH:=aarch64 SUBTARGET:=filogic BOARDNAME:=Filogic 8x0 (MT798x) CPU_TYPE:=cortex-a53 -DEFAULT_PACKAGES += fitblk kmod-crypto-hw-safexcel kmod-mt7915e wpad-openssl uboot-envtools +DEFAULT_PACKAGES += kmod-crypto-hw-safexcel kmod-mt7915e wpad-openssl uboot-envtools KERNELNAME:=Image dtbs define Target/Description diff --git a/lede/target/linux/mediatek/image/filogic.mk b/lede/target/linux/mediatek/image/filogic.mk index d5eb8b8114..15dc26c4fa 100644 --- a/lede/target/linux/mediatek/image/filogic.mk +++ b/lede/target/linux/mediatek/image/filogic.mk @@ -196,6 +196,15 @@ define Device/bananapi_bpi-r4 endef TARGET_DEVICES += bananapi_bpi-r4 +define Device/bananapi_bpi-r4-poe + DEVICE_MODEL := BPi-R4 2.5GE + DEVICE_DTS := mt7988a-bananapi-bpi-r4-poe + DEVICE_DTS_CONFIG := config-mt7988a-bananapi-bpi-r4-poe + $(call Device/bananapi_bpi-r4-common) + DEVICE_PACKAGES += mt7988-2p5g-phy-firmware +endef +TARGET_DEVICES += bananapi_bpi-r4-poe + define Device/cetron_ct3003 DEVICE_VENDOR := Cetron DEVICE_MODEL := CT3003 diff --git a/lede/target/linux/mediatek/mt7629/config-5.15 b/lede/target/linux/mediatek/mt7629/config-5.15 index fcf7ae32f6..81dd1070ca 100644 --- a/lede/target/linux/mediatek/mt7629/config-5.15 +++ b/lede/target/linux/mediatek/mt7629/config-5.15 @@ -98,6 +98,7 @@ CONFIG_DTC=y CONFIG_EDAC_ATOMIC_SCRUB=y CONFIG_EDAC_SUPPORT=y CONFIG_EINT_MTK=y +# CONFIG_FIT_PARTITION is not set CONFIG_FIXED_PHY=y CONFIG_FIX_EARLYCON_MEM=y CONFIG_FWNODE_MDIO=y diff --git a/lede/target/linux/mediatek/mt7629/config-6.1 b/lede/target/linux/mediatek/mt7629/config-6.1 index c0c501e59e..16edd787a8 100644 --- a/lede/target/linux/mediatek/mt7629/config-6.1 +++ b/lede/target/linux/mediatek/mt7629/config-6.1 @@ -107,6 +107,7 @@ CONFIG_EDAC_ATOMIC_SCRUB=y CONFIG_EDAC_SUPPORT=y CONFIG_EINT_MTK=y CONFIG_EXCLUSIVE_SYSTEM_RAM=y +# CONFIG_FIT_PARTITION is not set CONFIG_FIXED_PHY=y CONFIG_FIX_EARLYCON_MEM=y CONFIG_FRAME_WARN=1024 diff --git a/lede/target/linux/generic/hack-5.15/410-block-fit-partition-parser.patch b/lede/target/linux/mediatek/patches-5.15/041-block-fit-partition-parser.patch similarity index 100% rename from lede/target/linux/generic/hack-5.15/410-block-fit-partition-parser.patch rename to lede/target/linux/mediatek/patches-5.15/041-block-fit-partition-parser.patch diff --git a/lede/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch b/lede/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch similarity index 100% rename from lede/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch rename to lede/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch diff --git a/mieru/pkg/congestion/bbr_sender.go b/mieru/pkg/congestion/bbr_sender.go new file mode 100644 index 0000000000..cfc7638771 --- /dev/null +++ b/mieru/pkg/congestion/bbr_sender.go @@ -0,0 +1,210 @@ +// Copyright (C) 2024 mieru authors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package congestion + +import "time" + +type bbrMode int + +const ( + // Startup phase of the connection. + modeStartUp bbrMode = iota + + // After achieving the highest possible bandwidth during the startup, lower + // the pacing rate in order to drain the queue. + modeDrain + + // Cruising mode. + modeProbeBW + + // Temporarily slow down sending in order to empty the buffer and measure + // the real minimum RTT. + modeProbeRTT +) + +// Indicates how the congestion control limits the amount of bytes in flight. +type bbrRecoveryState int + +const ( + // Do not limit. + stateNotInRecovery bbrRecoveryState = iota + + // Allow 1 extra outstanding byte for each byte acknowledged. + stateConservation + + // Allow 1.5 extra outstanding bytes for each byte acknowledged. + stateMediumGrowth + + // Allow 2 extra outstanding bytes for each byte acknowledged (slow start). + stateGrowth +) + +type BBRSender struct { + rttStats *RTTStats + + // unackedPackets *QuicUnackedPacketMap + + // Current BBR running mode. + mode bbrMode + + // Bandwidth sampler provides BBR with the bandwidth measurements at + // individual points. + sampler BandwidthSamplerInterface + + // The number of the round trips that have occurred during the connection. + roundTripCount uint64 + + // The packet number of the most recently sent packet. + lastSentPacket int64 + + // Acknowledgement of any packet after currentRoundTripEnd will cause + // the round trip counter to advance. + currentRoundTripEnd int64 + + // Tracks the maximum bandwidth over the multiple recent round-trips. + maxBandwidth WindowedFilter[uint64] + + // Tracks the maximum number of bytes acked faster than the sending rate. + maxAckHeight WindowedFilter[uint64] + + // The time this aggregation started and the number of bytes acked during it. + aggregationEpochStartTime time.Time + aggregationEpochBytes int64 + + // The number of bytes acknowledged since the last time bytes in flight + // dropped below the target window. + bytesAckedSinceQueueDrained int64 + + // The muliplier for calculating the max amount of extra CWND to add to + // compensate for ack aggregation. + maxAggregationBytesMultiplier float64 + + // Minimum RTT estimate. Automatically expires within 10 seconds + // (and triggers PROBE_RTT mode) if no new value is sampled + // during that period. + minRTT time.Duration + + // The time at which the current value of minRTT was assigned. + minRTTTimestamp time.Time + + // The maximum allowed number of bytes in flight. + congestionWindow int64 + + // The initial value of the congestionWindow. + initialCongestionWindow int64 + + // The largest value the congestionWindow can achieve. + maxCongestionWindow int64 + + // The smallest value the congestionWindow can achieve. + minCongestionWindow int64 + + // The current pacing rate of the connection. + pacingRate int64 + + // The gain currently applied to the pacing rate. + pacingGain float64 + + // The gain currently applied to the congestion window. + congestionWindowGain float64 + + // The gain used for the congestion window during PROBE_BW. + congestionWindowGainConstant float64 + + // The coefficient by which mean RTT variance is added to the congestion window. + rttVarianceWeight float64 + + // The number of RTTs to stay in STARTUP mode. Defaults to 3. + numStartupRTTs uint64 + + // If true, exit startup if 1 RTT has passed with no bandwidth increase and + // the connection is in recovery. + exitStartupOnLoss bool + + // Number of round-trips in PROBE_BW mode, used for determining the current + // pacing gain cycle. + cycleCurrentOffset int + + // The time at which the last pacing gain cycle was started. + lastCycleStart time.Time + + // Indicates whether the connection has reached the full bandwidth mode. + isAtFullBandwidth bool + + // Number of rounds during which there was no significant bandwidth increase. + roundsWithoutBandwidthGain uint64 + + // The bandwidth compared to which the increase is measured. + bandwidthAtLastRound int64 + + // Set to true upon exiting quiescence. + exitingQuiescence bool + + // Time at which PROBE_RTT has to be exited. Setting it to zero indicates + // that the time is yet unknown as the number of packets in flight has not + // reached the required value. + exitProbeRTTAt time.Time + + // Indicates whether a round-trip has passed since PROBE_RTT became active. + probeRTTRoundPassed bool + + // Indicates whether the most recent bandwidth sample was marked as + // app-limited. + lastSampleIsAppLimited bool + + // Current state of recovery. + recoveryState bbrRecoveryState + + // Receiving acknowledgement of a packet after endRecoveryAt will cause + // BBR to exit the recovery mode. A value above zero indicates at least one + // loss has been detected, so it must not be set back to zero. + endRecoveryAt int64 + + // A window used to limit the number of bytes in flight during loss recovery. + recoveryWindow int64 + + // When true, recovery is rate based rather than congestion window based. + rateBasedRecovery bool + + // When true, pace at 1.5x and disable packet conservation in STARTUP. + slowerStartup bool + + // When true, disables packet conservation in STARTUP. + rateBasedStartup bool + + // Used as the initial packet conservation mode when first entering recovery. + initialConservationInStartup bbrRecoveryState + + // If true, will not exit low gain mode until bytesInFlight drops below BDP + // or it's time for high gain mode. + fullyDrainQueue bool + + // If true, use a CWND of 0.75*BDP during probe_rtt instead of 4 packets. + probeRTTBasedOnBDP bool + + // If true, skip PROBE_RTT and update the timestamp of the existing minRTT to + // now if minRTT over the last cycle is within 12.5% of the current minRTT. + // Even if the minRTT is 12.5% too low, the 25% gain cycling and 2x CWND gain + // should overcome an overly small minRTT. + probeRTTSkippedIfSimilarRTT bool + + // If true, disable PROBE_RTT entirely as long as the connection was recently + // app limited. + probeRTTDisabledIfAppLimited bool + + appLimitedSinceLastProbeRTT bool + minRTTSinceLastProbeRTT time.Duration +} diff --git a/openwrt-packages/luci-app-store/Makefile b/openwrt-packages/luci-app-store/Makefile index 90dad63202..1ea7580aea 100644 --- a/openwrt-packages/luci-app-store/Makefile +++ b/openwrt-packages/luci-app-store/Makefile @@ -11,7 +11,7 @@ LUCI_DEPENDS:=+curl +opkg +luci-base +tar +coreutils +coreutils-stat +libuci-lua LUCI_EXTRA_DEPENDS:=luci-lib-taskd (>=1.0.19) LUCI_PKGARCH:=all -PKG_VERSION:=0.1.20-0 +PKG_VERSION:=0.1.21-0 # PKG_RELEASE MUST be empty for luci.mk PKG_RELEASE:= diff --git a/openwrt-packages/luci-app-store/luasrc/controller/store.lua b/openwrt-packages/luci-app-store/luasrc/controller/store.lua index 6f65f438a5..ea6ac96ee5 100644 --- a/openwrt-packages/luci-app-store/luasrc/controller/store.lua +++ b/openwrt-packages/luci-app-store/luasrc/controller/store.lua @@ -77,6 +77,7 @@ local function user_config() local data = { hide_docker = uci:get("istore", "istore", "hide_docker") == "1", ignore_arch = uci:get("istore", "istore", "ignore_arch") == "1", + last_path = uci:get("istore", "istore", "last_path"), super_arch = uci:get("istore", "istore", "super_arch"), channel = uci:get("istore", "istore", "channel") } @@ -300,6 +301,9 @@ function store_action(param) local autoenable = luci.http.formvalue("enable") if autopath ~= nil then autoenv = autoenv .. " path=" .. luci.util.shellquote(autopath) + local uci = require "luci.model.uci".cursor() + uci:set("istore", "istore", "last_path", autopath) + uci:commit("istore") end autoenv = autoenv .. " enable=" .. autoenable code, out, err = _action(myopkg, luci.util.shellquote(autoenv), action, metapkg) diff --git a/openwrt-packages/luci-app-store/root/etc/config/istore b/openwrt-packages/luci-app-store/root/etc/config/istore index da48f7f5d6..deccf26489 100644 --- a/openwrt-packages/luci-app-store/root/etc/config/istore +++ b/openwrt-packages/luci-app-store/root/etc/config/istore @@ -1,6 +1,7 @@ config istore 'istore' # option hide_docker '0' # option ignore_arch '0' +# option last_path '/mnt/nvme' # option channel 'istore' # option super_arch 'x86_64' # option super_arch 'aarch64' diff --git a/small/hysteria/Makefile b/small/hysteria/Makefile index 8c8d304038..2b284c8b06 100644 --- a/small/hysteria/Makefile +++ b/small/hysteria/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=hysteria -PKG_VERSION:=2.4.5 +PKG_VERSION:=2.5.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/apernet/hysteria/tar.gz/app/v$(PKG_VERSION)? -PKG_HASH:=e0d5ffb3ddd5e98092f29e908edb64468b1d8b40af78281cc0054b26f542a48b +PKG_HASH:=78afca9c9c3f2c1a89c2356c66e70489bba74d3b4ede42f4194d179a09959d8c PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-app-v$(PKG_VERSION) PKG_LICENSE:=MIT diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index 474ef5282a..5b35ae1acb 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -30,13 +30,13 @@ define Download/geosite HASH:=2542bbc017ae060da37260da02f7567fb2b016f0e825aee5c23b1e8567c0649e endef -GEOSITE_IRAN_VER:=202406240029 +GEOSITE_IRAN_VER:=202407010032 GEOSITE_IRAN_FILE:=iran.dat.$(GEOSITE_IRAN_VER) define Download/geosite-ir URL:=https://github.com/bootmortis/iran-hosted-domains/releases/download/$(GEOSITE_IRAN_VER)/ URL_FILE:=iran.dat FILE:=$(GEOSITE_IRAN_FILE) - HASH:=86503687cbca94889b9c94504d4310983060cdb2d813929b6da6f077776d5096 + HASH:=1306992448a10f1e1c0c0a566c0bb6057e999a0029bb1004b17763299013b893 endef define Package/v2ray-geodata/template diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt index a5458edc5d..fd54c1adb3 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt @@ -387,9 +387,9 @@ object AngConfigManager { // } fun importBatchConfig(server: String?, subid: String, append: Boolean): Int { - var count = parseBatchConfig(server, subid, append) + var count = parseBatchConfig(Utils.decode(server), subid, append) if (count <= 0) { - count = parseBatchConfig(Utils.decode(server), subid, append) + count = parseBatchConfig(server, subid, append) } if (count <= 0) { count = parseCustomConfigServer(server, subid) @@ -577,9 +577,9 @@ object AngConfigManager { } private fun parseConfigViaSub(server: String?, subid: String, append: Boolean): Int { - var count = parseBatchConfig(server, subid, append) + var count = parseBatchConfig(Utils.decode(server), subid, append) if (count <= 0) { - count = parseBatchConfig(Utils.decode(server), subid, append) + count = parseBatchConfig(server, subid, append) } if (count <= 0) { count = parseCustomConfigServer(server, subid) diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt index 3e589f3e36..b2b0135c23 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt @@ -356,7 +356,7 @@ object Utils { } @Throws(IOException::class) - fun getUrlContentWithCustomUserAgent(urlStr: String?, httpPort: Int = 0): String { + fun getUrlContentWithCustomUserAgent(urlStr: String?, timeout: Int = 30000, httpPort: Int = 0): String { val url = URL(urlStr) val conn = if (httpPort == 0) { url.openConnection() @@ -368,6 +368,8 @@ object Utils { ) ) } + conn.connectTimeout = timeout + conn.readTimeout = timeout conn.setRequestProperty("Connection", "close") conn.setRequestProperty("User-agent", "v2rayNG/${BuildConfig.VERSION_NAME}") url.userInfo?.let { diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/WireguardFmt.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/WireguardFmt.kt index 27900f9786..9c0b2bbaa1 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/WireguardFmt.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/WireguardFmt.kt @@ -25,7 +25,7 @@ object WireguardFmt { ?: AppConfig.WIREGUARD_LOCAL_ADDRESS_V4).removeWhiteSpace() .split(",") wireguard.peers?.get(0)?.publicKey = queryParam["publickey"] ?: "" - wireguard.peers?.get(0)?.endpoint = "${uri.idnHost}:${uri.port}" + wireguard.peers?.get(0)?.endpoint = Utils.getIpv6Address(uri.idnHost) + ":${uri.port}" wireguard.mtu = Utils.parseInt(queryParam["mtu"] ?: AppConfig.WIREGUARD_LOCAL_MTU) wireguard.reserved = (queryParam["reserved"] ?: "0,0,0").removeWhiteSpace().split(",") diff --git a/v2rayu/Podfile b/v2rayu/Podfile index c5dec19cb7..e4ffe1ba23 100644 --- a/v2rayu/Podfile +++ b/v2rayu/Podfile @@ -1,7 +1,7 @@ # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' source 'https://github.com/CocoaPods/Specs.git' -platform :osx, '10.14' +platform :osx, '11.0' target 'V2rayU' do # Comment the next line if you're not using Swift and don't want to use dynamic frameworks @@ -14,7 +14,6 @@ target 'V2rayU' do pod 'SwiftyJSON' # master branch pod 'Preferences', :git => 'https://github.com/sindresorhus/Preferences.git' - pod 'Sparkle' ,'~> 2.0' pod 'QRCoder' pod 'MASShortcut' pod 'Swifter' diff --git a/v2rayu/V2rayU.xcodeproj/project.pbxproj b/v2rayu/V2rayU.xcodeproj/project.pbxproj index e8cbf8a33f..5dc3a9e413 100755 --- a/v2rayu/V2rayU.xcodeproj/project.pbxproj +++ b/v2rayu/V2rayU.xcodeproj/project.pbxproj @@ -18,9 +18,9 @@ 6618372E23E9BF74000F7410 /* ToastWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6618372C23E9BF73000F7410 /* ToastWindow.xib */; }; 66193A8623EE45B200289B6A /* PreferenceRouting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66193A8523EE45B200289B6A /* PreferenceRouting.swift */; }; 66193A8923EE46BC00289B6A /* PreferenceRouting.xib in Resources */ = {isa = PBXBuildFile; fileRef = 66193A8723EE46BC00289B6A /* PreferenceRouting.xib */; }; - 6633A43F2C0A120000C54CA5 /* Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6633A43E2C0A120000C54CA5 /* Sparkle.swift */; }; 663F040625ED4B2C00687600 /* V2rayLaunch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663F040525ED4B2C00687600 /* V2rayLaunch.swift */; }; 664BAC472C2DB0E100654FB7 /* V2rayRouting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664BAC462C2DB0E100654FB7 /* V2rayRouting.swift */; }; + 664BAC492C314CD600654FB7 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664BAC482C314CD600654FB7 /* AppVersion.swift */; }; 664EB375216C9A5E00B6AE0D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664EB374216C9A5E00B6AE0D /* AppDelegate.swift */; }; 664EB377216C9A5F00B6AE0D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 664EB376216C9A5F00B6AE0D /* Assets.xcassets */; }; 664EB392216CA9E800B6AE0D /* ConfigWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664EB390216CA9E800B6AE0D /* ConfigWindow.swift */; }; @@ -121,11 +121,11 @@ 6625848D2AB745E700DFDC1E /* sign.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = sign.sh; sourceTree = ""; }; 6625848E2AB746D500DFDC1E /* appdmg.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = appdmg.sh; sourceTree = ""; }; 662F0ACE2AB720C700884C17 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = ../en.lproj/PreferenceGeneral.strings; sourceTree = ""; }; - 6633A43E2C0A120000C54CA5 /* Sparkle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sparkle.swift; sourceTree = ""; }; 663F040525ED4B2C00687600 /* V2rayLaunch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = V2rayLaunch.swift; sourceTree = ""; }; 664666A021CBD6C60094F0B7 /* libPods-V2rayUTool.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libPods-V2rayUTool.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 664B95DD217062A500DBC941 /* Alamofire */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Alamofire; path = Pods/Alamofire; sourceTree = ""; }; 664BAC462C2DB0E100654FB7 /* V2rayRouting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = V2rayRouting.swift; sourceTree = ""; }; + 664BAC482C314CD600654FB7 /* AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = ""; }; 664EB371216C9A5E00B6AE0D /* V2rayU.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = V2rayU.app; sourceTree = BUILT_PRODUCTS_DIR; }; 664EB374216C9A5E00B6AE0D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 664EB376216C9A5F00B6AE0D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -267,6 +267,7 @@ 6608D9B82182BBAC00A0E0DD /* v2ray */, 664EB376216C9A5F00B6AE0D /* Assets.xcassets */, 664EB374216C9A5E00B6AE0D /* AppDelegate.swift */, + 664BAC482C314CD600654FB7 /* AppVersion.swift */, 66ACB19F21757D5B005B5881 /* MainMenu.swift */, 664EB378216C9A5F00B6AE0D /* MainMenu.xib */, 664EB390216CA9E800B6AE0D /* ConfigWindow.swift */, @@ -287,7 +288,6 @@ 6D6DF7F662C35646734A352E /* install.sh */, 6D6DF11F0983AFCBEF1E347B /* Uri.swift */, 6D6DF79424C83391C205CB9C /* Share.swift */, - 6633A43E2C0A120000C54CA5 /* Sparkle.swift */, ); path = V2rayU; sourceTree = ""; @@ -556,6 +556,7 @@ 6608D9DA2182C69D00A0E0DD /* v2rayStruct.swift in Sources */, 66F07CF9236D79540088A4AE /* Ping.swift in Sources */, 664EB392216CA9E800B6AE0D /* ConfigWindow.swift in Sources */, + 664BAC492C314CD600654FB7 /* AppVersion.swift in Sources */, 66193A8623EE45B200289B6A /* PreferenceRouting.swift in Sources */, 6D6DF8BFC33F97E9AFCA5A4B /* V2rayConfig.swift in Sources */, 6D6DF6F065067CD879201FF9 /* Import.swift in Sources */, @@ -568,7 +569,6 @@ 6D6DF807BE591BE396221EF3 /* PreferenceAdvance.swift in Sources */, 6D6DFC1D9432F2A60D2156E2 /* PreferenceDns.swift in Sources */, 6D6DF670FFB063EE2360776C /* Uri.swift in Sources */, - 6633A43F2C0A120000C54CA5 /* Sparkle.swift in Sources */, 6D6DF41FA8F7C7B020AC4115 /* Share.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -768,7 +768,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -827,7 +827,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; @@ -849,7 +849,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 4.2.0; + CURRENT_PROJECT_VERSION = 4.0.0; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; ENABLE_ONLY_ACTIVE_RESOURCES = YES; @@ -859,8 +859,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 4.2.0; + MACOSX_DEPLOYMENT_TARGET = 11.0; + MARKETING_VERSION = 4.0.0; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = net.yanue.V2rayU; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -883,7 +883,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 4.2.0; + CURRENT_PROJECT_VERSION = 4.0.0; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; ENABLE_ONLY_ACTIVE_RESOURCES = YES; @@ -893,8 +893,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 4.2.0; + MACOSX_DEPLOYMENT_TARGET = 11.0; + MARKETING_VERSION = 4.0.0; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = net.yanue.V2rayU; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -915,7 +915,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; }; @@ -930,7 +930,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; }; diff --git a/v2rayu/V2rayU/AppDelegate.swift b/v2rayu/V2rayU/AppDelegate.swift index 48a0c377e6..8b34a33770 100644 --- a/v2rayu/V2rayU/AppDelegate.swift +++ b/v2rayu/V2rayU/AppDelegate.swift @@ -10,12 +10,10 @@ import Cocoa import ServiceManagement import MASShortcut import Preferences -import Sparkle import FirebaseCore let launcherAppIdentifier = "net.yanue.V2rayU.Launcher" let appVersion = getAppVersion() -let V2rayUpdater = V2rayUpdaterController() let NOTIFY_TOGGLE_RUNNING_SHORTCUT = Notification.Name(rawValue: "NOTIFY_TOGGLE_RUNNING_SHORTCUT") let NOTIFY_SWITCH_PROXY_MODE_SHORTCUT = Notification.Name(rawValue: "NOTIFY_SWITCH_PROXY_MODE_SHORTCUT") @@ -42,6 +40,9 @@ let preferencesWindowController = PreferencesWindowController( ] ) +let langStr = Locale.current.languageCode +let isMainland = langStr == "zh-CN" || langStr == "zh" || langStr == "zh-Hans" || langStr == "zh-Hant" + @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { // bar menu diff --git a/v2rayu/V2rayU/AppVersion.swift b/v2rayu/V2rayU/AppVersion.swift new file mode 100644 index 0000000000..ea0b929490 --- /dev/null +++ b/v2rayu/V2rayU/AppVersion.swift @@ -0,0 +1,614 @@ +// +// AppVersion.swift +// V2rayU +// +// Created by yanue on 2024/6/30. +// Copyright © 2024 yanue. All rights reserved. +// +import SwiftUI +import ServiceManagement + +// 手动实现检查版本下载更新 UI. +// 基于 SwiftUI + NSWindowController 实现 +// 参考 UI: Sparkle(https://github.com/sparkle-project/Sparkle) +// 基于 https://github.com/yanue/V2rayU/releases 进行版本检查 + +struct GithubRelease: Codable { + let id: Int + let tagName: String + let name: String + let draft: Bool + let prerelease: Bool + let publishedAt: Date // 2024-06-30T09:00:00Z, 用于排序 + let assets: [GithubAsset] + let body: String + + enum CodingKeys: String, CodingKey { + case id + case tagName = "tag_name" + case name + case draft + case prerelease + case publishedAt = "published_at" + case assets + case body + } +} + +struct GithubAsset: Codable { + let name: String + let browserDownloadUrl: String + + enum CodingKeys: String, CodingKey { + case name + case browserDownloadUrl = "browser_download_url" + } +} + +let V2rayUpdater = AppCheckController() + +// AppCheckController - 检查新版本页面 + +class AppCheckController: NSWindowController { + // Declare the contentView as a property to avoid using self before super.init + private var contentView: NSHostingView! + var bindData = BindData() + + // Initialize the view and window + init() { + // Initialize the content view with a placeholder closure + let contentView = NSHostingView(rootView: ContentView( + bindData: bindData, + closeWindow: {} + )) + + // Create the window with specified dimensions and styles + let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 400, height: 300), + styleMask: [.titled, .closable, .resizable], + backing: .buffered, defer: false) + window.title = "Check V2rayU" + window.contentView = contentView + + // Call the super init with the created window + super.init(window: window) + + // Update the contentView with the actual closure after super.init + contentView.rootView = ContentView( + bindData: bindData, + closeWindow: closeWindow + ) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func windowDidLoad() { + super.windowDidLoad() + } + + func checkForUpdates(showWindow: Bool = false) { + if showWindow { + DispatchQueue.main.async { + self.window?.orderFrontRegardless() + self.window?.center() + self.window?.makeKeyAndOrderFront(nil) + NSApp.activate(ignoringOtherApps: true) + } + } else { + // close window + DispatchQueue.main.async { + self.window?.close() + } + } + guard let url = URL(string: "https://api.github.com/repos/yanue/V2rayU/releases") else { + return + } + print("checkForUpdates: \(url)") + let checkTask = URLSession.shared.dataTask(with: url) { data, response, error in + if let error = error { + print("Error fetching release: \(error)") + return + } + + guard let data = data else { + print("No data returned") + return + } + + print("checkForUpdates: \n \(data)") + + do { + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .iso8601 // 解析日期 + + // try decode data + let data: [GithubRelease] = try decoder.decode([GithubRelease].self, from: data) + + // 按日期倒序排序 + let sortedData = data.sorted { $0.publishedAt > $1.publishedAt } + + // 取第一个 + if let release = sortedData.first { + print("release: \(release.tagName)") + DispatchQueue.main.async { + let releaseVersion = release.tagName.replacingOccurrences(of: "v", with: "").replacingOccurrences(of: "V", with: "").trimmingCharacters(in: .whitespaces) // v4.1.0 => 4.1.0 + // get old version + let appVer = appVersion.versionToInt() + let releaseVer = releaseVersion.versionToInt() + + // new version is bigger than old version + if appVer.lexicographicallyPrecedes(releaseVer) { + // 点击菜单栏检查新版本,不过滤 + if !showWindow { + // 如果用户选择跳过版本更新, 则不显示新版本详情页面 + if let skipVersion = UserDefaults.standard.string(forKey: "skipAppVersion") { + if skipVersion == release.tagName { + print("Skip version: \(skipVersion)") + return + } + } + } + // 显示新版本详情页面 + let versionController = AppVersionController() + versionController.show(release: release) + // close window + self.closeWindow() + } else { + var title = "You are up to date!" + var toast = "V2rayU \(appVersion) is currently the newest version available." + if isMainland { + title = "当前已经是最新版了" + toast = "V2rayU \(appVersion) 已经是当前最新版了."; + } + // open dialog + alertDialog(title: title, message: toast) + // close window + self.closeWindow() + } + } + } + } catch { + print("Error decoding JSON: \(error)") + DispatchQueue.main.async { + // update progress text + self.bindData.progressText = "Check failed: \(error)" + var title = "Check failed!" + var toast = "\(error)" + if isMainland { + title = "检查失败" + toast = "\(error)"; + } + // open dialog + alertDialog(title: title, message: toast) + // sleep 2s + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + // close window + self.closeWindow() + } + } + } + } + checkTask.resume() + } + + func closeWindow() { + DispatchQueue.main.async { + self.window?.close() + } + } + + + class BindData: ObservableObject { + @Published var progressText = "check for updates..." + } + + struct ContentView: View { + @ObservedObject var bindData: BindData + + var closeWindow: () -> Void + + var body: some View { + VStack(spacing: 20) { + HStack { + Image("V2rayU") + .resizable() + .frame(width: 64, height: 64) + .cornerRadius(8) + + Spacer() + + VStack { + HStack { + ProgressView(bindData.progressText) .progressViewStyle(LinearProgressViewStyle()).padding(.horizontal) + } + + HStack { + Spacer() + Button(action: { + closeWindow() + }) { + Text("Cancel").font(.body) + } + .padding(.trailing, 20) + } + } + } + .padding() + } + } + + } +} + + +// AppVersionController - 新版本详情页面 + +class AppVersionController: NSWindowController { + var bindData = BindData() + private var contentView: NSHostingView! + private var release: GithubRelease! + + init() { + let contentView = NSHostingView(rootView: ContentView( + bindData: bindData, + skipAction: { print("Skip action") }, + installAction: { print("Install action") } + )) + let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 500, height: 300), + styleMask: [.titled, .closable, .resizable], + backing: .buffered, defer: false) + window.title = "Software Update" + window.contentView = contentView + + super.init(window: window) + + // Update the contentView with the actual closure after super.init + contentView.rootView = ContentView( + bindData: bindData, + skipAction: self.skipAction, + installAction: self.installAction + ) + } + + func show(release: GithubRelease) { + bindData.title = "A new version of V2rayU is available!" + bindData.description = "V2rayU \(appVersion) is now available—you have \(release.tagName). Would you like to download it now?" + bindData.releaseNotes = release.name + "\n" + release.body + self.release = release + print("bindData.releaseNotes", bindData.releaseNotes) + // bring window to front + window?.orderFrontRegardless() + // center position + window?.center() + // make window key + window?.makeKeyAndOrderFront(nil) + // activate app + NSApp.activate(ignoringOtherApps: true) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func windowDidLoad() { + super.windowDidLoad() + } + + // 安装新版本 + func installAction() { + DispatchQueue.main.async { + // 显示下载页面 + let downloadController = AppDownloadController() + downloadController.show(release: self.release) + // 关闭窗口 + self.window?.close() + } + } + + + func skipAction() { + print("Skip action") + // UserDefaults 记录是否跳过版本更新 + UserDefaults.standard.set(release.tagName, forKey: "skipAppVersion") + // 关闭窗口 + DispatchQueue.main.async { + self.window?.close() + } + } + + class BindData: ObservableObject { + @Published var title = "A new version of V2rayU App is available!" + @Published var description = "" + @Published var releaseNotes = """ + """ + } + + struct ContentView: View { + @ObservedObject var bindData: BindData + var skipAction: () -> Void + var installAction: () -> Void + + var body: some View { + VStack(alignment: .leading, spacing: 10) { + HStack(alignment: .top, spacing: 10) { + // use AppIcon.appiconset to Image + Image("V2rayU") + .resizable() + .frame(width: 64, height: 64) + .padding(.top, 20) + .padding(.leading, 20) + + VStack(alignment: .leading, spacing: 5) { + Text(bindData.title) + .font(.headline) + .padding(.top, 20) + + Text(bindData.description) + .padding(.trailing, 20) + + Text("Release Notes:") + .font(.headline) + .bold() + .padding(.top, 20) + + HStack { + + // 文字可选中 + TextEditor(text: $bindData.releaseNotes) + .lineSpacing(6) // 行间距 + .frame(height: 120) + .border(Color.gray, width: 1) // 黑色边框,宽度为 2 + .fixedSize(horizontal: false, vertical: true) + + + Spacer(minLength: 20) // 右边 margin 40 + } + } + } + + HStack { + Button("Skip This Version") { + skipAction() + } + + Spacer() + + Button("Install Update") { + installAction() + } + .keyboardShortcut(.defaultAction) + } + .padding(20) + } + .frame(width: 500, height: 300) + } + } +} + +// AppDownloadController - 下载安装页面 + +class AppDownloadController: NSWindowController, URLSessionDownloadDelegate { + private var contentView: NSHostingView! + var bindData = BindData() + private var downloadTask: URLSessionDownloadTask? + private var destinationURL: URL? + + init() { + let contentView = NSHostingView(rootView: ContentView( + bindData: bindData, + cancelDownload: {}, + doInstall: {} + )) + let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 400, height: 300), + styleMask: [.titled, .closable, .resizable], + backing: .buffered, defer: false) + window.title = "Download V2rayU" + window.contentView = contentView + super.init(window: window) + + // Update the contentView with the actual closure after super.init + contentView.rootView = ContentView( + bindData: bindData, + cancelDownload: cancelDownload, + doInstall: doInstall + ) + self.contentView = contentView + } + + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func windowDidLoad() { + super.windowDidLoad() + } + + func show(release: GithubRelease) { + DispatchQueue.main.async { + self.window?.orderFrontRegardless() + self.window?.center() + self.window?.makeKeyAndOrderFront(nil) + NSApp.activate(ignoringOtherApps: true) + } + download(release: release) + } + + func download(release: GithubRelease) { + DispatchQueue.main.async { + if let asset = release.assets.first { + self.bindData.dmgUrl = asset.browserDownloadUrl + print("download: \(self.bindData.dmgUrl)") + self.startDownload() + } else { + self.bindData.progressText = "No dmg asset found" + return + } + } + } + + private func startDownload() { + guard let url = URL(string: bindData.dmgUrl) else { + DispatchQueue.main.async { + self.bindData.isDownloading = true + self.bindData.progressText = "Invalid dmg url" + } + return + } + DispatchQueue.main.async { + self.bindData.isDownloading = true + self.bindData.progress = 0.0 + self.bindData.progressText = "Downloading..." + } + let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue()) + downloadTask = urlSession.downloadTask(with: url) + downloadTask?.resume() + + } + + private func cancelDownload() { + DispatchQueue.main.async { + self.bindData.isDownloading = false + self.bindData.progress = 0.0 + self.bindData.progressText = "Download canceled" + self.downloadTask?.cancel() + print("Download canceled") + } + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.window?.close() + } + } + + func doInstall() { + DispatchQueue.main.async { + if let destinationURL = self.destinationURL { + // open downloaded dmg + NSWorkspace.shared.open(destinationURL) + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + // close window + self.window?.close() + NSApplication.shared.terminate(self) + } + } + } + + print("Installing V2rayU") + } + + // ---------------------- ui 相关 -------------------------------- + // MARK: - 下载进度数据 + class BindData: ObservableObject { + @Published var progressText = "Downloading..." + @Published var dmgUrl: String = "" + @Published var progress: Float = 0.0 + @Published var isDownloading: Bool = false + } + + // MARK: - 下载进度视图 + + struct ContentView: View { + @ObservedObject var bindData: BindData + var cancelDownload: () -> Void + var doInstall: () -> Void + + var body: some View { + VStack(spacing: 20) { + VStack(spacing: 20) { + HStack { + Image("V2rayU") + .resizable() + .frame(width: 64, height: 64) + .cornerRadius(8) + + Spacer() + + VStack { + HStack { + ProgressView(value: bindData.progress, total: 100) { + Text(bindData.progressText) + } + } + + HStack { + Spacer() + if bindData.isDownloading { + Button(action: { + cancelDownload() + }) { + Text("Cancel").font(.body) + } + } else { + Button(action: { + doInstall() + }) { + Text("Install V2rayU").font(.body) + } + } + } + } + } + .padding() + } + } + .padding() + } + } + + // ---------------------- 下载相关 -------------------------------- + + // MARK: - URLSessionDownloadDelegate + func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { + let fileManager = FileManager.default + let downloadsDirectory = fileManager.urls(for: .downloadsDirectory, in: .userDomainMask).first! + destinationURL = downloadsDirectory.appendingPathComponent(downloadTask.response?.suggestedFilename ?? "V2rayU-macOS.dmg") + + do { + try fileManager.moveItem(at: location, to: destinationURL!) + DispatchQueue.main.async { + self.bindData.isDownloading = false + self.bindData.progress = 100.0 + self.bindData.progressText = "Download Completed" + } + print("Download finished: \(destinationURL!)") + } catch { + DispatchQueue.main.async { + self.bindData.isDownloading = false + self.bindData.progressText = "File move error: \(error.localizedDescription)" + var title = "Download failed!" + var toast = "\(error)" + if isMainland { + title = "移动文件失败" + toast = "\(error)"; + } + // open dialog + alertDialog(title: title, message: toast) + } + print("File move error: \(error.localizedDescription)") + } + } + + func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { + DispatchQueue.main.async { + self.bindData.progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite) * 100 + } + } + + func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + if let error = error { + DispatchQueue.main.async { + self.bindData.isDownloading = false + self.bindData.progressText = "Download Failed: \(error.localizedDescription)" + } + var title = "Download failed!" + var toast = "\(error)" + if isMainland { + title = "下载文件失败" + toast = "\(error)"; + } + // open dialog + alertDialog(title: title, message: toast) + print("Download error: \(error.localizedDescription)") + } + } +} diff --git a/v2rayu/V2rayU/Assets.xcassets/Contents.json b/v2rayu/V2rayU/Assets.xcassets/Contents.json index da4a164c91..73c00596a7 100644 --- a/v2rayu/V2rayU/Assets.xcassets/Contents.json +++ b/v2rayu/V2rayU/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/v2rayu/V2rayU/Assets.xcassets/IconOn.imageset/Contents.json b/v2rayu/V2rayU/Assets.xcassets/IconOn.imageset/Contents.json index 55bdf0abe7..b816fd1c78 100644 --- a/v2rayu/V2rayU/Assets.xcassets/IconOn.imageset/Contents.json +++ b/v2rayu/V2rayU/Assets.xcassets/IconOn.imageset/Contents.json @@ -1,26 +1,26 @@ { "images" : [ { - "idiom" : "universal", "filename" : "icon.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "icon@2x.png", + "idiom" : "universal", "scale" : "2x" }, { + "filename" : "icon@3x 1.png", "idiom" : "universal", - "filename" : "icon@3x.png", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 }, "properties" : { "template-rendering-intent" : "template" } -} \ No newline at end of file +} diff --git a/v2rayu/V2rayU/Assets.xcassets/IconOn.imageset/icon@3x 1.png b/v2rayu/V2rayU/Assets.xcassets/IconOn.imageset/icon@3x 1.png new file mode 100644 index 0000000000000000000000000000000000000000..1834aa6826f8c489a936ae5e8b429f8bfc8993e5 GIT binary patch literal 750 zcmVPx%s7XXYR9Fekn7vO_K@`P76NwEJlqNJ7NK7=_kXTuQ30e}caC=)@OaBHdyItcS zU_>fv8VSaaMjJv1jRm1VjmD4jdzsnH8)k<4)_r78a(3R_IrrR~-7qt}$%)}GqqGIb zn;N^$rl;|P_}THq#akJsHIulk=%yGp@hh5#Yr{Urp46oF8LTT37ui5TDq2!iw9o0I`lBWs-AK}AO9rHhS>DzActJ< zlN;$_0FM4WF((e=oYuDonfV7axsyHgg~?xuzm+jT4zPOVXEUMylotEXbhV3aXx zP|JihsoHD`Z)!BcSp6&QJ7;Gdo0ko~DK^5fc^%`MVr1iL{e@MNV<2pfvuVNcmd1x} gv9IyHIP@#Me=dVTBXbL{!TPx)b4f%&RA>d&nQus4br{Ewj#LO1ZK6zJ(rorlkcj@gnc2qNi<+as_F@LT31t5u zq8F=oy;*aa1hW_e-OFS#a?pa6gAA1=y)s4&14W$HVw5n<;6@axQs zTV7u7^@9U0IE!vo%J89ZU$7#^Mn|o{#>PfFZ+yPHdDE^_NK;c&z$eQIH#v%8ZDPG6 z1d=a5cwhxmjCY4y_wToB=2K`pcrd`>;Ux#T*3BLh6FajageEq^O#4|+kM;9@I%fU! z$&+?Hf|Fe2BzHl!Rnb?3*n~!yw>^5~hlRa8o z3<&*wZqB_mG7^}lfG_&{b8>p}q9N}h$`q7y=S`Bu`T0#0P3#k5~&#FDxwBx!>;HvwhQ9T3&YgE?+i7r)I|v+fUd*3z`BJR={iWdMDr+ zGci9uZ&xo~y5!uQowZ{+pZE7Wx5mcoTy=G|Q(799+PZ{w(1f-%=4YwYYPaB@=Od52 z_0P`DS<T)J0xnHf?7KyK_ioM*Ei=19V6WY*d%`fy_tvqE{ z|Ls8brf^Z<61T=CCOF=#TIKfb&X)rN&hb;HobQK+owqtVobmB-XL4%FxMbRznwmA^ z>;P_Zkjq~HE@(qzsO{419|D14crF{YSM7+`=Z*Gu`y>9OyE`n_t*EGQmlhVRAIA$X zN0t+Aj9mV8Ge#p?1IBs8IEA$@c_KJ@o)%_^DJdy&KkDpszq)qKZD?o+i_OdpT)mnp z;BQ?@D=RCF9~^MOX^dQEJ*-9R8hcWsX(7zn%y|ni!7r-A>C*Vbwzajj?xzhu?A)fX2*a-u#GP^)npEHi1|;(%K*dH_}Ecjyvg}1;i5zM_Ri<0aIzC zv#~F$?H9PcCpCPDA-2%`&NCu04-gPXA?z$9cWVdK8x^AB%{)H%##xfH5Sr1RIZFJj z)+C5(pT{|eaV$A5u&aI^=2*igmyydK?;oSta`hz$7?Mx3ki=@_^s&JA8_;Jii8afK zTzoET!^2;+{M3p`SaBlDol19Mzp)Y{jIdjXP! zhA%Nud~x$=+!d84&8J|JJrrq=5O=y|4Ig|>T)u7S?u##Dyfpen$d}aXe^>Eu3y%xN z=rhNf*Eioj+Sa_-(l}tezT*W`zT|%YAH~6QE1>UR&v%Tbz^g^gg&Kb@v0ur)#CLH5SOcXG@vDw5lHp9k`!y5+^NNzigW(SSA+uj!SbCi z_)k7l1nnW=j!>-KHoW8@S5d4=tnAEv!6aO-7EZXyQFPm_4BQbXg+dE}11>l>+_ov> zVWC&JEpYbFRS-V-5<@H;sV&VZGAbEQM|A?PDrxr$Edn+ud?T>i6WNyYP{H;OG1|D- TLPmzt00000NkvXXu0mjfzhlYd diff --git a/v2rayu/V2rayU/Assets.xcassets/V2rayU.imageset/1024.png b/v2rayu/V2rayU/Assets.xcassets/V2rayU.imageset/1024.png new file mode 100644 index 0000000000000000000000000000000000000000..f6b8946ec0fa63dabc0c4483bf587f068921dc69 GIT binary patch literal 308675 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�pO#?hU}0?`ghBq`K~w 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

+BQ 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 - + - + @@ -19,7 +19,7 @@ - + @@ -28,7 +28,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -46,7 +46,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -64,7 +64,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -82,7 +82,7 @@ - + @@ -91,7 +91,7 @@ - + @@ -100,7 +100,7 @@ - + diff --git a/v2rayu/V2rayU/Base.lproj/ToastWindow.xib b/v2rayu/V2rayU/Base.lproj/ToastWindow.xib index 0cde5efea2..4b007f438d 100644 --- a/v2rayu/V2rayU/Base.lproj/ToastWindow.xib +++ b/v2rayu/V2rayU/Base.lproj/ToastWindow.xib @@ -1,8 +1,8 @@ - + - + @@ -18,13 +18,13 @@ - + - + diff --git a/v2rayu/V2rayU/ConfigWindow.swift b/v2rayu/V2rayU/ConfigWindow.swift index 5d5c7b9c50..5da5e94a15 100644 --- a/v2rayu/V2rayU/ConfigWindow.swift +++ b/v2rayu/V2rayU/ConfigWindow.swift @@ -7,7 +7,6 @@ // import Cocoa -import Alamofire var v2rayConfig: V2rayConfig = V2rayConfig() @@ -645,22 +644,6 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel if let importUri = ImportUri.importUri(uri: uri, checkExist: false) { self.saveImport(importUri: importUri) - } else { - // download json file - Alamofire.request(jsonUrl.stringValue).responseString { DataResponse in - if (DataResponse.error != nil) { - DispatchQueue.main.async{ - self.errTip.stringValue = "error: " + DataResponse.error.debugDescription - } - return - } - - if DataResponse.value != nil { - DispatchQueue.main.async{ - self.configText.string = v2rayConfig.formatJson(json: DataResponse.value ?? text) - } - } - } } } diff --git a/v2rayu/V2rayU/Info.plist b/v2rayu/V2rayU/Info.plist index f943f715fa..2fca0a39bb 100644 --- a/v2rayu/V2rayU/Info.plist +++ b/v2rayu/V2rayU/Info.plist @@ -7,7 +7,11 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile + AppIcon + CFBundleGetInfoString + CFBundleDisplayName + CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion @@ -47,14 +51,10 @@ NSHumanReadableCopyright - Copyright © 2019 yanue. All rights reserved. + Copyright © 2024 yanue. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass NSApplication - SUFeedURL - https://v2rayu-61f76.web.app/appcast.xml - SUPublicEDKey - PW8pDnr5VZkmC93gZjUDlHI8gkJSspPoDU3DdhsMkps diff --git a/v2rayu/V2rayU/MainMenu.swift b/v2rayu/V2rayU/MainMenu.swift index 5152a70b1b..96615b9996 100644 --- a/v2rayu/V2rayU/MainMenu.swift +++ b/v2rayu/V2rayU/MainMenu.swift @@ -8,8 +8,6 @@ import Cocoa import ServiceManagement -import Sparkle -import Alamofire let menuController = (NSApplication.shared.delegate as? AppDelegate)?.statusMenu.delegate as! MenuController @@ -335,8 +333,7 @@ class MenuController: NSObject, NSMenuDelegate { } @IBAction func checkForUpdate(_ sender: NSMenuItem) { - // need set SUFeedURL into plist - V2rayUpdater.checkForUpdates() + V2rayUpdater.checkForUpdates(showWindow: true) } @IBAction func generateQrcode(_ sender: NSMenuItem) { diff --git a/v2rayu/V2rayU/Ping.swift b/v2rayu/V2rayU/Ping.swift index 59de2a6e2d..456f2ca663 100644 --- a/v2rayu/V2rayU/Ping.swift +++ b/v2rayu/V2rayU/Ping.swift @@ -6,7 +6,6 @@ // Copyright © 2019 yanue. All rights reserved. // -import Alamofire import SwiftyJSON // ping and choose fastest v2ray diff --git a/v2rayu/V2rayU/Preference/PreferenceGeneral.swift b/v2rayu/V2rayU/Preference/PreferenceGeneral.swift index 0bf18ae3bb..0b2959b19f 100644 --- a/v2rayu/V2rayU/Preference/PreferenceGeneral.swift +++ b/v2rayu/V2rayU/Preference/PreferenceGeneral.swift @@ -68,7 +68,6 @@ final class PreferenceGeneralViewController: NSViewController, PreferencePane { } @IBAction func checkVersion(_ sender: NSButton) { - // need set SUFeedURL into plist V2rayUpdater.checkForUpdates() } diff --git a/v2rayu/V2rayU/Preference/PreferencePac.swift b/v2rayu/V2rayU/Preference/PreferencePac.swift index 7ea2fba2ce..e5d4817c49 100644 --- a/v2rayu/V2rayU/Preference/PreferencePac.swift +++ b/v2rayu/V2rayU/Preference/PreferencePac.swift @@ -6,7 +6,6 @@ // Copyright © 2018 yanue. All rights reserved. // -import Alamofire import Cocoa import Preferences diff --git a/v2rayu/V2rayU/Preference/PreferenceSubscription.swift b/v2rayu/V2rayU/Preference/PreferenceSubscription.swift index b16e199443..214b8afdcd 100644 --- a/v2rayu/V2rayU/Preference/PreferenceSubscription.swift +++ b/v2rayu/V2rayU/Preference/PreferenceSubscription.swift @@ -8,7 +8,6 @@ import Cocoa import Preferences -import Alamofire import SwiftyJSON final class PreferenceSubscribeViewController: NSViewController, PreferencePane, NSTabViewDelegate { diff --git a/v2rayu/V2rayU/Sparkle.swift b/v2rayu/V2rayU/Sparkle.swift index 7827bb86c0..778bce71d6 100644 --- a/v2rayu/V2rayU/Sparkle.swift +++ b/v2rayu/V2rayU/Sparkle.swift @@ -23,7 +23,7 @@ class V2rayUpdaterController: NSObject, SPUUpdaterDelegate { func checkForUpdates() { // check version by github release - checkV2rayUVersion() +// checkV2rayUVersion() // check by sparkle fetchAppcast(from: primaryFeedURL) { success in // 主线程 diff --git a/v2rayu/V2rayU/Util.swift b/v2rayu/V2rayU/Util.swift index 40252c9e98..0d49788183 100644 --- a/v2rayu/V2rayU/Util.swift +++ b/v2rayu/V2rayU/Util.swift @@ -7,7 +7,6 @@ // import Cocoa -import Alamofire extension UserDefaults { enum KEY: String { diff --git a/v2rayu/V2rayU/V2rayLaunch.swift b/v2rayu/V2rayU/V2rayLaunch.swift index 734e463bd0..ee7ff2f109 100644 --- a/v2rayu/V2rayU/V2rayLaunch.swift +++ b/v2rayu/V2rayU/V2rayLaunch.swift @@ -428,58 +428,3 @@ class V2rayLaunch: NSObject { } } } - -func checkV2rayUVersion() { - // 当前版本检测 - Alamofire.request("https://api.github.com/repos/yanue/V2rayU/releases/latest").responseJSON { response in - //to get status code - if let status = response.response?.statusCode { - if status != 200 { - NSLog("error with response status: ", status) - return - } - } - - //to get JSON return value - if let result = response.result.value { - guard let JSON = result as? NSDictionary else { - NSLog("error: no tag_name") - return - } - - // get tag_name (version) - guard let tag_name = JSON["tag_name"] else { - NSLog("error: no tag_name") - return - } - - // get prerelease and draft - guard let prerelease = JSON["prerelease"], let draft = JSON["draft"] else { - // get - NSLog("error: get prerelease or draft") - return - } - - // not pre release or draft - if prerelease as! Bool == true || draft as! Bool == true { - NSLog("this release is a prerelease or draft") - return - } - - let newVer = (tag_name as! String) - // get old version - let oldVer = appVersion.replacingOccurrences(of: "v", with: "").versionToInt() - let curVer = newVer.replacingOccurrences(of: "v", with: "").versionToInt() - - // compare with [Int] - DispatchQueue.main.async { - if oldVer.lexicographicallyPrecedes(curVer) { - menuController.newVersionItem.isHidden = false - menuController.newVersionItem.title = "has new version " + newVer - } else { - menuController.newVersionItem.isHidden = true - } - } - } - } -} diff --git a/v2rayu/V2rayU/V2raySubscription.swift b/v2rayu/V2rayU/V2raySubscription.swift index fba04ce134..e0d9add155 100644 --- a/v2rayu/V2rayU/V2raySubscription.swift +++ b/v2rayu/V2rayU/V2raySubscription.swift @@ -7,7 +7,6 @@ // import Cocoa -import Alamofire import SwiftyJSON import Yams diff --git a/xray-core/transport/internet/splithttp/dialer.go b/xray-core/transport/internet/splithttp/dialer.go index cecab58f24..1a927a4993 100644 --- a/xray-core/transport/internet/splithttp/dialer.go +++ b/xray-core/transport/internet/splithttp/dialer.go @@ -1,6 +1,7 @@ package splithttp import ( + "bytes" "context" gotls "crypto/tls" "io" @@ -263,6 +264,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me return } + req.ContentLength = int64(chunk.Len()) req.Header = transportConfiguration.GetRequestHeader() if httpClient.isH2 { @@ -280,11 +282,19 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me return } } else { - var err error var uploadConn any - for i := 0; i < 5; i++ { + + // stringify the entire HTTP/1.1 request so it can be + // safely retried. if instead req.Write is called multiple + // times, the body is already drained after the first + // request + requestBytes := new(bytes.Buffer) + common.Must(req.Write(requestBytes)) + + for { uploadConn = httpClient.uploadRawPool.Get() - if uploadConn == nil { + newConnection := uploadConn == nil + if newConnection { uploadConn, err = httpClient.dialUploadConn(context.WithoutCancel(ctx)) if err != nil { errors.LogInfoInner(ctx, err, "failed to connect upload") @@ -293,18 +303,21 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me } } - err = req.Write(uploadConn.(net.Conn)) + _, err = uploadConn.(net.Conn).Write(requestBytes.Bytes()) + + // if the write failed, we try another connection from + // the pool, until the write on a new connection fails. + // failed writes to a pooled connection are normal when + // the connection has been closed in the meantime. if err == nil { break + } else if newConnection { + errors.LogInfoInner(ctx, err, "failed to send upload") + uploadPipeReader.Interrupt() + return } } - if err != nil { - errors.LogInfoInner(ctx, err, "failed to send upload") - uploadPipeReader.Interrupt() - return - } - httpClient.uploadRawPool.Put(uploadConn) } }() diff --git a/yass/.github/workflows/releases-rpm.yml b/yass/.github/workflows/releases-rpm.yml index 8742f92773..05913197e7 100644 --- a/yass/.github/workflows/releases-rpm.yml +++ b/yass/.github/workflows/releases-rpm.yml @@ -107,10 +107,10 @@ jobs: # gui_variant: gtk3 # - container: 'opensuse15' # gui_variant: qt5 - # - container: 'opensuse15' - # gui_variant: gtk4 - # except for qt6 package + # except for gtk4 and qt6 packages # glibc: 2.31 for opensuse15.5 + - container: 'opensuse15' + gui_variant: gtk4 - container: 'opensuse15' gui_variant: qt6 runs-on: ubuntu-22.04 diff --git a/yass/README.md b/yass/README.md index 095baf4813..0393a8e0ae 100644 --- a/yass/README.md +++ b/yass/README.md @@ -16,8 +16,8 @@ More details are at [Latest Release Page](https://github.com/Chilledheart/yass/r ### Prebuilt binaries (Linux) - GTK3 [download rpm](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-gtk3.el7.x86_64.1.11.3.rpm) or [download deb](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-gtk3-ubuntu-16.04-xenial_amd64.1.11.3.deb) (require glibc >= 2.16) - Qt5 [download rpm](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-qt5.el7.x86_64.1.11.3.rpm) or [download deb](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-qt5-ubuntu-16.04-xenial_amd64.1.11.3.deb) (require glibc >= 2.16) -- GTK4 [download rpm](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-gtk4.el9.x86_64.1.11.3.rpm) or [download deb](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-gtk4-ubuntu-22.04-jammy_amd64.1.11.3.deb) (require glibc >= 2.34) -- Qt6 [download rpm](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-qt6.lp155.x86_64.1.11.3.rpm) or [download deb](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-qt6-ubuntu-22.04-jammy_amd64.1.11.3.deb) (require glibc >= 2.36) +- GTK4 [download rpm](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-gtk4.el9.x86_64.1.11.3.rpm) or [download deb](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-gtk4-ubuntu-22.04-jammy_amd64.1.11.3.deb) (require glibc >= 2.35) +- Qt6 [download rpm](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-qt6.lp155.x86_64.1.11.3.rpm) or [download deb](https://github.com/Chilledheart/yass/releases/download/1.11.3/yass-qt6-ubuntu-22.04-jammy_amd64.1.11.3.deb) (require glibc >= 2.35) [![aur yass-proxy-gtk3](https://img.shields.io/aur/version/yass-proxy-gtk3)](https://aur.archlinux.org/packages/yass-proxy-gtk3) [![aur yass-proxy-qt5](https://img.shields.io/aur/version/yass-proxy-qt5)](https://aur.archlinux.org/packages/yass-proxy-qt5) diff --git a/yass/src/android/jni.cpp b/yass/src/android/jni.cpp index 02ebc24326..479605d87f 100644 --- a/yass/src/android/jni.cpp +++ b/yass/src/android/jni.cpp @@ -9,6 +9,8 @@ #include "config/config.hpp" #include "crypto/crypter_export.hpp" +#include +#include #include #include @@ -18,6 +20,20 @@ jobject g_activity_obj = nullptr; JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { g_jvm = vm; + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } + return JNI_VERSION_1_6; } diff --git a/yass/src/cli/cli.cpp b/yass/src/cli/cli.cpp index ff51b94aee..83e912982c 100644 --- a/yass/src/cli/cli.cpp +++ b/yass/src/cli/cli.cpp @@ -57,6 +57,21 @@ static asio::ip::tcp::resolver::results_type ResolveAddress(const std::string& d } int main(int argc, const char* argv[]) { +#ifndef _WIN32 + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } +#endif SetExecutablePath(argv[0]); std::string exec_path; if (!GetExecutablePath(&exec_path)) { @@ -206,10 +221,6 @@ int main(int argc, const char* argv[]) { }; signals.async_wait(cb); -#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_OHOS) - CHECK_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN)); -#endif - io_context.run(); PrintMallocStats(); diff --git a/yass/src/cli/cli_worker.cpp b/yass/src/cli/cli_worker.cpp index f3877e8d92..0771605b63 100644 --- a/yass/src/cli/cli_worker.cpp +++ b/yass/src/cli/cli_worker.cpp @@ -5,11 +5,13 @@ #include #include #include -#include #include "third_party/boringssl/src/include/openssl/crypto.h" #ifdef _WIN32 #include +#else +#include +#include #endif #include "cli/cli_server.hpp" @@ -41,10 +43,6 @@ Worker::Worker() CRYPTO_library_init(); -#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_OHOS) - CHECK_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN)); -#endif - thread_ = std::make_unique([this] { WorkFunc(); }); } @@ -173,6 +171,22 @@ void Worker::WorkFunc() { } LOG(INFO) << "worker: background thread started"; + +#ifndef _WIN32 + /* Check if we have blocked SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, nullptr, &saved_mask) == 0) { + if (sigismember(&saved_mask, SIGPIPE)) { + LOG(INFO) << "worker: signal SIGPIPE is masked as BLOCKED"; + } else { + PLOG(WARNING) << "worker: signal SIGPIPE is not masked as BLOCKED!"; + } + } else { + PLOG(WARNING) << "worker: pthread_sigmask failed"; + } +#endif + while (!in_destroy_) { work_guard_ = std::make_unique>(io_context_.get_executor()); diff --git a/yass/src/gtk/yass.cpp b/yass/src/gtk/yass.cpp index fbe09e3bf4..2fd6b0342f 100644 --- a/yass/src/gtk/yass.cpp +++ b/yass/src/gtk/yass.cpp @@ -33,6 +33,21 @@ static const char* kAppId = "it.gui.yass"; static const char* kAppName = YASS_APP_PRODUCT_NAME; int main(int argc, const char** argv) { +#ifndef _WIN32 + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } +#endif SetExecutablePath(argv[0]); std::string exec_path; if (!GetExecutablePath(&exec_path)) { diff --git a/yass/src/gtk4/yass.cpp b/yass/src/gtk4/yass.cpp index 8397a18966..0ae6207647 100644 --- a/yass/src/gtk4/yass.cpp +++ b/yass/src/gtk4/yass.cpp @@ -98,6 +98,21 @@ YASSGtkApp* yass_app_new(void) { } // extern "C" int main(int argc, const char** argv) { +#ifndef _WIN32 + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } +#endif SetExecutablePath(argv[0]); std::string exec_path; if (!GetExecutablePath(&exec_path)) { diff --git a/yass/src/harmony/yass.cpp b/yass/src/harmony/yass.cpp index 005f2c5902..222dc7cef3 100644 --- a/yass/src/harmony/yass.cpp +++ b/yass/src/harmony/yass.cpp @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include @@ -1153,6 +1155,20 @@ static napi_module yassModule = { }; extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } + napi_module_register(&yassModule); } diff --git a/yass/src/ios/extensions/YassPacketTunnelProvider.mm b/yass/src/ios/extensions/YassPacketTunnelProvider.mm index 4d529bb5fc..7cb1af0c79 100644 --- a/yass/src/ios/extensions/YassPacketTunnelProvider.mm +++ b/yass/src/ios/extensions/YassPacketTunnelProvider.mm @@ -3,6 +3,8 @@ #import "YassPacketTunnelProvider.h" +#include +#include #include #include @@ -34,6 +36,22 @@ static constexpr const uint32_t kYieldConcurrencyOfConnections = 12u; - (void)startTunnelWithOptions:(NSDictionary*)options completionHandler:(void (^)(NSError*))completionHandler { stopped_ = false; + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + completionHandler([NSError errorWithDomain:@"it.gui.ios.yass" + code:200 + userInfo:@{@"Error reason" : @(strerror(errno))}]); + return; + } SetExecutablePath("UNKNOWN.ext"); NETunnelProviderProtocol* protocolConfiguration = (NETunnelProviderProtocol*)self.protocolConfiguration; diff --git a/yass/src/ios/main.mm b/yass/src/ios/main.mm index c9c37ff11c..76eebe41b4 100644 --- a/yass/src/ios/main.mm +++ b/yass/src/ios/main.mm @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include @@ -26,6 +28,19 @@ const ProgramType pType = YASS_CLIENT_SLAVE; int main(int argc, const char** argv) { + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } SetExecutablePath(argv[0]); std::string exec_path; if (!GetExecutablePath(&exec_path)) { diff --git a/yass/src/mac/main.mm b/yass/src/mac/main.mm index 1d460bc420..50e0125ddc 100644 --- a/yass/src/mac/main.mm +++ b/yass/src/mac/main.mm @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include @@ -37,6 +39,20 @@ __attribute__((used)) const char kGrossPaddingForCrbug1300598[68 * 1024] = {}; #endif int main(int argc, const char** argv) { + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } + SetExecutablePath(argv[0]); std::string exec_path; if (!GetExecutablePath(&exec_path)) { diff --git a/yass/src/qt6/yass.cpp b/yass/src/qt6/yass.cpp index cfcdbe9d50..e9f20eedbc 100644 --- a/yass/src/qt6/yass.cpp +++ b/yass/src/qt6/yass.cpp @@ -27,6 +27,21 @@ #include "version.h" int main(int argc, const char** argv) { +#ifndef _WIN32 + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } +#endif SetExecutablePath(argv[0]); std::string exec_path; if (!GetExecutablePath(&exec_path)) { @@ -59,30 +74,6 @@ int main(int argc, const char** argv) { YASSApp program(argc, const_cast(argv)); -#ifndef _WIN32 - // setup signal handler - signal(SIGPIPE, SIG_IGN); - - struct sigaction sig_handler; - - sig_handler.sa_handler = [](int signal_num) { App()->quit(); }; - sigemptyset(&sig_handler.sa_mask); - sig_handler.sa_flags = 0; - - sigaction(SIGINT, &sig_handler, nullptr); - - /* Block SIGPIPE in all threads, this can happen if a thread calls write on - a closed pipe. */ - sigset_t sigpipe_mask; - sigemptyset(&sigpipe_mask); - sigaddset(&sigpipe_mask, SIGPIPE); - sigset_t saved_mask; - if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { - PLOG(WARNING) << "pthread_sigmask failed"; - return -1; - } -#endif - // call program init if (!program.Init()) { return 0; diff --git a/yass/src/server/server.cpp b/yass/src/server/server.cpp index f8219ae646..709627a757 100644 --- a/yass/src/server/server.cpp +++ b/yass/src/server/server.cpp @@ -35,6 +35,21 @@ const ProgramType pType = YASS_SERVER; using namespace net::server; int main(int argc, const char* argv[]) { +#ifndef _WIN32 + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } +#endif SetExecutablePath(argv[0]); std::string exec_path; if (!GetExecutablePath(&exec_path)) { @@ -176,10 +191,6 @@ int main(int argc, const char* argv[]) { }; signals.async_wait(cb); -#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) - CHECK_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN)); -#endif - #ifndef _WIN32 // change user and change group std::string username = absl::GetFlag(FLAGS_user); diff --git a/yass/src/ss_benchmark.cpp b/yass/src/ss_benchmark.cpp index 99a08c61e8..b3c8f8aca1 100644 --- a/yass/src/ss_benchmark.cpp +++ b/yass/src/ss_benchmark.cpp @@ -131,10 +131,6 @@ class ContentProviderConnection : public RefCountedThreadSafesocket_.native_non_blocking(false, ec); - downlink_->socket_.non_blocking(false, ec); do_io(); } @@ -582,6 +578,21 @@ int xc_main() { char* argv[] = {(char*)"xc_main", nullptr}; #else int main(int argc, char** argv) { +#endif +#ifndef _WIN32 + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } #endif SetExecutablePath(argv[0]); std::string exec_path; @@ -631,10 +642,6 @@ int main(int argc, char** argv) { CRYPTO_library_init(); -#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_OHOS) - CHECK_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN)); -#endif - if (absl::GetFlag(FLAGS_ipv6_mode)) { CHECK(Net_ipv6works()) << "IPv6 stack is required but not available"; } diff --git a/yass/src/ss_test.cpp b/yass/src/ss_test.cpp index 079d74fd94..fbc9d5f3f4 100644 --- a/yass/src/ss_test.cpp +++ b/yass/src/ss_test.cpp @@ -144,10 +144,6 @@ class ContentProviderConnection : public RefCountedThreadSafesocket_.native_non_blocking(false, ec); - downlink_->socket_.non_blocking(false, ec); do_io(); } @@ -736,6 +732,22 @@ int xc_main() { #else int main(int argc, char** argv) { #endif +#ifndef _WIN32 + // setup signal handler + signal(SIGPIPE, SIG_IGN); + + /* Block SIGPIPE in all threads, this can happen if a thread calls write on + a closed pipe. */ + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + sigset_t saved_mask; + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { + perror("pthread_sigmask failed"); + return -1; + } +#endif + SetExecutablePath(argv[0]); std::string exec_path; if (!GetExecutablePath(&exec_path)) { @@ -788,10 +800,6 @@ int main(int argc, char** argv) { curl_global_init(CURL_GLOBAL_ALL); #endif -#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_OHOS) - CHECK_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN)); -#endif - if (absl::GetFlag(FLAGS_ipv6_mode)) { CHECK(Net_ipv6works()) << "IPv6 stack is required but not available"; } diff --git a/yass/yass.spec.in b/yass/yass.spec.in index 1d77d08935..3083964d99 100644 --- a/yass/yass.spec.in +++ b/yass/yass.spec.in @@ -9,14 +9,16 @@ %endif # on centos, nghttp2 sits in epel repo -%if 0%{?fedora} || 0%{?sle_version} +# on opensuse, nghttp might be outdated +%if 0%{?fedora} %global enable_system_nghttp2_opt on %else %global enable_system_nghttp2_opt off %endif # on centos, mbedtls sits in epel repo -%if 0%{?fedora} || 0%{?sle_version} +# on opensuse, mbedtls might be outdated +%if 0%{?fedora} %global enable_system_mbedtls_opt on %else %global enable_system_mbedtls_opt off @@ -157,7 +159,7 @@ BuildRequires: cmake3 >= 3.12, pkgconfig %if 0%{?fedora} BuildRequires: c-ares-devel %endif -%if 0%{?fedora} || 0%{?sle_version} +%if 0%{?fedora} BuildRequires: mbedtls-devel %endif %if 0%{?fedora} && !%{with use_libcxx} @@ -167,7 +169,7 @@ BuildRequires: gperftools-devel BuildRequires: json-devel %endif BuildRequires: zlib-devel -%if 0%{?fedora} || 0%{?sle_version} +%if 0%{?fedora} BuildRequires: libnghttp2-devel %endif BuildRequires: gcc, gcc-c++, golang >= 1.4 diff --git a/yt-dlp/README.md b/yt-dlp/README.md index ea7c671748..ed022c0b9d 100644 --- a/yt-dlp/README.md +++ b/yt-dlp/README.md @@ -1288,6 +1288,8 @@ The available fields are: - `playlist_autonumber` (numeric): Position of the video in the playlist download queue padded with leading zeros according to the total length of the playlist - `playlist_uploader` (string): Full name of the playlist uploader - `playlist_uploader_id` (string): Nickname or id of the playlist uploader + - `playlist_channel` (string): Display name of the channel that uploaded the playlist + - `playlist_channel_id` (string): Identifier of the channel that uploaded the playlist - `webpage_url` (string): A URL to the video webpage which if given to yt-dlp should allow to get the same result again - `webpage_url_basename` (string): The basename of the webpage URL - `webpage_url_domain` (string): The domain of the webpage URL @@ -1851,6 +1853,9 @@ The following extractors use this feature: #### soundcloud * `formats`: Formats to request from the API. Requested values should be in the format of `{protocol}_{extension}` (omitting the bitrate), e.g. `hls_opus,http_aac`. The `*` character functions as a wildcard, e.g. `*_mp3`, and can passed by itself to request all formats. Known protocols include `http`, `hls` and `hls-aes`; known extensions include `aac`, `opus` and `mp3`. Original `download` formats are always extracted. Default is `http_aac,hls_aac,http_opus,hls_opus,http_mp3,hls_mp3` +#### orfon (orf:on) +* `prefer_segments_playlist`: Prefer a playlist of program segments instead of a single complete video when available. If individual segments are desired, use `--concat-playlist never --extractor-args "orfon:prefer_segments_playlist"` + **Note**: These options may be changed/removed in the future without concern for backward compatibility diff --git a/yt-dlp/yt_dlp/YoutubeDL.py b/yt-dlp/yt_dlp/YoutubeDL.py index 7ed01bf840..ba29b29dcb 100644 --- a/yt-dlp/yt_dlp/YoutubeDL.py +++ b/yt-dlp/yt_dlp/YoutubeDL.py @@ -1926,6 +1926,8 @@ class YoutubeDL: 'playlist_title': ie_result.get('title'), 'playlist_uploader': ie_result.get('uploader'), 'playlist_uploader_id': ie_result.get('uploader_id'), + 'playlist_channel': ie_result.get('channel'), + 'playlist_channel_id': ie_result.get('channel_id'), **kwargs, } if strict: diff --git a/yt-dlp/yt_dlp/extractor/_extractors.py b/yt-dlp/yt_dlp/extractor/_extractors.py index c411efb5aa..7f6507defd 100644 --- a/yt-dlp/yt_dlp/extractor/_extractors.py +++ b/yt-dlp/yt_dlp/extractor/_extractors.py @@ -76,6 +76,7 @@ from .aenetworks import ( ) from .aeonco import AeonCoIE from .afreecatv import ( + AfreecaTVCatchStoryIE, AfreecaTVIE, AfreecaTVLiveIE, AfreecaTVUserIE, @@ -779,6 +780,7 @@ from .gopro import GoProIE from .goshgay import GoshgayIE from .gotostage import GoToStageIE from .gputechconf import GPUTechConfIE +from .graspop import GraspopIE from .gronkh import ( GronkhFeedIE, GronkhIE, @@ -969,6 +971,10 @@ from .la7 import ( LA7PodcastEpisodeIE, LA7PodcastIE, ) +from .laracasts import ( + LaracastsIE, + LaracastsPlaylistIE, +) from .lastfm import ( LastFMIE, LastFMPlaylistIE, @@ -1113,12 +1119,15 @@ from .meipai import MeipaiIE from .melonvod import MelonVODIE from .metacritic import MetacriticIE from .mgtv import MGTVIE -from .microsoftembed import MicrosoftEmbedIE -from .microsoftstream import MicrosoftStreamIE -from .microsoftvirtualacademy import ( - MicrosoftVirtualAcademyCourseIE, - MicrosoftVirtualAcademyIE, +from .microsoftembed import ( + MicrosoftBuildIE, + MicrosoftEmbedIE, + MicrosoftLearnEpisodeIE, + MicrosoftLearnPlaylistIE, + MicrosoftLearnSessionIE, + MicrosoftMediusIE, ) +from .microsoftstream import MicrosoftStreamIE from .mildom import ( MildomClipIE, MildomIE, @@ -1603,6 +1612,7 @@ from .qqmusic import ( QQMusicPlaylistIE, QQMusicSingerIE, QQMusicToplistIE, + QQMusicVideoIE, ) from .r7 import ( R7IE, diff --git a/yt-dlp/yt_dlp/extractor/afreecatv.py b/yt-dlp/yt_dlp/extractor/afreecatv.py index bcfb02cb95..f51b5a68b5 100644 --- a/yt-dlp/yt_dlp/extractor/afreecatv.py +++ b/yt-dlp/yt_dlp/extractor/afreecatv.py @@ -72,7 +72,7 @@ class AfreecaTVIE(AfreecaTVBaseIE): )\?.*?\bnTitleNo=| vod\.afreecatv\.com/(PLAYER/STATION|player)/ ) - (?P\d+) + (?P\d+)/?(?:$|[?#&]) ''' _TESTS = [{ 'url': 'http://live.afreecatv.com:8079/app/index.cgi?szType=read_ucc_bbs&szBjId=dailyapril&nStationNo=16711924&nBbsNo=18605867&nTitleNo=36164052&szSkin=', @@ -189,7 +189,7 @@ class AfreecaTVIE(AfreecaTVBaseIE): headers={'Referer': url}, data=urlencode_postdata({ 'nTitleNo': video_id, 'nApiLevel': 10, - }))['data'] + }), impersonate=True)['data'] error_code = traverse_obj(data, ('code', {int})) if error_code == -6221: @@ -253,6 +253,43 @@ class AfreecaTVIE(AfreecaTVBaseIE): return self.playlist_result(entries, video_id, multi_video=True, **common_info) +class AfreecaTVCatchStoryIE(AfreecaTVBaseIE): + IE_NAME = 'afreecatv:catchstory' + IE_DESC = 'afreecatv.com catch story' + _VALID_URL = r'https?://vod\.afreecatv\.com/player/(?P\d+)/catchstory' + _TESTS = [{ + 'url': 'https://vod.afreecatv.com/player/103247/catchstory', + 'info_dict': { + 'id': '103247', + }, + 'playlist_count': 2, + }] + + def _real_extract(self, url): + video_id = self._match_id(url) + data = self._download_json( + 'https://api.m.afreecatv.com/catchstory/a/view', video_id, headers={'Referer': url}, + query={'aStoryListIdx': '', 'nStoryIdx': video_id}, impersonate=True) + + return self.playlist_result(self._entries(data), video_id) + + @staticmethod + def _entries(data): + # 'files' is always a list with 1 element + yield from traverse_obj(data, ( + 'data', lambda _, v: v['story_type'] == 'catch', + 'catch_list', lambda _, v: v['files'][0]['file'], { + 'id': ('files', 0, 'file_info_key', {str}), + 'url': ('files', 0, 'file', {url_or_none}), + 'duration': ('files', 0, 'duration', {functools.partial(int_or_none, scale=1000)}), + 'title': ('title', {str}), + 'uploader': ('writer_nick', {str}), + 'uploader_id': ('writer_id', {str}), + 'thumbnail': ('thumb', {url_or_none}), + 'timestamp': ('write_timestamp', {int_or_none}), + })) + + class AfreecaTVLiveIE(AfreecaTVBaseIE): IE_NAME = 'afreecatv:live' IE_DESC = 'afreecatv.com livestreams' diff --git a/yt-dlp/yt_dlp/extractor/digitalconcerthall.py b/yt-dlp/yt_dlp/extractor/digitalconcerthall.py index 594ce2d0b9..8b4d5c0fc4 100644 --- a/yt-dlp/yt_dlp/extractor/digitalconcerthall.py +++ b/yt-dlp/yt_dlp/extractor/digitalconcerthall.py @@ -1,16 +1,16 @@ from .common import InfoExtractor from ..utils import ( ExtractorError, - parse_resolution, - traverse_obj, try_get, + url_or_none, urlencode_postdata, ) +from ..utils.traversal import traverse_obj class DigitalConcertHallIE(InfoExtractor): IE_DESC = 'DigitalConcertHall extractor' - _VALID_URL = r'https?://(?:www\.)?digitalconcerthall\.com/(?P[a-z]+)/(?Pfilm|concert)/(?P[0-9]+)' + _VALID_URL = r'https?://(?:www\.)?digitalconcerthall\.com/(?P[a-z]+)/(?Pfilm|concert|work)/(?P[0-9]+)-?(?P[0-9]+)?' _OAUTH_URL = 'https://api.digitalconcerthall.com/v2/oauth2/token' _ACCESS_TOKEN = None _NETRC_MACHINE = 'digitalconcerthall' @@ -26,7 +26,8 @@ class DigitalConcertHallIE(InfoExtractor): 'upload_date': '20210624', 'timestamp': 1624548600, 'duration': 2798, - 'album_artist': 'Members of the Berliner Philharmoniker / Simon Rössler', + 'album_artists': ['Members of the Berliner Philharmoniker', 'Simon Rössler'], + 'composers': ['Kurt Weill'], }, 'params': {'skip_download': 'm3u8'}, }, { @@ -34,8 +35,9 @@ class DigitalConcertHallIE(InfoExtractor): 'url': 'https://www.digitalconcerthall.com/en/concert/53785', 'info_dict': { 'id': '53785', - 'album_artist': 'Berliner Philharmoniker / Kirill Petrenko', + 'album_artists': ['Berliner Philharmoniker', 'Kirill Petrenko'], 'title': 'Kirill Petrenko conducts Mendelssohn and Shostakovich', + 'thumbnail': r're:^https?://images.digitalconcerthall.com/cms/thumbnails.*\.jpg$', }, 'params': {'skip_download': 'm3u8'}, 'playlist_count': 3, @@ -49,9 +51,20 @@ class DigitalConcertHallIE(InfoExtractor): 'thumbnail': r're:^https?://images.digitalconcerthall.com/cms/thumbnails.*\.jpg$', 'upload_date': '20220714', 'timestamp': 1657785600, - 'album_artist': 'Frank Peter Zimmermann / Benedikt von Bernstorff / Jakob von Bernstorff', + 'album_artists': ['Frank Peter Zimmermann', 'Benedikt von Bernstorff', 'Jakob von Bernstorff'], }, 'params': {'skip_download': 'm3u8'}, + }, { + 'note': 'Concert with several works and an interview', + 'url': 'https://www.digitalconcerthall.com/en/work/53785-1', + 'info_dict': { + 'id': '53785', + 'album_artists': ['Berliner Philharmoniker', 'Kirill Petrenko'], + 'title': 'Kirill Petrenko conducts Mendelssohn and Shostakovich', + 'thumbnail': r're:^https?://images.digitalconcerthall.com/cms/thumbnails.*\.jpg$', + }, + 'params': {'skip_download': 'm3u8'}, + 'playlist_count': 1, }] def _perform_login(self, username, password): @@ -97,15 +110,14 @@ class DigitalConcertHallIE(InfoExtractor): 'Accept-Language': language, }) - m3u8_url = traverse_obj( - stream_info, ('channel', lambda k, _: k.startswith('vod_mixed'), 'stream', 0, 'url'), get_all=False) - formats = self._extract_m3u8_formats(m3u8_url, video_id, 'mp4', 'm3u8_native', fatal=False) + formats = [] + for m3u8_url in traverse_obj(stream_info, ('channel', ..., 'stream', ..., 'url', {url_or_none})): + formats.extend(self._extract_m3u8_formats(m3u8_url, video_id, 'mp4', fatal=False)) yield { 'id': video_id, 'title': item.get('title'), 'composer': item.get('name_composer'), - 'url': m3u8_url, 'formats': formats, 'duration': item.get('duration_total'), 'timestamp': traverse_obj(item, ('date', 'published')), @@ -119,31 +131,32 @@ class DigitalConcertHallIE(InfoExtractor): } def _real_extract(self, url): - language, type_, video_id = self._match_valid_url(url).group('language', 'type', 'id') + language, type_, video_id, part = self._match_valid_url(url).group('language', 'type', 'id', 'part') if not language: language = 'en' - thumbnail_url = self._html_search_regex( - r'(https?://images\.digitalconcerthall\.com/cms/thumbnails/.*\.jpg)', - self._download_webpage(url, video_id), 'thumbnail') - thumbnails = [{ - 'url': thumbnail_url, - **parse_resolution(thumbnail_url), - }] - + api_type = 'concert' if type_ == 'work' else type_ vid_info = self._download_json( - f'https://api.digitalconcerthall.com/v2/{type_}/{video_id}', video_id, headers={ + f'https://api.digitalconcerthall.com/v2/{api_type}/{video_id}', video_id, headers={ 'Accept': 'application/json', 'Accept-Language': language, }) - album_artist = ' / '.join(traverse_obj(vid_info, ('_links', 'artist', ..., 'name')) or '') + album_artists = traverse_obj(vid_info, ('_links', 'artist', ..., 'name')) videos = [vid_info] if type_ == 'film' else traverse_obj(vid_info, ('_embedded', ..., ...)) + if type_ == 'work': + videos = [videos[int(part) - 1]] + + thumbnail = traverse_obj(vid_info, ( + 'image', ..., {self._proto_relative_url}, {url_or_none}, + {lambda x: x.format(width=0, height=0)}, any)) # NB: 0x0 is the original size + return { '_type': 'playlist', 'id': video_id, 'title': vid_info.get('title'), - 'entries': self._entries(videos, language, thumbnails=thumbnails, album_artist=album_artist, type_=type_), - 'thumbnails': thumbnails, - 'album_artist': album_artist, + 'entries': self._entries( + videos, language, type_, thumbnail=thumbnail, album_artists=album_artists), + 'thumbnail': thumbnail, + 'album_artists': album_artists, } diff --git a/yt-dlp/yt_dlp/extractor/graspop.py b/yt-dlp/yt_dlp/extractor/graspop.py new file mode 100644 index 0000000000..09371f8c46 --- /dev/null +++ b/yt-dlp/yt_dlp/extractor/graspop.py @@ -0,0 +1,32 @@ +from .common import InfoExtractor +from ..utils import update_url, url_or_none +from ..utils.traversal import traverse_obj + + +class GraspopIE(InfoExtractor): + _VALID_URL = r'https?://vod\.graspop\.be/[a-z]{2}/(?P\d+)/' + _TESTS = [{ + 'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/', + 'info_dict': { + 'id': '101556', + 'ext': 'mp4', + 'title': 'Thy Art Is Murder', + 'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg', + }, + }] + + def _real_extract(self, url): + video_id = self._match_id(url) + metadata = self._download_json( + f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id) + + return { + 'id': video_id, + 'formats': self._extract_m3u8_formats( + # Downgrade manifest request to avoid incomplete certificate chain error + update_url(metadata['source']['assetUri'], scheme='http'), video_id, 'mp4'), + **traverse_obj(metadata, { + 'title': ('name', {str}), + 'thumbnail': ('source', 'poster', {url_or_none}), + }), + } diff --git a/yt-dlp/yt_dlp/extractor/jiocinema.py b/yt-dlp/yt_dlp/extractor/jiocinema.py index 5898e1f497..30d98ba796 100644 --- a/yt-dlp/yt_dlp/extractor/jiocinema.py +++ b/yt-dlp/yt_dlp/extractor/jiocinema.py @@ -364,20 +364,25 @@ class JioCinemaSeriesIE(JioCinemaBaseIE): 'title': 'naagin', }, 'playlist_mincount': 120, + }, { + 'url': 'https://www.jiocinema.com/tv-shows/mtv-splitsvilla-x5/3499820', + 'info_dict': { + 'id': '3499820', + 'title': 'mtv-splitsvilla-x5', + }, + 'playlist_mincount': 310, }] def _entries(self, series_id): - seasons = self._download_json( - f'{self._METADATA_API_BASE}/voot/v1/voot-web/content/generic/season-by-show', series_id, - 'Downloading series metadata JSON', query={ - 'sort': 'season:asc', - 'id': series_id, - 'responseType': 'common', - }) + seasons = traverse_obj(self._download_json( + f'{self._METADATA_API_BASE}/voot/v1/voot-web/view/show/{series_id}', series_id, + 'Downloading series metadata JSON', query={'responseType': 'common'}), ( + 'trays', lambda _, v: v['trayId'] == 'season-by-show-multifilter', + 'trayTabs', lambda _, v: v['id'])) - for season_num, season in enumerate(traverse_obj(seasons, ('result', lambda _, v: v['id'])), 1): + for season_num, season in enumerate(seasons, start=1): season_id = season['id'] - label = season.get('season') or season_num + label = season.get('label') or season_num for page_num in itertools.count(1): episodes = traverse_obj(self._download_json( f'{self._METADATA_API_BASE}/voot/v1/voot-web/content/generic/series-wise-episode', diff --git a/yt-dlp/yt_dlp/extractor/laracasts.py b/yt-dlp/yt_dlp/extractor/laracasts.py new file mode 100644 index 0000000000..4494c4b79a --- /dev/null +++ b/yt-dlp/yt_dlp/extractor/laracasts.py @@ -0,0 +1,114 @@ +import json + +from .common import InfoExtractor +from .vimeo import VimeoIE +from ..utils import ( + clean_html, + extract_attributes, + get_element_html_by_id, + int_or_none, + parse_duration, + str_or_none, + unified_strdate, + url_or_none, + urljoin, +) +from ..utils.traversal import traverse_obj + + +class LaracastsBaseIE(InfoExtractor): + def _get_prop_data(self, url, display_id): + webpage = self._download_webpage(url, display_id) + return traverse_obj( + get_element_html_by_id('app', webpage), + ({extract_attributes}, 'data-page', {json.loads}, 'props')) + + def _parse_episode(self, episode): + if not traverse_obj(episode, 'vimeoId'): + self.raise_login_required('This video is only available for subscribers.') + return self.url_result( + VimeoIE._smuggle_referrer( + f'https://player.vimeo.com/video/{episode["vimeoId"]}', 'https://laracasts.com/'), + VimeoIE, url_transparent=True, + **traverse_obj(episode, { + 'id': ('id', {int}, {str_or_none}), + 'webpage_url': ('path', {lambda x: urljoin('https://laracasts.com', x)}), + 'title': ('title', {clean_html}), + 'season_number': ('chapter', {int_or_none}), + 'episode_number': ('position', {int_or_none}), + 'description': ('body', {clean_html}), + 'thumbnail': ('largeThumbnail', {url_or_none}), + 'duration': ('length', {int_or_none}), + 'date': ('dateSegments', 'published', {unified_strdate}), + })) + + +class LaracastsIE(LaracastsBaseIE): + IE_NAME = 'laracasts' + _VALID_URL = r'https?://(?:www\.)?laracasts\.com/series/(?P[\w-]+/episodes/\d+)/?(?:[?#]|$)' + _TESTS = [{ + 'url': 'https://laracasts.com/series/30-days-to-learn-laravel-11/episodes/1', + 'md5': 'c8f5e7b02ad0e438ef9280a08c8493dc', + 'info_dict': { + 'id': '922040563', + 'title': 'Hello, Laravel', + 'ext': 'mp4', + 'duration': 519, + 'date': '20240312', + 'thumbnail': 'https://laracasts.s3.amazonaws.com/videos/thumbnails/youtube/30-days-to-learn-laravel-11-1.png', + 'description': 'md5:ddd658bb241975871d236555657e1dd1', + 'season_number': 1, + 'season': 'Season 1', + 'episode_number': 1, + 'episode': 'Episode 1', + 'uploader': 'Laracasts', + 'uploader_id': 'user20182673', + 'uploader_url': 'https://vimeo.com/user20182673', + }, + 'expected_warnings': ['Failed to parse XML'], # TODO: Remove when vimeo extractor is fixed + }] + + def _real_extract(self, url): + display_id = self._match_id(url) + return self._parse_episode(self._get_prop_data(url, display_id)['lesson']) + + +class LaracastsPlaylistIE(LaracastsBaseIE): + IE_NAME = 'laracasts:series' + _VALID_URL = r'https?://(?:www\.)?laracasts\.com/series/(?P[\w-]+)/?(?:[?#]|$)' + _TESTS = [{ + 'url': 'https://laracasts.com/series/30-days-to-learn-laravel-11', + 'info_dict': { + 'title': '30 Days to Learn Laravel', + 'id': '210', + 'thumbnail': 'https://laracasts.s3.amazonaws.com/series/thumbnails/social-cards/30-days-to-learn-laravel-11.png?v=2', + 'duration': 30600.0, + 'modified_date': '20240511', + 'description': 'md5:27c260a1668a450984e8f901579912dd', + 'categories': ['Frameworks'], + 'tags': ['Laravel'], + 'display_id': '30-days-to-learn-laravel-11', + }, + 'playlist_count': 30, + }] + + def _real_extract(self, url): + display_id = self._match_id(url) + series = self._get_prop_data(url, display_id)['series'] + + metadata = { + 'display_id': display_id, + **traverse_obj(series, { + 'title': ('title', {str}), + 'id': ('id', {int}, {str_or_none}), + 'description': ('body', {clean_html}), + 'thumbnail': (('large_thumbnail', 'thumbnail'), {url_or_none}, any), + 'duration': ('runTime', {parse_duration}), + 'categories': ('taxonomy', 'name', {str}, {lambda x: x and [x]}), + 'tags': ('topics', ..., 'name', {str}), + 'modified_date': ('lastUpdated', {unified_strdate}), + }), + } + + return self.playlist_result(traverse_obj( + series, ('chapters', ..., 'episodes', lambda _, v: v['vimeoId'], {self._parse_episode})), **metadata) diff --git a/yt-dlp/yt_dlp/extractor/microsoftembed.py b/yt-dlp/yt_dlp/extractor/microsoftembed.py index 98d50b18a9..d0135f5a9c 100644 --- a/yt-dlp/yt_dlp/extractor/microsoftembed.py +++ b/yt-dlp/yt_dlp/extractor/microsoftembed.py @@ -1,5 +1,14 @@ +import re + from .common import InfoExtractor -from ..utils import int_or_none, traverse_obj, unified_timestamp +from ..utils import ( + int_or_none, + parse_iso8601, + traverse_obj, + unified_timestamp, + url_basename, + url_or_none, +) class MicrosoftEmbedIE(InfoExtractor): @@ -63,3 +72,250 @@ class MicrosoftEmbedIE(InfoExtractor): 'subtitles': subtitles, 'thumbnails': thumbnails, } + + +class MicrosoftMediusBaseIE(InfoExtractor): + @staticmethod + def _sub_to_dict(subtitle_list): + subtitles = {} + for sub in subtitle_list: + subtitles.setdefault(sub.pop('tag', 'und'), []).append(sub) + return subtitles + + def _extract_ism(self, ism_url, video_id): + formats = self._extract_ism_formats(ism_url, video_id) + for fmt in formats: + if fmt['language'] != 'eng' and 'English' not in fmt['format_id']: + fmt['language_preference'] = -10 + return formats + + +class MicrosoftMediusIE(MicrosoftMediusBaseIE): + _VALID_URL = r'https?://medius\.microsoft\.com/Embed/(?:Video\?id=|video-nc/|VideoDetails/)(?P[\da-f-]+)' + + _TESTS = [{ + 'url': 'https://medius.microsoft.com/Embed/video-nc/9640d86c-f513-4889-959e-5dace86e7d2b', + 'info_dict': { + 'id': '9640d86c-f513-4889-959e-5dace86e7d2b', + 'ext': 'ismv', + 'title': 'Rapidly code, test and ship from secure cloud developer environments', + 'description': 'md5:33c8e4facadc438613476eea24165f71', + 'thumbnail': r're:https://mediusimg\.event\.microsoft\.com/video-\d+/thumbnail\.jpg.*', + 'subtitles': 'count:30', + }, + }, { + 'url': 'https://medius.microsoft.com/Embed/video-nc/81215af5-c813-4dcd-aede-94f4e1a7daa3', + 'info_dict': { + 'id': '81215af5-c813-4dcd-aede-94f4e1a7daa3', + 'ext': 'ismv', + 'title': 'Microsoft Build opening', + 'description': 'md5:43455096141077a1f23144cab8cec1cb', + 'thumbnail': r're:https://mediusimg\.event\.microsoft\.com/video-\d+/thumbnail\.jpg.*', + 'subtitles': 'count:31', + }, + }, { + 'url': 'https://medius.microsoft.com/Embed/VideoDetails/78493569-9b3b-4a85-a409-ee76e789e25c', + 'info_dict': { + 'id': '78493569-9b3b-4a85-a409-ee76e789e25c', + 'ext': 'ismv', + 'title': ' Anomaly Detection & Root cause at Edge', + 'description': 'md5:f8f1ad93d7918649bfb97fa081b03b83', + 'thumbnail': r're:https://mediusdownload.event.microsoft.com/asset.*\.jpg.*', + 'subtitles': 'count:17', + }, + }, { + 'url': 'https://medius.microsoft.com/Embed/Video?id=0dc69bda-079b-4070-a7db-a8da1a06a9c7', + 'only_matching': True, + }, { + 'url': 'https://medius.microsoft.com/Embed/video-nc/fe823a91-959c-465b-96d4-8f4db624f72c', + 'only_matching': True, + }] + + def _extract_subtitle(self, webpage, video_id): + captions = traverse_obj( + self._search_json(r'const\s+captionsConfiguration\s*=', webpage, 'captions', video_id, default=None), + ('languageList', lambda _, v: url_or_none(v['src']), { + 'url': 'src', + 'tag': ('srclang', {str}), + 'name': ('kind', {str}), + })) or [{'url': url, 'tag': url_basename(url).split('.vtt')[0].split('_')[-1]} + for url in re.findall(r'var\s+file\s+=\s+\{[^}]+\'(https://[^\']+\.vtt\?[^\']+)', webpage)] + + return self._sub_to_dict(captions) + + def _real_extract(self, url): + video_id = self._match_id(url) + webpage = self._download_webpage(f'https://medius.microsoft.com/Embed/video-nc/{video_id}', video_id) + + return { + 'id': video_id, + 'title': self._og_search_title(webpage), + 'description': self._og_search_description(webpage), + 'formats': self._extract_ism( + self._search_regex(r'StreamUrl\s*=\s*"([^"]+manifest)"', webpage, 'ism url'), video_id), + 'thumbnail': self._og_search_thumbnail(webpage), + 'subtitles': self._extract_subtitle(webpage, video_id), + } + + +class MicrosoftLearnPlaylistIE(InfoExtractor): + _VALID_URL = r'https?://learn\.microsoft\.com/(?:[\w-]+/)?(?Pshows|events)/(?P[\w-]+)/?(?:[?#]|$)' + _TESTS = [{ + 'url': 'https://learn.microsoft.com/en-us/shows/bash-for-beginners', + 'info_dict': { + 'id': 'bash-for-beginners', + 'title': 'Bash for Beginners', + 'description': 'md5:16a91c07222117d1e00912f0dbc02c2c', + }, + 'playlist_count': 20, + }, { + 'url': 'https://learn.microsoft.com/en-us/events/build-2022', + 'info_dict': { + 'id': 'build-2022', + 'title': 'Microsoft Build 2022 - Events', + 'description': 'md5:c16b43848027df837b22c6fbac7648d3', + }, + 'playlist_count': 201, + }] + + def _entries(self, url_base, video_id): + skip = 0 + while True: + playlist_info = self._download_json(url_base, video_id, f'Downloading entries {skip}', query={ + 'locale': 'en-us', + '$skip': skip, + }) + url_paths = traverse_obj(playlist_info, ('results', ..., 'url', {str})) + for url_path in url_paths: + yield self.url_result(f'https://learn.microsoft.com/en-us{url_path}') + skip += len(url_paths) + if skip >= playlist_info.get('count', 0) or not url_paths: + break + + def _real_extract(self, url): + playlist_id, playlist_type = self._match_valid_url(url).group('id', 'type') + webpage = self._download_webpage(url, playlist_id) + + metainfo = { + 'title': self._og_search_title(webpage), + 'description': self._og_search_description(webpage), + } + sub_type = 'episodes' if playlist_type == 'shows' else 'sessions' + + url_base = f'https://learn.microsoft.com/api/contentbrowser/search/{playlist_type}/{playlist_id}/{sub_type}' + return self.playlist_result(self._entries(url_base, playlist_id), playlist_id, **metainfo) + + +class MicrosoftLearnEpisodeIE(MicrosoftMediusBaseIE): + _VALID_URL = r'https?://learn\.microsoft\.com/(?:[\w-]+/)?shows/[\w-]+/(?P[^?#/]+)' + _TESTS = [{ + 'url': 'https://learn.microsoft.com/en-us/shows/bash-for-beginners/what-is-the-difference-between-a-terminal-and-a-shell-2-of-20-bash-for-beginners/', + 'info_dict': { + 'id': 'd44e1a03-a0e5-45c2-9496-5c9fa08dc94c', + 'ext': 'ismv', + 'title': 'What is the Difference Between a Terminal and a Shell? (Part 2 of 20)', + 'description': 'md5:7bbbfb593d21c2cf2babc3715ade6b88', + 'timestamp': 1676339547, + 'upload_date': '20230214', + 'thumbnail': r're:https://learn\.microsoft\.com/video/media/.*\.png', + 'subtitles': 'count:14', + }, + }] + + def _real_extract(self, url): + video_id = self._match_id(url) + webpage = self._download_webpage(url, video_id) + + entry_id = self._html_search_meta('entryId', webpage, 'entryId', fatal=True) + video_info = self._download_json( + f'https://learn.microsoft.com/api/video/public/v1/entries/{entry_id}', video_id) + return { + 'id': entry_id, + 'formats': self._extract_ism(video_info['publicVideo']['adaptiveVideoUrl'], video_id), + 'subtitles': self._sub_to_dict(traverse_obj(video_info, ( + 'publicVideo', 'captions', lambda _, v: url_or_none(v['url']), { + 'tag': ('language', {str}), + 'url': 'url', + }))), + 'title': self._og_search_title(webpage), + 'description': self._og_search_description(webpage), + **traverse_obj(video_info, { + 'timestamp': ('createTime', {parse_iso8601}), + 'thumbnails': ('publicVideo', 'thumbnailOtherSizes', ..., {'url': {url_or_none}}), + }), + } + + +class MicrosoftLearnSessionIE(InfoExtractor): + _VALID_URL = r'https?://learn\.microsoft\.com/(?:[\w-]+/)?events/[\w-]+/(?P[^?#/]+)' + _TESTS = [{ + 'url': 'https://learn.microsoft.com/en-us/events/build-2022/ts01-rapidly-code-test-ship-from-secure-cloud-developer-environments', + 'info_dict': { + 'id': '9640d86c-f513-4889-959e-5dace86e7d2b', + 'ext': 'ismv', + 'title': 'Rapidly code, test and ship from secure cloud developer environments - Events', + 'description': 'md5:f26c1a85d41c1cffd27a0279254a25c3', + 'timestamp': 1653408600, + 'upload_date': '20220524', + 'thumbnail': r're:https://mediusimg\.event\.microsoft\.com/video-\d+/thumbnail\.jpg.*', + }, + }] + + def _real_extract(self, url): + video_id = self._match_id(url) + webpage = self._download_webpage(url, video_id) + + metainfo = { + 'title': self._og_search_title(webpage), + 'description': self._og_search_description(webpage), + 'timestamp': parse_iso8601(self._html_search_meta('startDate', webpage, 'startDate')), + } + + return self.url_result( + self._html_search_meta('externalVideoUrl', webpage, 'videoUrl', fatal=True), + url_transparent=True, ie=MicrosoftMediusIE, **metainfo) + + +class MicrosoftBuildIE(InfoExtractor): + _VALID_URL = [ + r'https?://build\.microsoft\.com/[\w-]+/sessions/(?P[\da-f-]+)', + r'https?://build\.microsoft\.com/[\w-]+/(?Psessions)/?(?:[?#]|$)', + ] + + _TESTS = [{ + 'url': 'https://build.microsoft.com/en-US/sessions/b49feb31-afcd-4217-a538-d3ca1d171198?source=sessions', + 'info_dict': { + 'id': 'aee55fb5-fcf9-4b38-b764-a3527cb57554', + 'ext': 'ismv', + 'title': 'Microsoft Build opening keynote', + 'description': 'md5:d38338f336ef4b6ef9ad2a7466a76655', + 'timestamp': 1716307200, + 'upload_date': '20240521', + 'thumbnail': r're:https://mediusimg\.event\.microsoft\.com/video-\d+/thumbnail\.jpg.*', + }, + }, { + 'url': 'https://build.microsoft.com/en-US/sessions', + 'info_dict': { + 'id': 'sessions', + }, + 'playlist_mincount': 418, + }] + + def _real_extract(self, url): + video_id = self._match_id(url) + + entries = [ + self.url_result( + video_info['onDemand'], ie=MicrosoftMediusIE, url_transparent=True, **traverse_obj(video_info, { + 'id': ('sessionId', {str}), + 'title': ('title', {str}), + 'description': ('description', {str}), + 'timestamp': ('startDateTime', {parse_iso8601}), + })) + for video_info in self._download_json( + 'https://api-v2.build.microsoft.com/api/session/all/en-US', video_id, 'Downloading video info') + ] + if video_id == 'sessions': + return self.playlist_result(entries, video_id) + else: + return traverse_obj(entries, (lambda _, v: v['id'] == video_id), get_all=False) diff --git a/yt-dlp/yt_dlp/extractor/microsoftvirtualacademy.py b/yt-dlp/yt_dlp/extractor/microsoftvirtualacademy.py deleted file mode 100644 index e354d8a507..0000000000 --- a/yt-dlp/yt_dlp/extractor/microsoftvirtualacademy.py +++ /dev/null @@ -1,188 +0,0 @@ -import re - -from .common import InfoExtractor -from ..utils import ( - int_or_none, - parse_duration, - smuggle_url, - unsmuggle_url, - xpath_text, -) - - -class MicrosoftVirtualAcademyBaseIE(InfoExtractor): - def _extract_base_url(self, course_id, display_id): - return self._download_json( - f'https://api-mlxprod.microsoft.com/services/products/anonymous/{course_id}', - display_id, 'Downloading course base URL') - - def _extract_chapter_and_title(self, title): - if not title: - return None, None - m = re.search(r'(?P\d+)\s*\|\s*(?P.+)', title) - return (int(m.group('chapter')), m.group('title')) if m else (None, title) - - -class MicrosoftVirtualAcademyIE(MicrosoftVirtualAcademyBaseIE): - IE_NAME = 'mva' - IE_DESC = 'Microsoft Virtual Academy videos' - _VALID_URL = rf'(?:{IE_NAME}:|https?://(?:mva\.microsoft|(?:www\.)?microsoftvirtualacademy)\.com/[^/]+/training-courses/[^/?#&]+-)(?P<course_id>\d+)(?::|\?l=)(?P<id>[\da-zA-Z]+_\d+)' - - _TESTS = [{ - 'url': 'https://mva.microsoft.com/en-US/training-courses/microsoft-azure-fundamentals-virtual-machines-11788?l=gfVXISmEB_6804984382', - 'md5': '7826c44fc31678b12ad8db11f6b5abb9', - 'info_dict': { - 'id': 'gfVXISmEB_6804984382', - 'ext': 'mp4', - 'title': 'Course Introduction', - 'formats': 'mincount:3', - 'subtitles': { - 'en': [{ - 'ext': 'ttml', - }], - }, - }, - }, { - 'url': 'mva:11788:gfVXISmEB_6804984382', - 'only_matching': True, - }] - - def _real_extract(self, url): - url, smuggled_data = unsmuggle_url(url, {}) - - mobj = self._match_valid_url(url) - course_id = mobj.group('course_id') - video_id = mobj.group('id') - - base_url = smuggled_data.get('base_url') or self._extract_base_url(course_id, video_id) - - settings = self._download_xml( - f'{base_url}/content/content_{video_id}/videosettings.xml?v=1', - video_id, 'Downloading video settings XML') - - _, title = self._extract_chapter_and_title(xpath_text( - settings, './/Title', 'title', fatal=True)) - - formats = [] - - for sources in settings.findall('.//MediaSources'): - sources_type = sources.get('videoType') - for source in sources.findall('./MediaSource'): - video_url = source.text - if not video_url or not video_url.startswith('http'): - continue - if sources_type == 'smoothstreaming': - formats.extend(self._extract_ism_formats( - video_url, video_id, 'mss', fatal=False)) - continue - video_mode = source.get('videoMode') - height = int_or_none(self._search_regex( - r'^(\d+)[pP]$', video_mode or '', 'height', default=None)) - codec = source.get('codec') - acodec, vcodec = [None] * 2 - if codec: - codecs = codec.split(',') - if len(codecs) == 2: - acodec, vcodec = codecs - elif len(codecs) == 1: - vcodec = codecs[0] - formats.append({ - 'url': video_url, - 'format_id': video_mode, - 'height': height, - 'acodec': acodec, - 'vcodec': vcodec, - }) - - subtitles = {} - for source in settings.findall('.//MarkerResourceSource'): - subtitle_url = source.text - if not subtitle_url: - continue - subtitles.setdefault('en', []).append({ - 'url': f'{base_url}/{subtitle_url}', - 'ext': source.get('type'), - }) - - return { - 'id': video_id, - 'title': title, - 'subtitles': subtitles, - 'formats': formats, - } - - -class MicrosoftVirtualAcademyCourseIE(MicrosoftVirtualAcademyBaseIE): - IE_NAME = 'mva:course' - IE_DESC = 'Microsoft Virtual Academy courses' - _VALID_URL = rf'(?:{IE_NAME}:|https?://(?:mva\.microsoft|(?:www\.)?microsoftvirtualacademy)\.com/[^/]+/training-courses/(?P<display_id>[^/?#&]+)-)(?P<id>\d+)' - - _TESTS = [{ - 'url': 'https://mva.microsoft.com/en-US/training-courses/microsoft-azure-fundamentals-virtual-machines-11788', - 'info_dict': { - 'id': '11788', - 'title': 'Microsoft Azure Fundamentals: Virtual Machines', - }, - 'playlist_count': 36, - }, { - # with emphasized chapters - 'url': 'https://mva.microsoft.com/en-US/training-courses/developing-windows-10-games-with-construct-2-16335', - 'info_dict': { - 'id': '16335', - 'title': 'Developing Windows 10 Games with Construct 2', - }, - 'playlist_count': 10, - }, { - 'url': 'https://www.microsoftvirtualacademy.com/en-US/training-courses/microsoft-azure-fundamentals-virtual-machines-11788', - 'only_matching': True, - }, { - 'url': 'mva:course:11788', - 'only_matching': True, - }] - - @classmethod - def suitable(cls, url): - return False if MicrosoftVirtualAcademyIE.suitable(url) else super().suitable(url) - - def _real_extract(self, url): - mobj = self._match_valid_url(url) - course_id = mobj.group('id') - display_id = mobj.group('display_id') - - base_url = self._extract_base_url(course_id, display_id) - - manifest = self._download_json( - f'{base_url}/imsmanifestlite.json', - display_id, 'Downloading course manifest JSON')['manifest'] - - organization = manifest['organizations']['organization'][0] - - entries = [] - for chapter in organization['item']: - chapter_number, chapter_title = self._extract_chapter_and_title(chapter.get('title')) - chapter_id = chapter.get('@identifier') - for item in chapter.get('item', []): - item_id = item.get('@identifier') - if not item_id: - continue - metadata = item.get('resource', {}).get('metadata') or {} - if metadata.get('learningresourcetype') != 'Video': - continue - _, title = self._extract_chapter_and_title(item.get('title')) - duration = parse_duration(metadata.get('duration')) - description = metadata.get('description') - entries.append({ - '_type': 'url_transparent', - 'url': smuggle_url( - f'mva:{course_id}:{item_id}', {'base_url': base_url}), - 'title': title, - 'description': description, - 'duration': duration, - 'chapter': chapter_title, - 'chapter_number': chapter_number, - 'chapter_id': chapter_id, - }) - - title = organization.get('title') or manifest.get('metadata', {}).get('title') - - return self.playlist_result(entries, course_id, title) diff --git a/yt-dlp/yt_dlp/extractor/nuum.py b/yt-dlp/yt_dlp/extractor/nuum.py index 3db663ded0..697fc6b32e 100644 --- a/yt-dlp/yt_dlp/extractor/nuum.py +++ b/yt-dlp/yt_dlp/extractor/nuum.py @@ -43,15 +43,17 @@ class NuumBaseIE(InfoExtractor): is_live = media.get('media_status') == 'RUNNING' formats, subtitles = None, None + headers = {'Referer': 'https://nuum.ru/'} if extract_formats: formats, subtitles = self._extract_m3u8_formats_and_subtitles( - media_url, video_id, 'mp4', live=is_live) + media_url, video_id, 'mp4', live=is_live, headers=headers) return filter_dict({ 'id': video_id, 'is_live': is_live, 'formats': formats, 'subtitles': subtitles, + 'http_headers': headers, **traverse_obj(container, { 'title': ('media_container_name', {str}), 'description': ('media_container_description', {str}), @@ -78,7 +80,7 @@ class NuumMediaIE(NuumBaseIE): 'only_matching': True, }, { 'url': 'https://nuum.ru/videos/1567547-toxi-hurtz', - 'md5': 'f1d9118a30403e32b702a204eb03aca3', + 'md5': 'ce28837a5bbffe6952d7bfd3d39811b0', 'info_dict': { 'id': '1567547', 'ext': 'mp4', diff --git a/yt-dlp/yt_dlp/extractor/orf.py b/yt-dlp/yt_dlp/extractor/orf.py index f1403d9207..9c37a54d62 100644 --- a/yt-dlp/yt_dlp/extractor/orf.py +++ b/yt-dlp/yt_dlp/extractor/orf.py @@ -550,7 +550,8 @@ class ORFONIE(InfoExtractor): return self._extract_video_info(segment_id, selected_segment) # Even some segmented videos have an unsegmented version available in API response root - if not traverse_obj(api_json, ('sources', ..., ..., 'src', {url_or_none})): + if (self._configuration_arg('prefer_segments_playlist') + or not traverse_obj(api_json, ('sources', ..., ..., 'src', {url_or_none}))): return self.playlist_result( (self._extract_video_info(str(segment['id']), segment) for segment in segments), video_id, **self._parse_metadata(api_json), multi_video=True) diff --git a/yt-dlp/yt_dlp/extractor/pokergo.py b/yt-dlp/yt_dlp/extractor/pokergo.py index e22348053c..72cbce0a0c 100644 --- a/yt-dlp/yt_dlp/extractor/pokergo.py +++ b/yt-dlp/yt_dlp/extractor/pokergo.py @@ -5,6 +5,7 @@ from ..utils import ( ExtractorError, try_get, ) +from ..utils.traversal import traverse_obj class PokerGoBaseIE(InfoExtractor): @@ -65,7 +66,7 @@ class PokerGoIE(PokerGoBaseIE): 'width': image.get('width'), 'height': image.get('height'), } for image in data_json.get('images') or [] if image.get('url')] - series_json = next(dct for dct in data_json.get('show_tags') or [] if dct.get('video_id') == video_id) or {} + series_json = traverse_obj(data_json, ('show_tags', lambda _, v: v['video_id'] == video_id, any)) or {} return { '_type': 'url_transparent', diff --git a/yt-dlp/yt_dlp/extractor/qqmusic.py b/yt-dlp/yt_dlp/extractor/qqmusic.py index a57dd5fb35..d0238692f6 100644 --- a/yt-dlp/yt_dlp/extractor/qqmusic.py +++ b/yt-dlp/yt_dlp/extractor/qqmusic.py @@ -1,48 +1,125 @@ +import base64 +import functools +import json import random -import re import time from .common import InfoExtractor from ..utils import ( ExtractorError, + OnDemandPagedList, clean_html, + int_or_none, + join_nonempty, + js_to_json, + str_or_none, strip_jsonp, + traverse_obj, unescapeHTML, + url_or_none, + urljoin, ) -class QQMusicIE(InfoExtractor): +class QQMusicBaseIE(InfoExtractor): + def _get_cookie(self, key, default=None): + return getattr(self._get_cookies('https://y.qq.com').get(key), 'value', default) + + def _get_g_tk(self): + n = 5381 + for c in self._get_cookie('qqmusic_key', ''): + n += (n << 5) + ord(c) + return n & 2147483647 + + def _get_uin(self): + return int_or_none(self._get_cookie('uin')) or 0 + + @property + def is_logged_in(self): + return bool(self._get_uin() and self._get_cookie('fqm_pvqid')) + + # Reference: m_r_GetRUin() in top_player.js + # http://imgcache.gtimg.cn/music/portal_v3/y/top_player.js + @staticmethod + def _m_r_get_ruin(): + cur_ms = int(time.time() * 1000) % 1000 + return int(round(random.random() * 2147483647) * cur_ms % 1E10) + + def _download_init_data(self, url, mid, fatal=True): + webpage = self._download_webpage(url, mid, fatal=fatal) + return self._search_json(r'window\.__INITIAL_DATA__\s*=', webpage, + 'init data', mid, transform_source=js_to_json, fatal=fatal) + + def _make_fcu_req(self, req_dict, mid, headers={}, **kwargs): + return self._download_json( + 'https://u.y.qq.com/cgi-bin/musicu.fcg', mid, data=json.dumps({ + 'comm': { + 'cv': 0, + 'ct': 24, + 'format': 'json', + 'uin': self._get_uin(), + }, + **req_dict, + }, separators=(',', ':')).encode(), headers=headers, **kwargs) + + +class QQMusicIE(QQMusicBaseIE): IE_NAME = 'qqmusic' IE_DESC = 'QQ音乐' - _VALID_URL = r'https?://y\.qq\.com/n/yqq/song/(?P<id>[0-9A-Za-z]+)\.html' + _VALID_URL = r'https?://y\.qq\.com/n/ryqq/songDetail/(?P<id>[0-9A-Za-z]+)' _TESTS = [{ - 'url': 'https://y.qq.com/n/yqq/song/004295Et37taLD.html', + 'url': 'https://y.qq.com/n/ryqq/songDetail/004Ti8rT003TaZ', + 'md5': 'd7adc5c438d12e2cb648cca81593fd47', + 'info_dict': { + 'id': '004Ti8rT003TaZ', + 'ext': 'mp3', + 'title': '永夜のパレード (永夜的游行)', + 'album': '幻想遊園郷 -Fantastic Park-', + 'release_date': '20111230', + 'duration': 281, + 'creators': ['ケーキ姫', 'JUMA'], + 'genres': ['Pop'], + 'description': 'md5:b5261f3d595657ae561e9e6aee7eb7d9', + 'size': 4501244, + 'thumbnail': r're:^https?://.*\.jpg(?:$|[#?])', + 'subtitles': 'count:1', + }, + }, { + 'url': 'https://y.qq.com/n/ryqq/songDetail/004295Et37taLD', 'md5': '5f1e6cea39e182857da7ffc5ef5e6bb8', 'info_dict': { 'id': '004295Et37taLD', 'ext': 'mp3', 'title': '可惜没如果', - 'release_date': '20141227', - 'creator': '林俊杰', - 'description': 'md5:d85afb3051952ecc50a1ee8a286d1eac', - 'thumbnail': r're:^https?://.*\.jpg$', + 'album': '新地球 - 人 (Special Edition)', + 'release_date': '20150129', + 'duration': 298, + 'creators': ['林俊杰'], + 'genres': ['Pop'], + 'description': 'md5:f568421ff618d2066e74b65a04149c4e', + 'thumbnail': r're:^https?://.*\.jpg(?:$|[#?])', }, + 'skip': 'premium member only', }, { 'note': 'There is no mp3-320 version of this song.', - 'url': 'https://y.qq.com/n/yqq/song/004MsGEo3DdNxV.html', - 'md5': 'fa3926f0c585cda0af8fa4f796482e3e', + 'url': 'https://y.qq.com/n/ryqq/songDetail/004MsGEo3DdNxV', + 'md5': '028aaef1ae13d8a9f4861a92614887f9', 'info_dict': { 'id': '004MsGEo3DdNxV', 'ext': 'mp3', 'title': '如果', + 'album': '新传媒电视连续剧金曲系列II', 'release_date': '20050626', - 'creator': '李季美', - 'description': 'md5:46857d5ed62bc4ba84607a805dccf437', - 'thumbnail': r're:^https?://.*\.jpg$', + 'duration': 220, + 'creators': ['李季美'], + 'genres': [], + 'description': 'md5:fc711212aa623b28534954dc4bd67385', + 'size': 3535730, + 'thumbnail': r're:^https?://.*\.jpg(?:$|[#?])', }, }, { 'note': 'lyrics not in .lrc format', - 'url': 'https://y.qq.com/n/yqq/song/001JyApY11tIp6.html', + 'url': 'https://y.qq.com/n/ryqq/songDetail/001JyApY11tIp6', 'info_dict': { 'id': '001JyApY11tIp6', 'ext': 'mp3', @@ -50,185 +127,193 @@ class QQMusicIE(InfoExtractor): 'release_date': '19970225', 'creator': 'Dark Funeral', 'description': 'md5:c9b20210587cbcd6836a1c597bab4525', - 'thumbnail': r're:^https?://.*\.jpg$', - }, - 'params': { - 'skip_download': True, + 'thumbnail': r're:^https?://.*\.jpg(?:$|[#?])', }, + 'params': {'skip_download': True}, + 'skip': 'no longer available', }] _FORMATS = { - 'mp3-320': {'prefix': 'M800', 'ext': 'mp3', 'preference': 40, 'abr': 320}, - 'mp3-128': {'prefix': 'M500', 'ext': 'mp3', 'preference': 30, 'abr': 128}, - 'm4a': {'prefix': 'C200', 'ext': 'm4a', 'preference': 10}, + 'F000': {'name': 'flac', 'prefix': 'F000', 'ext': 'flac', 'preference': 60}, + 'A000': {'name': 'ape', 'prefix': 'A000', 'ext': 'ape', 'preference': 50}, + 'M800': {'name': '320mp3', 'prefix': 'M800', 'ext': 'mp3', 'preference': 40, 'abr': 320}, + 'M500': {'name': '128mp3', 'prefix': 'M500', 'ext': 'mp3', 'preference': 30, 'abr': 128}, + 'C400': {'name': '96aac', 'prefix': 'C400', 'ext': 'm4a', 'preference': 20, 'abr': 96}, + 'C200': {'name': '48aac', 'prefix': 'C200', 'ext': 'm4a', 'preference': 20, 'abr': 48}, } - # Reference: m_r_GetRUin() in top_player.js - # http://imgcache.gtimg.cn/music/portal_v3/y/top_player.js - @staticmethod - def m_r_get_ruin(): - cur_ms = int(time.time() * 1000) % 1000 - return int(round(random.random() * 2147483647) * cur_ms % 1E10) - def _real_extract(self, url): mid = self._match_id(url) - detail_info_page = self._download_webpage( - f'http://s.plcloud.music.qq.com/fcgi-bin/fcg_yqq_song_detail_info.fcg?songmid={mid}&play=0', - mid, note='Download song detail info', - errnote='Unable to get song detail info', encoding='gbk') + init_data = self._download_init_data(url, mid, fatal=False) + info_data = self._make_fcu_req({'info': { + 'module': 'music.pf_song_detail_svr', + 'method': 'get_song_detail_yqq', + 'param': { + 'song_mid': mid, + 'song_type': 0, + }, + }}, mid, note='Downloading song info')['info']['data']['track_info'] - song_name = self._html_search_regex( - r"songname:\s*'([^']+)'", detail_info_page, 'song name') + media_mid = info_data['file']['media_mid'] - publish_time = self._html_search_regex( - r'发行时间:(\d{4}-\d{2}-\d{2})', detail_info_page, - 'publish time', default=None) - if publish_time: - publish_time = publish_time.replace('-', '') - - singer = self._html_search_regex( - r"singer:\s*'([^']+)", detail_info_page, 'singer', default=None) - - lrc_content = self._html_search_regex( - r'<div class="content" id="lrc_content"[^<>]*>([^<>]+)</div>', - detail_info_page, 'LRC lyrics', default=None) - if lrc_content: - lrc_content = lrc_content.replace('\\n', '\n') - - thumbnail_url = None - albummid = self._search_regex( - [r'albummid:\'([0-9a-zA-Z]+)\'', r'"albummid":"([0-9a-zA-Z]+)"'], - detail_info_page, 'album mid', default=None) - if albummid: - thumbnail_url = f'http://i.gtimg.cn/music/photo/mid_album_500/{albummid[-2:-1]}/{albummid[-1]}/{albummid}.jpg' - - guid = self.m_r_get_ruin() - - vkey = self._download_json( - f'http://base.music.qq.com/fcgi-bin/fcg_musicexpress.fcg?json=3&guid={guid}', - mid, note='Retrieve vkey', errnote='Unable to get vkey', - transform_source=strip_jsonp)['key'] + data = self._make_fcu_req({ + 'req_1': { + 'module': 'vkey.GetVkeyServer', + 'method': 'CgiGetVkey', + 'param': { + 'guid': str(self._m_r_get_ruin()), + 'songmid': [mid] * len(self._FORMATS), + 'songtype': [0] * len(self._FORMATS), + 'uin': str(self._get_uin()), + 'loginflag': 1, + 'platform': '20', + 'filename': [f'{f["prefix"]}{media_mid}.{f["ext"]}' for f in self._FORMATS.values()], + }, + }, + 'req_2': { + 'module': 'music.musichallSong.PlayLyricInfo', + 'method': 'GetPlayLyricInfo', + 'param': {'songMID': mid}, + }, + }, mid, note='Downloading formats and lyric', headers=self.geo_verification_headers()) + code = traverse_obj(data, ('req_1', 'code', {int})) + if code != 0: + raise ExtractorError(f'Failed to download format info, error code {code or "unknown"}') formats = [] - for format_id, details in self._FORMATS.items(): + for media_info in traverse_obj(data, ( + 'req_1', 'data', 'midurlinfo', lambda _, v: v['songmid'] == mid and v['purl']), + ): + format_key = traverse_obj(media_info, ('filename', {str}, {lambda x: x[:4]})) + format_info = self._FORMATS.get(format_key) or {} + format_id = format_info.get('name') formats.append({ - 'url': 'http://cc.stream.qqmusic.qq.com/{}{}.{}?vkey={}&guid={}&fromtag=0'.format( - details['prefix'], mid, details['ext'], vkey, guid), + 'url': urljoin('https://dl.stream.qqmusic.qq.com', media_info['purl']), 'format': format_id, 'format_id': format_id, - 'quality': details['preference'], - 'abr': details.get('abr'), + 'size': traverse_obj(info_data, ('file', f'size_{format_id}', {int_or_none})), + 'quality': format_info.get('preference'), + 'abr': format_info.get('abr'), + 'ext': format_info.get('ext'), + 'vcodec': 'none', }) - self._check_formats(formats, mid) - actual_lrc_lyrics = ''.join( - line + '\n' for line in re.findall( - r'(?m)^(\[[0-9]{2}:[0-9]{2}(?:\.[0-9]{2,})?\][^\n]*|\[[^\]]*\])', lrc_content)) + if not formats and not self.is_logged_in: + self.raise_login_required() + + if traverse_obj(data, ('req_2', 'code')): + self.report_warning(f'Failed to download lyric, error {data["req_2"]["code"]!r}') + lrc_content = traverse_obj(data, ('req_2', 'data', 'lyric', {lambda x: base64.b64decode(x).decode('utf-8')})) info_dict = { 'id': mid, 'formats': formats, - 'title': song_name, - 'release_date': publish_time, - 'creator': singer, - 'description': lrc_content, - 'thumbnail': thumbnail_url, + **traverse_obj(info_data, { + 'title': ('title', {str}), + 'album': ('album', 'title', {str}, {lambda x: x or None}), + 'release_date': ('time_public', {lambda x: x.replace('-', '') or None}), + 'creators': ('singer', ..., 'name', {str}), + 'alt_title': ('subtitle', {str}, {lambda x: x or None}), + 'duration': ('interval', {int_or_none}), + }), + **traverse_obj(init_data, ('detail', { + 'thumbnail': ('picurl', {url_or_none}), + 'description': ('info', 'intro', 'content', ..., 'value', {str}), + 'genres': ('info', 'genre', 'content', ..., 'value', {str}, all), + }), get_all=False), } - if actual_lrc_lyrics: - info_dict['subtitles'] = { - 'origin': [{ - 'ext': 'lrc', - 'data': actual_lrc_lyrics, - }], - } + if lrc_content: + info_dict['subtitles'] = {'origin': [{'ext': 'lrc', 'data': lrc_content}]} + info_dict['description'] = join_nonempty(info_dict.get('description'), lrc_content, delim='\n') return info_dict -class QQPlaylistBaseIE(InfoExtractor): - @staticmethod - def qq_static_url(category, mid): - return f'http://y.qq.com/y/static/{category}/{mid[-2]}/{mid[-1]}/{mid}.html' - - def get_singer_all_songs(self, singmid, num): - return self._download_webpage( - r'https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg', singmid, - query={ - 'format': 'json', - 'inCharset': 'utf8', - 'outCharset': 'utf-8', - 'platform': 'yqq', - 'needNewCode': 0, - 'singermid': singmid, - 'order': 'listen', - 'begin': 0, - 'num': num, - 'songstatus': 1, - }) - - def get_entries_from_page(self, singmid): - entries = [] - - default_num = 1 - json_text = self.get_singer_all_songs(singmid, default_num) - json_obj_all_songs = self._parse_json(json_text, singmid) - - if json_obj_all_songs['code'] == 0: - total = json_obj_all_songs['data']['total'] - json_text = self.get_singer_all_songs(singmid, total) - json_obj_all_songs = self._parse_json(json_text, singmid) - - for item in json_obj_all_songs['data']['list']: - if item['musicData'].get('songmid') is not None: - songmid = item['musicData']['songmid'] - entries.append(self.url_result( - rf'https://y.qq.com/n/yqq/song/{songmid}.html', 'QQMusic', songmid)) - - return entries - - -class QQMusicSingerIE(QQPlaylistBaseIE): +class QQMusicSingerIE(QQMusicBaseIE): IE_NAME = 'qqmusic:singer' IE_DESC = 'QQ音乐 - 歌手' - _VALID_URL = r'https?://y\.qq\.com/n/yqq/singer/(?P<id>[0-9A-Za-z]+)\.html' - _TEST = { - 'url': 'https://y.qq.com/n/yqq/singer/001BLpXF2DyJe2.html', + _VALID_URL = r'https?://y\.qq\.com/n/ryqq/singer/(?P<id>[0-9A-Za-z]+)' + _TESTS = [{ + 'url': 'https://y.qq.com/n/ryqq/singer/001BLpXF2DyJe2', 'info_dict': { 'id': '001BLpXF2DyJe2', 'title': '林俊杰', - 'description': 'md5:870ec08f7d8547c29c93010899103751', + 'description': 'md5:10624ce73b06fa400bc846f59b0305fa', + 'thumbnail': r're:^https?://.*\.jpg(?:$|[#?])', }, - 'playlist_mincount': 12, - } + 'playlist_mincount': 100, + }, { + 'url': 'https://y.qq.com/n/ryqq/singer/000Q00f213YzNV', + 'info_dict': { + 'id': '000Q00f213YzNV', + 'title': '桃几OvO', + 'description': '小破站小唱见~希望大家喜欢听我唱歌~!', + 'thumbnail': r're:^https?://.*\.jpg(?:$|[#?])', + }, + 'playlist_count': 12, + 'playlist': [{ + 'info_dict': { + 'id': '0016cvsy02mmCl', + 'ext': 'mp3', + 'title': '群青', + 'album': '桃几2021年翻唱集', + 'release_date': '20210913', + 'duration': 248, + 'creators': ['桃几OvO'], + 'genres': ['Pop'], + 'description': 'md5:4296005a04edcb5cdbe0889d5055a7ae', + 'size': 3970822, + 'thumbnail': r're:^https?://.*\.jpg(?:$|[#?])', + }, + }], + }] + + _PAGE_SIZE = 50 + + def _fetch_page(self, mid, page_size, page_num): + data = self._make_fcu_req({'req_1': { + 'module': 'music.web_singer_info_svr', + 'method': 'get_singer_detail_info', + 'param': { + 'sort': 5, + 'singermid': mid, + 'sin': page_num * page_size, + 'num': page_size, + }}}, mid, note=f'Downloading page {page_num}') + yield from traverse_obj(data, ('req_1', 'data', 'songlist', ..., {lambda x: self.url_result( + f'https://y.qq.com/n/ryqq/songDetail/{x["mid"]}', QQMusicIE, x['mid'], x.get('title'))})) def _real_extract(self, url): mid = self._match_id(url) + init_data = self._download_init_data(url, mid, fatal=False) - entries = self.get_entries_from_page(mid) - singer_page = self._download_webpage(url, mid, 'Download singer page') - singer_name = self._html_search_regex( - r"singername\s*:\s*'(.*?)'", singer_page, 'singer name', default=None) - singer_desc = None + return self.playlist_result( + OnDemandPagedList(functools.partial(self._fetch_page, mid, self._PAGE_SIZE), self._PAGE_SIZE), + mid, **traverse_obj(init_data, ('singerDetail', { + 'title': ('basic_info', 'name', {str}), + 'description': ('ex_info', 'desc', {str}), + 'thumbnail': ('pic', 'pic', {url_or_none}), + }))) - if mid: - singer_desc_page = self._download_xml( - 'http://s.plcloud.music.qq.com/fcgi-bin/fcg_get_singer_desc.fcg', mid, - 'Donwload singer description XML', - query={'utf8': 1, 'outCharset': 'utf-8', 'format': 'xml', 'singermid': mid}, - headers={'Referer': 'https://y.qq.com/n/yqq/singer/'}) - singer_desc = singer_desc_page.find('./data/info/desc').text - - return self.playlist_result(entries, mid, singer_name, singer_desc) +class QQPlaylistBaseIE(InfoExtractor): + def _extract_entries(self, info_json, path): + for song in traverse_obj(info_json, path): + song_mid = song.get('songmid') + if not song_mid: + continue + yield self.url_result( + f'https://y.qq.com/n/ryqq/songDetail/{song_mid}', + QQMusicIE, song_mid, song.get('songname')) class QQMusicAlbumIE(QQPlaylistBaseIE): IE_NAME = 'qqmusic:album' IE_DESC = 'QQ音乐 - 专辑' - _VALID_URL = r'https?://y\.qq\.com/n/yqq/album/(?P<id>[0-9A-Za-z]+)\.html' + _VALID_URL = r'https?://y\.qq\.com/n/ryqq/albumDetail/(?P<id>[0-9A-Za-z]+)' _TESTS = [{ - 'url': 'https://y.qq.com/n/yqq/album/000gXCTb2AhRR1.html', + 'url': 'https://y.qq.com/n/ryqq/albumDetail/000gXCTb2AhRR1', 'info_dict': { 'id': '000gXCTb2AhRR1', 'title': '我们都是这样长大的', @@ -236,10 +321,10 @@ class QQMusicAlbumIE(QQPlaylistBaseIE): }, 'playlist_count': 4, }, { - 'url': 'https://y.qq.com/n/yqq/album/002Y5a3b3AlCu3.html', + 'url': 'https://y.qq.com/n/ryqq/albumDetail/002Y5a3b3AlCu3', 'info_dict': { 'id': '002Y5a3b3AlCu3', - 'title': '그리고...', + 'title': '그리고…', 'description': 'md5:a48823755615508a95080e81b51ba729', }, 'playlist_count': 8, @@ -248,49 +333,45 @@ class QQMusicAlbumIE(QQPlaylistBaseIE): def _real_extract(self, url): mid = self._match_id(url) - album = self._download_json( - f'http://i.y.qq.com/v8/fcg-bin/fcg_v8_album_info_cp.fcg?albummid={mid}&format=json', - mid, 'Download album page')['data'] + album_json = self._download_json( + 'http://i.y.qq.com/v8/fcg-bin/fcg_v8_album_info_cp.fcg', + mid, 'Download album page', + query={'albummid': mid, 'format': 'json'})['data'] - entries = [ - self.url_result( - 'https://y.qq.com/n/yqq/song/' + song['songmid'] + '.html', 'QQMusic', song['songmid'], - ) for song in album['list'] - ] - album_name = album.get('name') - album_detail = album.get('desc') - if album_detail is not None: - album_detail = album_detail.strip() + entries = self._extract_entries(album_json, ('list', ...)) - return self.playlist_result(entries, mid, album_name, album_detail) + return self.playlist_result(entries, mid, **traverse_obj(album_json, { + 'title': ('name', {str}), + 'description': ('desc', {str.strip}), + })) class QQMusicToplistIE(QQPlaylistBaseIE): IE_NAME = 'qqmusic:toplist' IE_DESC = 'QQ音乐 - 排行榜' - _VALID_URL = r'https?://y\.qq\.com/n/yqq/toplist/(?P<id>[0-9]+)\.html' + _VALID_URL = r'https?://y\.qq\.com/n/ryqq/toplist/(?P<id>[0-9]+)' _TESTS = [{ - 'url': 'https://y.qq.com/n/yqq/toplist/123.html', + 'url': 'https://y.qq.com/n/ryqq/toplist/123', 'info_dict': { 'id': '123', - 'title': '美国iTunes榜', - 'description': 'md5:89db2335fdbb10678dee2d43fe9aba08', + 'title': r're:美国热门音乐榜 \d{4}-\d{2}-\d{2}', + 'description': '美国热门音乐榜,每周一更新。', }, - 'playlist_count': 100, + 'playlist_count': 95, }, { - 'url': 'https://y.qq.com/n/yqq/toplist/3.html', + 'url': 'https://y.qq.com/n/ryqq/toplist/3', 'info_dict': { 'id': '3', - 'title': '巅峰榜·欧美', - 'description': 'md5:5a600d42c01696b26b71f8c4d43407da', + 'title': r're:巅峰榜·欧美 \d{4}-\d{2}-\d{2}', + 'description': 'md5:4def03b60d3644be4c9a36f21fd33857', }, 'playlist_count': 100, }, { - 'url': 'https://y.qq.com/n/yqq/toplist/106.html', + 'url': 'https://y.qq.com/n/ryqq/toplist/106', 'info_dict': { 'id': '106', - 'title': '韩国Mnet榜', + 'title': r're:韩国Mnet榜 \d{4}-\d{2}-\d{2}', 'description': 'md5:cb84b325215e1d21708c615cac82a6e7', }, 'playlist_count': 50, @@ -304,33 +385,20 @@ class QQMusicToplistIE(QQPlaylistBaseIE): note='Download toplist page', query={'type': 'toplist', 'topid': list_id, 'format': 'json'}) - entries = [self.url_result( - 'https://y.qq.com/n/yqq/song/' + song['data']['songmid'] + '.html', 'QQMusic', - song['data']['songmid']) - for song in toplist_json['songlist']] - - topinfo = toplist_json.get('topinfo', {}) - list_name = topinfo.get('ListName') - list_description = topinfo.get('info') - return self.playlist_result(entries, list_id, list_name, list_description) + return self.playlist_result( + self._extract_entries(toplist_json, ('songlist', ..., 'data')), list_id, + playlist_title=join_nonempty(*traverse_obj( + toplist_json, ((('topinfo', 'ListName'), 'update_time'), None)), delim=' '), + playlist_description=traverse_obj(toplist_json, ('topinfo', 'info'))) class QQMusicPlaylistIE(QQPlaylistBaseIE): IE_NAME = 'qqmusic:playlist' IE_DESC = 'QQ音乐 - 歌单' - _VALID_URL = r'https?://y\.qq\.com/n/yqq/playlist/(?P<id>[0-9]+)\.html' + _VALID_URL = r'https?://y\.qq\.com/n/ryqq/playlist/(?P<id>[0-9]+)' _TESTS = [{ - 'url': 'http://y.qq.com/n/yqq/playlist/3462654915.html', - 'info_dict': { - 'id': '3462654915', - 'title': '韩国5月新歌精选下旬', - 'description': 'md5:d2c9d758a96b9888cf4fe82f603121d4', - }, - 'playlist_count': 40, - 'skip': 'playlist gone', - }, { - 'url': 'https://y.qq.com/n/yqq/playlist/1374105607.html', + 'url': 'https://y.qq.com/n/ryqq/playlist/1374105607', 'info_dict': { 'id': '1374105607', 'title': '易入人心的华语民谣', @@ -346,19 +414,83 @@ class QQMusicPlaylistIE(QQPlaylistBaseIE): 'http://i.y.qq.com/qzone-music/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg', list_id, 'Download list page', query={'type': 1, 'json': 1, 'utf8': 1, 'onlysong': 0, 'disstid': list_id}, - transform_source=strip_jsonp) + transform_source=strip_jsonp, headers={'Referer': url}) if not len(list_json.get('cdlist', [])): - if list_json.get('code'): - raise ExtractorError( - 'QQ Music said: error %d in fetching playlist info' % list_json['code'], - expected=True) - raise ExtractorError('Unable to get playlist info') + raise ExtractorError(join_nonempty( + 'Unable to get playlist info', + join_nonempty('code', 'subcode', from_dict=list_json), + list_json.get('msg'), delim=': ')) - cdlist = list_json['cdlist'][0] - entries = [self.url_result( - 'https://y.qq.com/n/yqq/song/' + song['songmid'] + '.html', 'QQMusic', song['songmid']) - for song in cdlist['songlist']] + entries = self._extract_entries(list_json, ('cdlist', 0, 'songlist', ...)) - list_name = cdlist.get('dissname') - list_description = clean_html(unescapeHTML(cdlist.get('desc'))) - return self.playlist_result(entries, list_id, list_name, list_description) + return self.playlist_result(entries, list_id, **traverse_obj(list_json, ('cdlist', 0, { + 'title': ('dissname', {str}), + 'description': ('desc', {unescapeHTML}, {clean_html}), + }))) + + +class QQMusicVideoIE(QQMusicBaseIE): + IE_NAME = 'qqmusic:mv' + IE_DESC = 'QQ音乐 - MV' + _VALID_URL = r'https?://y\.qq\.com/n/ryqq/mv/(?P<id>[0-9A-Za-z]+)' + + _TESTS = [{ + 'url': 'https://y.qq.com/n/ryqq/mv/002Vsarh3SVU8K', + 'info_dict': { + 'id': '002Vsarh3SVU8K', + 'ext': 'mp4', + 'title': 'The Chant (Extended Mix / Audio)', + 'description': '', + 'thumbnail': r're:^https?://.*\.jpg(?:$|[#?])', + 'release_timestamp': 1688918400, + 'release_date': '20230709', + 'duration': 313, + 'creators': ['Duke Dumont'], + 'view_count': int, + }, + }] + + def _parse_url_formats(self, url_data): + return traverse_obj(url_data, ('mp4', lambda _, v: v['freeflow_url'], { + 'url': ('freeflow_url', 0, {url_or_none}), + 'filesize': ('fileSize', {int_or_none}), + 'format_id': ('newFileType', {str_or_none}), + })) + + def _real_extract(self, url): + video_id = self._match_id(url) + + video_info = self._make_fcu_req({ + 'mvInfo': { + 'module': 'music.video.VideoData', + 'method': 'get_video_info_batch', + 'param': { + 'vidlist': [video_id], + 'required': [ + 'vid', 'type', 'sid', 'cover_pic', 'duration', 'singers', + 'video_pay', 'hint', 'code', 'msg', 'name', 'desc', + 'playcnt', 'pubdate', 'play_forbid_reason'], + }, + }, + 'mvUrl': { + 'module': 'music.stream.MvUrlProxy', + 'method': 'GetMvUrls', + 'param': {'vids': [video_id]}, + }, + }, video_id, headers=self.geo_verification_headers()) + if traverse_obj(video_info, ('mvInfo', 'data', video_id, 'play_forbid_reason')) == 3: + self.raise_geo_restricted() + + return { + 'id': video_id, + 'formats': self._parse_url_formats(traverse_obj(video_info, ('mvUrl', 'data', video_id))), + **traverse_obj(video_info, ('mvInfo', 'data', video_id, { + 'title': ('name', {str}), + 'description': ('desc', {str}), + 'thumbnail': ('cover_pic', {url_or_none}), + 'release_timestamp': ('pubdate', {int_or_none}), + 'duration': ('duration', {int_or_none}), + 'creators': ('singers', ..., 'name', {str}), + 'view_count': ('playcnt', {int_or_none}), + })), + } diff --git a/yt-dlp/yt_dlp/extractor/youtube.py b/yt-dlp/yt_dlp/extractor/youtube.py index 7aa84aa8b5..094b1e9a36 100644 --- a/yt-dlp/yt_dlp/extractor/youtube.py +++ b/yt-dlp/yt_dlp/extractor/youtube.py @@ -468,7 +468,10 @@ class YoutubeBaseInfoExtractor(InfoExtractor): 'si', 'th', 'lo', 'my', 'ka', 'am', 'km', 'zh-CN', 'zh-TW', 'zh-HK', 'ja', 'ko', ] - _IGNORED_WARNINGS = {'Unavailable videos will be hidden during playback'} + _IGNORED_WARNINGS = { + 'Unavailable videos will be hidden during playback', + 'Unavailable videos are hidden', + } _YT_HANDLE_RE = r'@[\w.-]{3,30}' # https://support.google.com/youtube/answer/11585688?hl=en _YT_CHANNEL_UCID_RE = r'UC[\w-]{22}'