Trigger usb_modeswitch on boot for Huawei E3372 Modem

I am trying to make a Huawei Brovi E3372-325 USB LTE model work with a Raspberry Pi. Out of the box, it shows as a CDROM when plugging it in. (This is apparently used to automatically run the driver installation on Windows.)

So far, I found this post with a udev rules configuration file. That enables the modem when hotplugging it while the system is running by running usb_modeswitch. However, if the modem is plugged in on boot, it does not work, instead showing as a CD ROM.

Therefore, I am now trying to write a system service to run usb_modeswitch on boot. As a step towards that, I booted with the modem plugged in and then tried executing the usb_modeswitch commands from the configuration file manually. However, that does not have the intended effect.

The commands are

/sbin/usb_modeswitch -v 3566 -p 2001 -W -R -w 400
/sbin/usb_modeswitch -v 3566 -p 2001 -W -R

What do I need to do to make this work? Does the udev rules configuration trigger more actions that just the two listed commands? Or why do the seemingly same commands not have the same effect?

Update

Apparently, upon being powered on, the modem shows itself as a modem for a second, then switches to CDROM mode, but does not seem to accept commands switching it back to modem mode. The CDROM mode is intended for automatic driver installation in Windows. Though, that also means that when the driver is installed, the drive can be switched back to modem mode. So, it seems that usb_modeswitch and the Windows driver use different commands to switch to modem mode?

Asked By: LiterallyCode

||

Those commands don’t do anything useful on their own; both only reset the USB port. Actual mode-switching would be done using the -J or -X options (the former switches it to CDC fake-Ethernet mode; the latter to MBIM modem mode).

However, the modem also appears to start in RNDIS fake-Ethernet mode, only switching to CDROM mode if nothing binds to the RNDIS interface within a second. So the behavior will be different during normal connection (when udev is ready to load the driver instantly) vs during a system boot (when it takes a while between USB device initialization and driver load).

At least that was the case when I originally got mine, but then it mysteriously switched behavior two days later. I believe it must’ve downloaded a firmware update¹ and now its "startup" appears to be completely different – when connected it only stays 3566:2001 for a second before turning into 12d1:1f01, which usb_modeswitch recognizes and switches to CDC fake-Ethernet mode. (It also freezes a lot.)


¹ It’s not just a modem, it’s a whole Linux device on a stick, complete with internal web server and automatic updates.

Answered By: u1686_grawity

I found a solution, which seems to work both on hotplug and on boot.

First, the copy and paste solution:

echo -e "ACTION!="add", GOTO="modeswitch_rules_end"nSUBSYSTEM!="usb", GOTO="modeswitch_rules_end"nn# All known install partitions are on interface 0nATTRS{bInterfaceNumber}!="00", GOTO="modeswitch_rules_end"nn# only storage class devices are handled; negativen# filtering here would exclude some quirky devicesnATTRS{bDeviceClass}=="e0", GOTO="modeswitch_rules_begin"nATTRS{bInterfaceClass}=="e0", GOTO="modeswitch_rules_begin"nGOTO="modeswitch_rules_end"nnLABEL="modeswitch_rules_begin"n# Huawei E3372-325nATTRS{idVendor}=="3566", ATTRS{idProduct}=="2001", RUN+="/sbin/usb_modeswitch -v 3566 -p 2001 -W -R -w 400"nATTRS{idVendor}=="3566", ATTRS{idProduct}=="2001", RUN+="/sbin/usb_modeswitch -v 3566 -p 2001 -W -R"nnLABEL="modeswitch_rules_end"" | sudo tee /etc/udev/rules.d/40-huawei.rules > /dev/null
echo -e "[Unit]nDescription=Switch E3372 dongle to modem modenAfter=multi-user.targetnn[Service]nType=simplenExecStart=usb_modeswitch -v 3566 -p 2001  -XnExecStartPost=sleep 1nExecStartPost=modprobe optionnExecStartPost=sleep 1nExecStartPost=/bin/bash -c 'echo "3566 2001 ff" | sudo tee /sys/bus/usb-serial/drivers/option1/new_id > /dev/null'nExecStartPost=sleep 1nExecStartPost=/bin/bash -c 'ls -la /dev/ttyUSB4 | grep dialout && { echo AT^RESET > /dev/ttyUSB4; timeout 2 cat /dev/ttyUSB4; }'nn[Install]nWantedBy=multi-user.targetn" | sudo tee /etc/systemd/system/modeswitch_e3372_modem.service > /dev/null
sudo systemctl daemon-reload
sudo systemctl enable modeswitch_e3372_modem.service

The above first creates Udev rules to modeswitch the modem on hotplug to, well, modem mode, based on this post:

ACTION!="add", GOTO="modeswitch_rules_end"
SUBSYSTEM!="usb", GOTO="modeswitch_rules_end"

# All known install partitions are on interface 0
ATTRS{bInterfaceNumber}!="00", GOTO="modeswitch_rules_end"

# only storage class devices are handled; negative
# filtering here would exclude some quirky devices
ATTRS{bDeviceClass}=="e0", GOTO="modeswitch_rules_begin"
ATTRS{bInterfaceClass}=="e0", GOTO="modeswitch_rules_begin"
GOTO="modeswitch_rules_end"

LABEL="modeswitch_rules_begin"
# Huawei E3372-325
ATTRS{idVendor}=="3566", ATTRS{idProduct}=="2001", RUN+="/sbin/usb_modeswitch -v 3566 -p 2001 -W -R -w 400"
ATTRS{idVendor}=="3566", ATTRS{idProduct}=="2001", RUN+="/sbin/usb_modeswitch -v 3566 -p 2001 -W -R"

LABEL="modeswitch_rules_end"

Then, it creates a system service to reset the modem after booting to be able to talk to it in the one second time window in which it accepts commands (based on an idea from this post):

[Unit]
Description=Switch E3372 dongle to modem mode
After=multi-user.target

[Service]
Type=simple
ExecStart=usb_modeswitch -v 3566 -p 2001  -X
ExecStartPost=sleep 1
ExecStartPost=modprobe option
ExecStartPost=sleep 1
ExecStartPost=/bin/bash -c 'echo "3566 2001 ff" | sudo tee /sys/bus/usb-serial/drivers/option1/new_id > /dev/null'
ExecStartPost=sleep 1
ExecStartPost=/bin/bash -c 'ls -la /dev/ttyUSB4 | grep dialout && { echo AT^RESET > /dev/ttyUSB4; timeout 2 cat /dev/ttyUSB4; }'

[Install]
WantedBy=multi-user.target
Answered By: LiterallyCode