Repository navigation
[Guide]: "Serial Port Passthrough (/dev/ttyS0) in dockur/windows" #1248
Description
Activity
- addedquestionFurther information is requestedFurther information is requested
on May 20, 2025 - changed the title
[-][Guide]: Resolving "Device or resource busy" for Serial Port Passthrough (`/dev/ttyS0`) in `dockur/windows`[/-][+][Guide]: "Serial Port Passthrough (`/dev/ttyS0`) in `dockur/windows`"[/+]on May 21, 2025 @toruscomputer thank you for the detailed writeup. Your post gave me enough information to resolve a problem that I have been expeiencing for quite some time 👍.
I try to pass an FTDI cable virtual COM port from the host to the guest based on the serial number of the FTDI cable. I need to use the cable serial number because there are multiple FTDI cables connected to the host and there is only 1 specific cable that needs to be connected to the guest. This means that filtering on vendor ID / product ID is not an option.
The cable is detected in the host OS as e.g.
/dev/serial/by-id/FTDI-ABCDEF/. The docker-compose file that results in a working serial port in the guest looks like:services: windows: image: dockurr/windows:latest container_name: windows environment: VERSION: "win11" ARGUMENTS: "-chardev serial,id=cable1,path=/dev/serial/by-id/FTDI-ABCDEF -device usb-serial,chardev=cable1" devices: - /dev/kvm - /dev/serial/by-id/FTDI-ABCDEF cap_add: - NET_ADMIN volumes: - "./windows/share:/storage/shared" stop_grace_period: 2m restart: on-failureThis works because the
devicessection in the docker-compose.yml passes the FTDI from the host to the docker container where qemu runs in, and then theARGUMENTSconfigure qemu to present that port as a virtual COM port to the guest Windows OS.Notes for my later self when I need to refer back to this:
- the first time you boot the windows VM it takes some time for the VCOM driver to be initialised in Windows. Let it do its thing, in the end the port will appear under the COM port section of the hardware overview.
- opening the serial port takes some time in the guest. Once it is open all is working as expected.
- for troubleshooting you can check the arguments passed to qemu by running
docker compose exec windows ps -ef | grep qemu-system-x86
Hi. I have 4 serial ports to pass to the client but it only supports 1. It says there are not enough resources.
I have tried different approaches but without success.
Above all, if anyone has encountered the same problem. Many thanks.compose:
services:
windows:
image: dockurr/windows:latest
container_name: win7u
privileged: true
environment:
VERSION: "7u"
ARGUMENTS: "-serial /dev/ttyUSB0 -serial /dev/ttyUSB1 -serial /dev/ttyUSB2 -serial /dev/ttyUSB3"
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
- /dev/ttyUSB1:/dev/ttyUSB1
- /dev/ttyUSB2:/dev/ttyUSB2
- /dev/ttyUSB3:/dev/ttyUSB3
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 8007:8006
volumes:
- /home/x/WIN7U:/storage
restart: always
stop_grace_period: 2m
Is your question not already answered in the FAQ?
Is this a general question and not a technical issue?
Question
Description
When attempting to pass through a host serial port (e.g.,
/dev/ttyS0) to a Windows XP VM running via thedockur/windowsDocker image, users might encounter aqemu-system-x86_64: -serial /dev/ttyS0: Could not open '/dev/ttyS0': Device or resource busyerror in the Docker logs, even when thedevices:mapping is correctly configured indocker-compose.yml.Additionally, initial attempts to use environment variables like
QEMU_ARGS,EXTRA_ARGS, orARGSto specify-serial /dev/ttyS0may appear to be ignored or overridden by-serial ptyin the final QEMU command.Root Cause Analysis
Through detailed debugging of the
dockur/windowsentrypoint scripts (entry.sh,power.sh,config.sh), the following was discovered:entry.sh, thepower.shscript is sourced beforeconfig.sh.power.sh(specifically around line 217 in the providedpower.shversion) contains the lineSERIAL="pty". This hardcodes theSERIALshell variable topty.config.shBehavior: Whenconfig.shis later sourced:: "${SERIAL:="mon:stdio"}"does not overrideSERIAL, because it's already set bypower.sh.SERIAL_OPTSvariable is therefore set to-serial pty.config.shconstructs the final QEMUARGSstring by appending the$ARGUMENTSenvironment variable last.-serial ptyand then-serial /dev/ttyS0), QEMU generally honors the last instance of that argument.Therefore, the strategy is to leverage the
ARGUMENTSenvironment variable to append our desired serial port configuration (-serial /dev/ttyS0) at the very end of the QEMU command, effectively overriding the default-serial pty.The "Device or resource busy" error is a separate issue, indicating that the serial port on the host system is actively in use by another process. This needs to be resolved on the host itself.
Solution
The solution involves two key parts:
ARGUMENTSenvironment variable is used correctly./dev/ttyS0.Step 1: Modify
docker-compose.ymlUpdate your
docker-compose.ymlfile as follows. Ensure you remove or comment out any previous attempts to setQEMU_ARGS,EXTRA_ARGS, orSERIAL.Step 2: Identify and Terminate Conflicting Processes on the Host
After updating your
docker-compose.ymland before redeploying, it's crucial to ensure/dev/ttyS0on your Ubuntu host is not in use.Check if
ttyS0is busy:sudo lsof /dev/ttyS0 # OR sudo fuser /dev/ttyS0If these commands return any output (e.g.,
screen,ModemManager,minicom, etc.), it means a process is using the port.Terminate conflicting processes:
lsoforfusershow processes (e.g.,screenprocesses with PIDs), kill them:ModemManagerand you don't need it:sudo systemctl stop ModemManager sudo systemctl disable ModemManager # To prevent it from starting on bootdialoutgroup (or the group owning/dev/ttyS0):Verify
ttyS0is free:This command should now return no output.
Step 3: Redeploy and Verify
Redeploy your Docker stack:
(Or update the stack in Portainer).
Check Docker logs:
Look for the
Arguments:section. You should now see both-serial ptyAND-serial /dev/ttyS0, with-serial /dev/ttyS0appearing after-serial pty. The critical "Device or resource busy" error should be gone.Test in Windows XP:
/dev/ttyS0. Set the baud rate, data bits, parity, etc., to match your device.By following these steps, you should achieve successful serial communication from your Windows XP VM through your host's
/dev/ttyS0.