From 3ac37d71641c79ff4ea98c8c54227d50756bbc82 Mon Sep 17 00:00:00 2001
From: paulober <44974737+paulober@users.noreply.github.com>
Date: Thu, 19 Sep 2024 12:02:51 +0100
Subject: [PATCH 01/10] Add USB Ethernet Gadget toggle
Signed-off-by: paulober <44974737+paulober@users.noreply.github.com>
---
src/CMakeLists.txt | 5 +-
src/OptionsPopup.qml | 42 ++++++-
src/cli.cpp | 4 +-
.../zlib-1.3.1/{zconf.h => zconf.h.included} | 0
src/downloadthread.cpp | 22 +++-
src/downloadthread.h | 3 +-
src/extraFiles.qrc | 7 ++
src/extraFiles/10-usb.network | 33 +++++
.../configure-usb-ether-gadget-once.sh | 115 ++++++++++++++++++
src/extraFiles/usb-ether-gadget-once.service | 17 +++
src/imagewriter.cpp | 6 +-
src/imagewriter.h | 5 +-
12 files changed, 248 insertions(+), 11 deletions(-)
rename src/dependencies/zlib-1.3.1/{zconf.h => zconf.h.included} (100%)
create mode 100644 src/extraFiles.qrc
create mode 100644 src/extraFiles/10-usb.network
create mode 100644 src/extraFiles/configure-usb-ether-gadget-once.sh
create mode 100644 src/extraFiles/usb-ether-gadget-once.service
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a266380b2..3c0600959 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -278,7 +278,8 @@ set(SOURCES ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc ${QM_FILES})
if (WIN32)
# Adding WIN32 prevents a console window being opened on Windows
- add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${HEADERS} ${DEPENDENCIES})
+ add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${HEADERS} ${DEPENDENCIES}
+ extraFiles.qrc)
else()
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS} ${DEPENDENCIES})
endif()
@@ -495,4 +496,4 @@ else()
endif()
include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${LIBLZMA_INCLUDE_DIRS} ${LIBDRM_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${ZSTD_INCLUDE_DIR})
-target_link_libraries(${PROJECT_NAME} PRIVATE ${QT}::Core ${QT}::Quick ${QT}::Svg ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${ZSTD_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBLZMA_LIBRARIES} ${LIBDRM_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS})
\ No newline at end of file
+target_link_libraries(${PROJECT_NAME} PRIVATE ${QT}::Core ${QT}::Quick ${QT}::Svg ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${ZSTD_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBLZMA_LIBRARIES} ${LIBDRM_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS})
diff --git a/src/OptionsPopup.qml b/src/OptionsPopup.qml
index 88f5410da..b770e57b9 100644
--- a/src/OptionsPopup.qml
+++ b/src/OptionsPopup.qml
@@ -34,6 +34,7 @@ Window {
property string cloudinitrun
property string cloudinitwrite
property string cloudinitnetwork
+ property bool enableEtherGadget
signal saveSettingsSignal(var settings)
@@ -355,6 +356,11 @@ Window {
ColumnLayout {
// Remote access tab
+ ImCheckBox {
+ id: chkUSBEther
+ text: qsTr("Enable USB Ethernet Gadget")
+ }
+
ImCheckBox {
id: chkSSH
text: qsTr("Enable SSH")
@@ -826,6 +832,40 @@ Window {
addCmdline("cfg80211.ieee80211_regdom="+fieldWifiCountry.editText)
}
+ if (chkUSBEther.checked) {
+ addConfig("dtoverlay=dwc2,dr_mode=peripheral")
+ // only required if no conf is used to load modules
+ // g_ether must not be loaded when using manual config
+ // with sh script
+ addCmdline("modules-load=dwc2,g_ether")
+ // TODO: generate mac addresses if there are issues with DHCP
+ //addCmdline("g_ether.dev_addr=8A:89:6a:8d:14:22")
+ //addCmdline("g_ether.host_addr=6A:89:6a:8d:14:22")
+ addCmdline("g_ether.idVendor=0x04b3")
+ addCmdline("g_ether.idProduct=0x4010")
+ addCmdline("g_ether.iManufacturer=\"Raspberry Pi\"")
+ addCmdline("g_ether.bcdDevice=0x0100")
+ addCmdline("g_ether.iProduct=\"USB Ethernet Gadget\"")
+ // TODO: maybe set device serial
+ //addCmdline("g_ether.iSerialNumber=8c1aceb07269b131")
+
+ enableEtherGadget = true;
+
+ // manual config with this script requires not to load g_ether
+ //addFirstRun("mv /boot/firmware/etherSet.sh /usr/sbin/configure-usb-ether-gadget-once")
+ //addFirstRun("chmod +x /usr/sbin/configure-usb-ether-gadget-once")
+ //addFirstRun("mv /boot/firmware/sysdEth.srv /etc/systemd/system/usb-ether-gadget-once.service")
+ //addFirstRun("mkdir -p /etc/systemd/system/usb-gadget.target.wants")
+ //addFirstRun("ln -s /etc/systemd/system/usb-ether-gadget-once.service /etc/systemd/system/usb-gadget.target.wants/usb-ether-gadget-once.service")
+ addFirstRun("mv /boot/firmware/10usb.net /etc/systemd/network/10-usb.network\n")
+ // enable stuff
+ //addFirstRun("systemctl daemon-reload")
+ //addFirstRun("systemctl enable usb-ether-gadget-once.service")
+ //addFirstRun("systemctl start usb-ether-gadget-once.service\n")
+ // enable networkd as I don't have NetworkManager config
+ addFirstRun("systemctl enable systemd-networkd\n")
+ }
+
if (chkLocale.checked) {
var kbdconfig = "XKBMODEL=\"pc105\"\n"
kbdconfig += "XKBLAYOUT=\""+fieldKeyboardLayout.editText+"\"\n"
@@ -870,7 +910,7 @@ Window {
addCloudInit("runcmd:\n"+cloudinitrun+"\n")
}
- imageWriter.setImageCustomization(config, cmdline, firstrun, cloudinit, cloudinitnetwork)
+ imageWriter.setImageCustomization(config, cmdline, firstrun, cloudinit, cloudinitnetwork, enableEtherGadget)
}
function saveSettings()
diff --git a/src/cli.cpp b/src/cli.cpp
index ed5aa062e..bb0e88c19 100644
--- a/src/cli.cpp
+++ b/src/cli.cpp
@@ -186,7 +186,7 @@ int Cli::run()
return 1;
}
- _imageWriter->setImageCustomization("", "", "", userData, networkConfig);
+ _imageWriter->setImageCustomization("", "", "", userData, networkConfig, false);
}
else if (!parser.value("first-run-script").isEmpty())
{
@@ -208,7 +208,7 @@ int Cli::run()
return 1;
}
- _imageWriter->setImageCustomization("", "", firstRunScript, "", "");
+ _imageWriter->setImageCustomization("", "", firstRunScript, "", "", false);
}
_imageWriter->setDst(args[1]);
diff --git a/src/dependencies/zlib-1.3.1/zconf.h b/src/dependencies/zlib-1.3.1/zconf.h.included
similarity index 100%
rename from src/dependencies/zlib-1.3.1/zconf.h
rename to src/dependencies/zlib-1.3.1/zconf.h.included
diff --git a/src/downloadthread.cpp b/src/downloadthread.cpp
index 3db9c2384..4e488e609 100644
--- a/src/downloadthread.cpp
+++ b/src/downloadthread.cpp
@@ -885,7 +885,7 @@ qint64 DownloadThread::_sectorsWritten()
return -1;
}
-void DownloadThread::setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudInitNetwork, const QByteArray &initFormat)
+void DownloadThread::setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudInitNetwork, const QByteArray &initFormat, const bool enableEtherGadget)
{
_config = config;
_cmdline = cmdline;
@@ -893,6 +893,7 @@ void DownloadThread::setImageCustomization(const QByteArray &config, const QByte
_cloudinit = cloudinit;
_cloudinitNetwork = cloudInitNetwork;
_initFormat = initFormat;
+ _enableEtherGadget = enableEtherGadget;
}
bool DownloadThread::_customizeImage()
@@ -974,6 +975,25 @@ bool DownloadThread::_customizeImage()
_cmdline += " systemd.run=/boot/firstrun.sh systemd.run_success_action=reboot systemd.unit=kernel-command-line.target";
}
+ if (_enableEtherGadget) {
+ // load files from disk and write
+ QByteArray networkConfig = _fileGetContentsTrimmed("://extraFiles/10-usb.network");
+ fat->writeFile("10usb.net", networkConfig);
+ // little optimization for memory constraint systems - add if more files are loaded in this scope
+ //networkConfig.clear();
+
+ // only needed for manual config without g_ether
+ //QByteArray script = _fileGetContentsTrimmed("://extraFiles/configure-usb-ether-gadget-once.sh");
+ //fat->writeFile("etherSet.sh", script);
+ // little optimization for memory constraint systems - add if more files are loaded in this scope
+ //script.clear();
+
+ //QByteArray serviceFile = _fileGetContentsTrimmed("://extraFiles/usb-ether-gadget-once.service");
+ //fat->writeFile("sysdEth.srv", serviceFile);
+ // not needed anymore, because auto cleanup after out of scope
+ //serviceFile.clear();
+ }
+
if (!_cloudinit.isEmpty() && _initFormat == "cloudinit")
{
_cloudinit = "#cloud-config\n"+_cloudinit;
diff --git a/src/downloadthread.h b/src/downloadthread.h
index 3fb954255..a8f3483a7 100644
--- a/src/downloadthread.h
+++ b/src/downloadthread.h
@@ -116,7 +116,7 @@ class DownloadThread : public QThread
/*
* Enable image customization
*/
- void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const QByteArray &initFormat);
+ void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const QByteArray &initFormat, const bool enableEtherGadget);
/*
* Thread safe download progress query functions
@@ -171,6 +171,7 @@ class DownloadThread : public QThread
std::uint64_t _lastFailureOffset;
qint64 _sectorsStart;
QByteArray _url, _useragent, _buf, _filename, _lastError, _expectedHash, _config, _cmdline, _firstrun, _cloudinit, _cloudinitNetwork, _initFormat;
+ bool _enableEtherGadget;
char *_firstBlock;
size_t _firstBlockSize;
static QByteArray _proxy;
diff --git a/src/extraFiles.qrc b/src/extraFiles.qrc
new file mode 100644
index 000000000..df02268f7
--- /dev/null
+++ b/src/extraFiles.qrc
@@ -0,0 +1,7 @@
+
+
+ extraFiles/10-usb.network
+ extraFiles/configure-usb-ether-gadget-once.sh
+ extraFiles/usb-ether-gadget-once.service
+
+
diff --git a/src/extraFiles/10-usb.network b/src/extraFiles/10-usb.network
new file mode 100644
index 000000000..8223e446b
--- /dev/null
+++ b/src/extraFiles/10-usb.network
@@ -0,0 +1,33 @@
+[Match]
+Name=usb*
+
+[Link]
+RequiredForOnline=no
+
+[Network]
+# Configure Subnet for USB Ethernet Gadget
+# - IP Range: 10.12.194.1 to 10.12.194.14
+# - Total IPs: 16
+# - Usable IPs: 14
+# - Network Address: 10.12.194.0
+# - Broadcast Address: 10.12.194.15
+# - Subnet Mask: 255.255.255.240 (/28)
+# | 10 - private
+# | 12 - 2012 founding of Raspberry Pi Ltd.
+# | 194 - address of Raspberry Pi Ltd. in the Science Park, Cambridge
+# | 1 - first device
+# TODO: maybe only static hostname to not conflict when multiple devices are connected
+# to the same computer
+Address=10.12.194.1/28
+DHCPServer=yes
+
+[DHCPServer]
+# Configure DHCP settings
+PoolSize=16 # Number of IP addresses available for lease
+DefaultLeaseTimeSec=60 # Default lease time for DHCP clients
+MaxLeaseTimeSec=60 # Maximum lease time for DHCP clients
+
+# Network isolation settings (no internet)
+EmitDNS=no # Do not provide DNS information
+EmitNTP=no # Do not provide NTP information
+EmitRouter=no # Do not provide router information
diff --git a/src/extraFiles/configure-usb-ether-gadget-once.sh b/src/extraFiles/configure-usb-ether-gadget-once.sh
new file mode 100644
index 000000000..199c799dc
--- /dev/null
+++ b/src/extraFiles/configure-usb-ether-gadget-once.sh
@@ -0,0 +1,115 @@
+#!/bin/bash
+
+######################
+## Config variables ##
+######################
+# required for RNDIS (Windows compatibility)
+# Acer Incorporated. - Other hardware - Acer USB Ethernet/RNDIS Gadget
+# did not work correctly
+#VID="0x0502"
+#PID="0x3230"
+# Did work correctly with IBM driver
+VID="0x04b3"
+PID="0x4010"
+SERIAL=$(grep Serial /proc/cpuinfo | awk '{print $3}')
+# Compute the SHA256 hash of the serial number
+sha=$(echo -n "$SERIAL" | sha256sum | cut -d ' ' -f 1)
+config_path=g_ether
+##########################
+## END Config variables ##
+##########################
+
+###############################
+## Setup basic configuration ##
+###############################
+mkdir -p ${config_path}
+cd ${config_path} || exit 1
+
+echo "${VID}" > idVendor # Custom Vendor ID
+echo "${PID}" > idProduct # Custom Product ID
+echo 0x0100 > bcdDevice # v1.0.0
+echo 0x0200 > bcdUSB # USB2
+# setup appearance
+mkdir -p strings/0x409
+echo "${SERIAL}" > strings/0x409/serialnumber
+echo "Raspberry Pi" > strings/0x409/manufacturer
+echo "USB Ethernet Gadget" > strings/0x409/product
+###################################
+## END Setup basic configuration ##
+###################################
+
+####################################################
+## ECM (Ethernet Control Model) for Mac and Linux ##
+####################################################
+mkdir -p configs/c.1/strings/0x409
+mkdir -p functions/ecm.usb0
+
+# max possible stable USB 2.0 power
+echo 250 > configs/c.1/MaxPower
+echo "ECM" > configs/c.1/strings/0x409/configuration
+########################################################
+## END ECM (Ethernet Control Model) for Mac and Linux ##
+########################################################
+
+#####################################
+## RNDIS for Windows compatibility ##
+#####################################
+mkdir -p configs/c.2/strings/0x409
+mkdir -p functions/rndis.usb0
+# not allowed
+#mkdir -p os_desc/interface.rndis
+
+echo "RNDIS" > configs/c.2/strings/0x409/configuration
+#echo "RNDIS" > os_desc/interface.rndis/compatibility_id
+#echo "5162001" > os_desc/interface.rndis/sub_compatibility_id
+#########################################
+## END RNDIS for Windows compatibility ##
+#########################################
+
+#########################
+## Setup MAC addresses ##
+#########################
+# Generate MAC addresses using slices of the hash
+# TODO: maybe change prefix
+mac0=6A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2}
+mac1=7A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2}
+mac2=8A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2}
+mac3=9A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2}
+
+echo "${mac1}" > functions/ecm.usb0/host_addr
+echo "${mac3}" > functions/ecm.usb0/dev_addr
+
+echo "${mac0}" > functions/rndis.usb0/host_addr
+echo "${mac2}" > functions/rndis.usb0/dev_addr
+#############################
+## END Setup MAC addresses ##
+#############################
+
+######################################
+## Link functions to configurations ##
+######################################
+ln -s functions/ecm.usb0 configs/c.1/
+ln -s functions/rndis.usb0 configs/c.2/
+##########################################
+
+######################################
+## Link the UDC to start the gadget ##
+######################################
+count=0
+while [ ${count} -lt 15 ]; do
+ udc="$(ls /sys/class/udc)"
+ if [ -n "${udc}" ]; then
+ echo "Found UDC ${udc}"
+ echo "${udc}" > UDC
+ break
+ fi
+ count=$((count + 1))
+ sleep 1
+done
+##########################################
+## END Link the UDC to start the gadget ##
+##########################################
+
+systemctl restart getty@ttyGS0
+
+echo "Ethernet USB OTG gadget init complete - $(cat UDC)"
diff --git a/src/extraFiles/usb-ether-gadget-once.service b/src/extraFiles/usb-ether-gadget-once.service
new file mode 100644
index 000000000..941f4930a
--- /dev/null
+++ b/src/extraFiles/usb-ether-gadget-once.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=Configure USB Ethernet Gadget
+Requires=sys-kernel-config.mount
+After=sys-kernel-config.mount
+Requires=systemd-modules-load.service
+After=systemd-modules-load.service
+
+[Service]
+Type=oneshot
+WorkingDirectory=/sys/kernel/config/usb_gadget
+ExecStart=/usr/sbin/configure-usb-ether-gadget-once
+StandardOutput=journal+console
+# TODO: remove
+User=root
+
+[Install]
+WantedBy=usb-gadget.target
diff --git a/src/imagewriter.cpp b/src/imagewriter.cpp
index c538b0970..55bc39ff2 100644
--- a/src/imagewriter.cpp
+++ b/src/imagewriter.cpp
@@ -296,7 +296,7 @@ void ImageWriter::startWrite()
connect(_thread, SIGNAL(preparationStatusUpdate(QString)), SLOT(onPreparationStatusUpdate(QString)));
_thread->setVerifyEnabled(_verifyEnabled);
_thread->setUserAgent(QString("Mozilla/5.0 rpi-imager/%1").arg(constantVersion()).toUtf8());
- _thread->setImageCustomization(_config, _cmdline, _firstrun, _cloudinit, _cloudinitNetwork, _initFormat);
+ _thread->setImageCustomization(_config, _cmdline, _firstrun, _cloudinit, _cloudinitNetwork, _initFormat, _enableEtherGadget);
if (!_expectedHash.isEmpty() && _cachedFileHash != _expectedHash && _cachingEnabled)
{
@@ -1184,18 +1184,20 @@ void ImageWriter::setSetting(const QString &key, const QVariant &value)
_settings.sync();
}
-void ImageWriter::setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork)
+void ImageWriter::setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const bool enableEtherGadget)
{
_config = config;
_cmdline = cmdline;
_firstrun = firstrun;
_cloudinit = cloudinit;
_cloudinitNetwork = cloudinitNetwork;
+ _enableEtherGadget = enableEtherGadget;
qDebug() << "Custom config.txt entries:" << config;
qDebug() << "Custom cmdline.txt entries:" << cmdline;
qDebug() << "Custom firstuse.sh:" << firstrun;
qDebug() << "Cloudinit:" << cloudinit;
+ qDebug() << "Enable USB Ethernet gadget:" << enableEtherGadget;
}
QString ImageWriter::crypt(const QByteArray &password)
diff --git a/src/imagewriter.h b/src/imagewriter.h
index 843ed539b..166c241aa 100644
--- a/src/imagewriter.h
+++ b/src/imagewriter.h
@@ -122,8 +122,8 @@ class ImageWriter : public QObject
Q_INVOKABLE QString getPSK();
Q_INVOKABLE bool getBoolSetting(const QString &key);
- Q_INVOKABLE void setSetting(const QString &key, const QVariant &value);
- Q_INVOKABLE void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork);
+ Q_INVOKABLE void setSetting(const QString &key, const QVariant &value);//, const QVariantList
+ Q_INVOKABLE void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const bool enableEtherGadget);
Q_INVOKABLE void setSavedCustomizationSettings(const QVariantMap &map);
Q_INVOKABLE QVariantMap getSavedCustomizationSettings();
Q_INVOKABLE void clearSavedCustomizationSettings();
@@ -191,6 +191,7 @@ protected slots:
QUrl _src, _repo;
QString _dst, _cacheFileName, _parentCategory, _osName, _currentLang, _currentLangcode, _currentKeyboard;
QByteArray _expectedHash, _cachedFileHash, _cmdline, _config, _firstrun, _cloudinit, _cloudinitNetwork, _initFormat;
+ bool _enableEtherGadget;
quint64 _downloadLen, _extrLen, _devLen, _dlnow, _verifynow;
DriveListModel _drivelist;
QQmlApplicationEngine *_engine;
From a2223c1e9d90783d7f301a78b62570b6f7ab61c5 Mon Sep 17 00:00:00 2001
From: paulober <44974737+paulober@users.noreply.github.com>
Date: Thu, 19 Sep 2024 16:56:31 +0100
Subject: [PATCH 02/10] Implemented requested changes and switched to auto
g_ether
Signed-off-by: paulober <44974737+paulober@users.noreply.github.com>
---
src/CMakeLists.txt | 3 +-
src/OptionsPopup.qml | 45 +++----
src/downloadthread.cpp | 18 +--
src/extraFiles.qrc | 4 +-
.../configure-usb-ether-gadget-once.sh | 115 ------------------
src/extraFiles/g_ether.conf | 1 +
src/extraFiles/usb-ether-gadget-once.service | 17 ---
src/extraFiles/usb-ether-gadget.conf | 2 +
src/imagewriter.cpp | 15 ++-
src/imagewriter.h | 17 ++-
src/main.qml | 2 +-
11 files changed, 64 insertions(+), 175 deletions(-)
delete mode 100644 src/extraFiles/configure-usb-ether-gadget-once.sh
create mode 100644 src/extraFiles/g_ether.conf
delete mode 100644 src/extraFiles/usb-ether-gadget-once.service
create mode 100644 src/extraFiles/usb-ether-gadget.conf
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3c0600959..628d5a626 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -281,7 +281,8 @@ if (WIN32)
add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${HEADERS} ${DEPENDENCIES}
extraFiles.qrc)
else()
- add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS} ${DEPENDENCIES})
+ add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS} ${DEPENDENCIES}
+ extraFiles.qrc)
endif()
set_property(TARGET ${PROJECT_NAME} PROPERTY AUTOMOC ON)
diff --git a/src/OptionsPopup.qml b/src/OptionsPopup.qml
index b770e57b9..11fc379da 100644
--- a/src/OptionsPopup.qml
+++ b/src/OptionsPopup.qml
@@ -34,6 +34,7 @@ Window {
property string cloudinitrun
property string cloudinitwrite
property string cloudinitnetwork
+ property bool deviceUsbOtgSupport
property bool enableEtherGadget
signal saveSettingsSignal(var settings)
@@ -359,6 +360,7 @@ Window {
ImCheckBox {
id: chkUSBEther
text: qsTr("Enable USB Ethernet Gadget")
+ enabled: deviceUsbOtgSupport
}
ImCheckBox {
@@ -635,6 +637,18 @@ Window {
}
}
+ var hwFilterList = imageWriter.getHWFilterList()
+ var hwFilterIsModelZero = imageWriter.getHWFilterIsModelZero()
+
+ if (hwFilterList) {
+ var targetTags = ["pi5-64bit", "pi4-64bit", "pi5-32bit", "pi4-32bit"]
+ deviceUsbOtgSupport = targetTags.some(tag => hwFilterList.includes(tag)) || hwFilterIsModelZero
+ if (!deviceUsbOtgSupport) {
+ // make sure it isn't disabled and selected
+ chkUSBEther = false;
+ }
+ }
+
//open()
show()
raise()
@@ -834,35 +848,14 @@ Window {
}
if (chkUSBEther.checked) {
addConfig("dtoverlay=dwc2,dr_mode=peripheral")
- // only required if no conf is used to load modules
- // g_ether must not be loaded when using manual config
- // with sh script
- addCmdline("modules-load=dwc2,g_ether")
- // TODO: generate mac addresses if there are issues with DHCP
- //addCmdline("g_ether.dev_addr=8A:89:6a:8d:14:22")
- //addCmdline("g_ether.host_addr=6A:89:6a:8d:14:22")
- addCmdline("g_ether.idVendor=0x04b3")
- addCmdline("g_ether.idProduct=0x4010")
- addCmdline("g_ether.iManufacturer=\"Raspberry Pi\"")
- addCmdline("g_ether.bcdDevice=0x0100")
- addCmdline("g_ether.iProduct=\"USB Ethernet Gadget\"")
- // TODO: maybe set device serial
- //addCmdline("g_ether.iSerialNumber=8c1aceb07269b131")
enableEtherGadget = true;
- // manual config with this script requires not to load g_ether
- //addFirstRun("mv /boot/firmware/etherSet.sh /usr/sbin/configure-usb-ether-gadget-once")
- //addFirstRun("chmod +x /usr/sbin/configure-usb-ether-gadget-once")
- //addFirstRun("mv /boot/firmware/sysdEth.srv /etc/systemd/system/usb-ether-gadget-once.service")
- //addFirstRun("mkdir -p /etc/systemd/system/usb-gadget.target.wants")
- //addFirstRun("ln -s /etc/systemd/system/usb-ether-gadget-once.service /etc/systemd/system/usb-gadget.target.wants/usb-ether-gadget-once.service")
- addFirstRun("mv /boot/firmware/10usb.net /etc/systemd/network/10-usb.network\n")
- // enable stuff
- //addFirstRun("systemctl daemon-reload")
- //addFirstRun("systemctl enable usb-ether-gadget-once.service")
- //addFirstRun("systemctl start usb-ether-gadget-once.service\n")
- // enable networkd as I don't have NetworkManager config
+ addFirstRun("\nmv /boot/firmware/10usb.net /etc/systemd/network/10-usb.network")
+ addFirstRun("mv /boot/firmware/geth.cnf /etc/modprobe.d/g_ether.conf")
+ addFirstRun("mv /boot/firmware/gemod.cnf /etc/modules-load.d/usb-ether-gadget.conf\n")
+ addFirstRun("SERIAL=$(grep Serial /proc/cpuinfo | awk '{print $3}')")
+ addFirstRun("sed -i \"s//$SERIAL/g\" /etc/modprobe.d/g_ether.conf")
addFirstRun("systemctl enable systemd-networkd\n")
}
diff --git a/src/downloadthread.cpp b/src/downloadthread.cpp
index 4e488e609..ca64d5718 100644
--- a/src/downloadthread.cpp
+++ b/src/downloadthread.cpp
@@ -979,19 +979,19 @@ bool DownloadThread::_customizeImage()
// load files from disk and write
QByteArray networkConfig = _fileGetContentsTrimmed("://extraFiles/10-usb.network");
fat->writeFile("10usb.net", networkConfig);
- // little optimization for memory constraint systems - add if more files are loaded in this scope
- //networkConfig.clear();
+ // little optimization for memory constraint systems
+ networkConfig.clear();
// only needed for manual config without g_ether
- //QByteArray script = _fileGetContentsTrimmed("://extraFiles/configure-usb-ether-gadget-once.sh");
- //fat->writeFile("etherSet.sh", script);
- // little optimization for memory constraint systems - add if more files are loaded in this scope
- //script.clear();
+ QByteArray modprobeConf = _fileGetContentsTrimmed("://extraFiles/g_ether.conf");
+ fat->writeFile("geth.cnf", modprobeConf);
+ // little optimization for memory constraint systems
+ modprobeConf.clear();
- //QByteArray serviceFile = _fileGetContentsTrimmed("://extraFiles/usb-ether-gadget-once.service");
- //fat->writeFile("sysdEth.srv", serviceFile);
+ QByteArray modulesConf = _fileGetContentsTrimmed("://extraFiles/usb-ether-gadget.conf");
+ fat->writeFile("gemod.cnf", modulesConf);
// not needed anymore, because auto cleanup after out of scope
- //serviceFile.clear();
+ //modulesConf.clear();
}
if (!_cloudinit.isEmpty() && _initFormat == "cloudinit")
diff --git a/src/extraFiles.qrc b/src/extraFiles.qrc
index df02268f7..bf056b740 100644
--- a/src/extraFiles.qrc
+++ b/src/extraFiles.qrc
@@ -1,7 +1,7 @@
extraFiles/10-usb.network
- extraFiles/configure-usb-ether-gadget-once.sh
- extraFiles/usb-ether-gadget-once.service
+ extraFiles/g_ether.conf
+ extraFiles/usb-ether-gadget.conf
diff --git a/src/extraFiles/configure-usb-ether-gadget-once.sh b/src/extraFiles/configure-usb-ether-gadget-once.sh
deleted file mode 100644
index 199c799dc..000000000
--- a/src/extraFiles/configure-usb-ether-gadget-once.sh
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/bin/bash
-
-######################
-## Config variables ##
-######################
-# required for RNDIS (Windows compatibility)
-# Acer Incorporated. - Other hardware - Acer USB Ethernet/RNDIS Gadget
-# did not work correctly
-#VID="0x0502"
-#PID="0x3230"
-# Did work correctly with IBM driver
-VID="0x04b3"
-PID="0x4010"
-SERIAL=$(grep Serial /proc/cpuinfo | awk '{print $3}')
-# Compute the SHA256 hash of the serial number
-sha=$(echo -n "$SERIAL" | sha256sum | cut -d ' ' -f 1)
-config_path=g_ether
-##########################
-## END Config variables ##
-##########################
-
-###############################
-## Setup basic configuration ##
-###############################
-mkdir -p ${config_path}
-cd ${config_path} || exit 1
-
-echo "${VID}" > idVendor # Custom Vendor ID
-echo "${PID}" > idProduct # Custom Product ID
-echo 0x0100 > bcdDevice # v1.0.0
-echo 0x0200 > bcdUSB # USB2
-# setup appearance
-mkdir -p strings/0x409
-echo "${SERIAL}" > strings/0x409/serialnumber
-echo "Raspberry Pi" > strings/0x409/manufacturer
-echo "USB Ethernet Gadget" > strings/0x409/product
-###################################
-## END Setup basic configuration ##
-###################################
-
-####################################################
-## ECM (Ethernet Control Model) for Mac and Linux ##
-####################################################
-mkdir -p configs/c.1/strings/0x409
-mkdir -p functions/ecm.usb0
-
-# max possible stable USB 2.0 power
-echo 250 > configs/c.1/MaxPower
-echo "ECM" > configs/c.1/strings/0x409/configuration
-########################################################
-## END ECM (Ethernet Control Model) for Mac and Linux ##
-########################################################
-
-#####################################
-## RNDIS for Windows compatibility ##
-#####################################
-mkdir -p configs/c.2/strings/0x409
-mkdir -p functions/rndis.usb0
-# not allowed
-#mkdir -p os_desc/interface.rndis
-
-echo "RNDIS" > configs/c.2/strings/0x409/configuration
-#echo "RNDIS" > os_desc/interface.rndis/compatibility_id
-#echo "5162001" > os_desc/interface.rndis/sub_compatibility_id
-#########################################
-## END RNDIS for Windows compatibility ##
-#########################################
-
-#########################
-## Setup MAC addresses ##
-#########################
-# Generate MAC addresses using slices of the hash
-# TODO: maybe change prefix
-mac0=6A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2}
-mac1=7A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2}
-mac2=8A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2}
-mac3=9A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2}
-
-echo "${mac1}" > functions/ecm.usb0/host_addr
-echo "${mac3}" > functions/ecm.usb0/dev_addr
-
-echo "${mac0}" > functions/rndis.usb0/host_addr
-echo "${mac2}" > functions/rndis.usb0/dev_addr
-#############################
-## END Setup MAC addresses ##
-#############################
-
-######################################
-## Link functions to configurations ##
-######################################
-ln -s functions/ecm.usb0 configs/c.1/
-ln -s functions/rndis.usb0 configs/c.2/
-##########################################
-
-######################################
-## Link the UDC to start the gadget ##
-######################################
-count=0
-while [ ${count} -lt 15 ]; do
- udc="$(ls /sys/class/udc)"
- if [ -n "${udc}" ]; then
- echo "Found UDC ${udc}"
- echo "${udc}" > UDC
- break
- fi
- count=$((count + 1))
- sleep 1
-done
-##########################################
-## END Link the UDC to start the gadget ##
-##########################################
-
-systemctl restart getty@ttyGS0
-
-echo "Ethernet USB OTG gadget init complete - $(cat UDC)"
diff --git a/src/extraFiles/g_ether.conf b/src/extraFiles/g_ether.conf
new file mode 100644
index 000000000..0e9f090ab
--- /dev/null
+++ b/src/extraFiles/g_ether.conf
@@ -0,0 +1 @@
+options g_ether idVendor=0x04b3 idProduct=0x4010 iManufacturer="Raspberry Pi" bcdDevice=0x0100 iProduct="USB Ethernet Gadget" iSerialNumber=
diff --git a/src/extraFiles/usb-ether-gadget-once.service b/src/extraFiles/usb-ether-gadget-once.service
deleted file mode 100644
index 941f4930a..000000000
--- a/src/extraFiles/usb-ether-gadget-once.service
+++ /dev/null
@@ -1,17 +0,0 @@
-[Unit]
-Description=Configure USB Ethernet Gadget
-Requires=sys-kernel-config.mount
-After=sys-kernel-config.mount
-Requires=systemd-modules-load.service
-After=systemd-modules-load.service
-
-[Service]
-Type=oneshot
-WorkingDirectory=/sys/kernel/config/usb_gadget
-ExecStart=/usr/sbin/configure-usb-ether-gadget-once
-StandardOutput=journal+console
-# TODO: remove
-User=root
-
-[Install]
-WantedBy=usb-gadget.target
diff --git a/src/extraFiles/usb-ether-gadget.conf b/src/extraFiles/usb-ether-gadget.conf
new file mode 100644
index 000000000..b79e76045
--- /dev/null
+++ b/src/extraFiles/usb-ether-gadget.conf
@@ -0,0 +1,2 @@
+dwc2
+g_ether
diff --git a/src/imagewriter.cpp b/src/imagewriter.cpp
index 55bc39ff2..dd1289061 100644
--- a/src/imagewriter.cpp
+++ b/src/imagewriter.cpp
@@ -477,10 +477,23 @@ namespace {
} // namespace anonymous
-void ImageWriter::setHWFilterList(const QByteArray &json, const bool &inclusive) {
+void ImageWriter::setHWFilterList(const QByteArray &json, const bool &inclusive, const bool &isModelZero) {
QJsonDocument json_document = QJsonDocument::fromJson(json);
_deviceFilter = json_document.array();
_deviceFilterIsInclusive = inclusive;
+ _isModelZero = isModelZero;
+}
+
+QJsonArray ImageWriter::getHWFilterList() {
+ return _deviceFilter;
+}
+
+bool ImageWriter::getHWFilterListInclusive() {
+ return _deviceFilterIsInclusive;
+}
+
+bool ImageWriter::getHWFilterIsModelZero() {
+ return _isModelZero;
}
void ImageWriter::handleNetworkRequestFinished(QNetworkReply *data) {
diff --git a/src/imagewriter.h b/src/imagewriter.h
index 166c241aa..251ed25cd 100644
--- a/src/imagewriter.h
+++ b/src/imagewriter.h
@@ -85,7 +85,16 @@ class ImageWriter : public QObject
Q_INVOKABLE void beginOSListFetch();
/** Set the HW filter, for a filtered view of the OS list */
- Q_INVOKABLE void setHWFilterList(const QByteArray &json, const bool &inclusive);
+ Q_INVOKABLE void setHWFilterList(const QByteArray &json, const bool &inclusive, const bool &isModelZero);
+
+ /* Get the HW filter list */
+ Q_INVOKABLE QJsonArray getHWFilterList();
+
+ /* Get if the HW filter is in inclusive mode */
+ Q_INVOKABLE bool getHWFilterListInclusive();
+
+ /* Get if HW filter tags are from a Pi Zero model */
+ Q_INVOKABLE bool getHWFilterIsModelZero();
/* Set custom cache file */
void setCustomCacheFile(const QString &cacheFile, const QByteArray &sha256);
@@ -122,8 +131,8 @@ class ImageWriter : public QObject
Q_INVOKABLE QString getPSK();
Q_INVOKABLE bool getBoolSetting(const QString &key);
- Q_INVOKABLE void setSetting(const QString &key, const QVariant &value);//, const QVariantList
- Q_INVOKABLE void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const bool enableEtherGadget);
+ Q_INVOKABLE void setSetting(const QString &key, const QVariant &value);
+ Q_INVOKABLE void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const bool enableEtherGadget);
Q_INVOKABLE void setSavedCustomizationSettings(const QVariantMap &map);
Q_INVOKABLE QVariantMap getSavedCustomizationSettings();
Q_INVOKABLE void clearSavedCustomizationSettings();
@@ -186,6 +195,8 @@ protected slots:
QJsonDocument _completeOsList;
QJsonArray _deviceFilter;
bool _deviceFilterIsInclusive;
+ /* As there is no distinction between normal pi models and zeros (in the tags), this flag can be used to differenciate */
+ bool _isModelZero;
protected:
QUrl _src, _repo;
diff --git a/src/main.qml b/src/main.qml
index f89e95541..6894b4a0f 100644
--- a/src/main.qml
+++ b/src/main.qml
@@ -1614,7 +1614,7 @@ ApplicationWindow {
}
}
- imageWriter.setHWFilterList(hwmodel.tags, inclusive)
+ imageWriter.setHWFilterList(hwmodel.tags, inclusive, hwmodel.name.toLowerCase().includes("zero"))
/* Reload list */
var oslist_json = imageWriter.getFilteredOSlist();
From 38ee1031e719ad40fc464b35acb6aa5f83922e8a Mon Sep 17 00:00:00 2001
From: paulober <44974737+paulober@users.noreply.github.com>
Date: Thu, 19 Sep 2024 17:32:26 +0100
Subject: [PATCH 03/10] Added CLI support for enable usb ether gadget mode
config + CLI version and help arguments
Signed-off-by: paulober <44974737+paulober@users.noreply.github.com>
---
src/OptionsPopup.qml | 1 +
src/cli.cpp | 28 +++++++++++++++++++++++++---
src/downloadthread.cpp | 4 ++++
src/downloadthread.h | 5 +++++
src/imagewriter.cpp | 8 +++++++-
src/imagewriter.h | 3 +++
6 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/src/OptionsPopup.qml b/src/OptionsPopup.qml
index 11fc379da..99e83fd29 100644
--- a/src/OptionsPopup.qml
+++ b/src/OptionsPopup.qml
@@ -847,6 +847,7 @@ Window {
addCmdline("cfg80211.ieee80211_regdom="+fieldWifiCountry.editText)
}
if (chkUSBEther.checked) {
+ // keep parity with cli.cpp
addConfig("dtoverlay=dwc2,dr_mode=peripheral")
enableEtherGadget = true;
diff --git a/src/cli.cpp b/src/cli.cpp
index bb0e88c19..44d0a8b61 100644
--- a/src/cli.cpp
+++ b/src/cli.cpp
@@ -58,11 +58,14 @@ int Cli::run()
{"first-run-script", "Add firstrun.sh to image", "first-run-script", ""},
{"cloudinit-userdata", "Add cloud-init user-data file to image", "cloudinit-userdata", ""},
{"cloudinit-networkconfig", "Add cloud-init network-config file to image", "cloudinit-networkconfig", ""},
+ {"usb-ether-gadget", "Enable USB Ethernet Gadget mode"},
{"disable-eject", "Disable automatic ejection of storage media after verification"},
{"debug", "Output debug messages to console"},
{"quiet", "Only write to console on error"},
});
+ parser.addVersionOption();
+ parser.addHelpOption();
parser.addPositionalArgument("src", "Image file/URL");
parser.addPositionalArgument("dst", "Destination device");
parser.process(*_app);
@@ -70,7 +73,7 @@ int Cli::run()
const QStringList args = parser.positionalArguments();
if (args.count() != 2)
{
- std::cerr << "Usage: --cli [--disable-verify] [--disable-eject] [--sha256 [--cache-file ]] [--first-run-script