Claudio La Rosa
Claudio La Rosa

Reputation: 161

WSL and serial port

I am using Win10 and Linux Ubuntu on WSL 2.0.

For testing purposes of some programs, I would like to use the serial port of my PC in "loopback" with Linux running through WSL.

Basically I would like a process on Linux/WSL to be able to send/receive data from a Windows process or vice versa, through serial port, but without any hardware hack.

Of course I have already tried to set the Windows process serial as "COM1" (as indicated by the Windows resource manager) and the Linux port on WSL as "/dev/ttyS1", but apparently it doesn't work.

Is there any way to do this?

Upvotes: 11

Views: 37752

Answers (4)

Alessandro Bertulli
Alessandro Bertulli

Reputation: 500

I run recently into the same problem with WSL2, and I discovered that it is possible, but with some tinkering.

  • Install usbipd-win. It is needed by WSL2 to access USB devices read by Windows
  • Follow this procedure to download and recompile the WSL2 kernel (it is easier than it seems). Microsoft uses a custom built version of the Linux Kernel to run WSL2, and by default it has many device supports turned off (the assumption is that the WSL should not access external devices, but only virtual ones provided by Windows). Roughly speaking (adjust to your needs and versions) in the Linux bash:
# install build dependencies
sudo apt install build-essential flex bison libssl-dev libelf-dev libncurses-dev autoconf libudev-dev libtool
# check your current kernel version
uname -r
# clone the Microsoft's Linux kernel repo
git clone https://github.com/microsoft/WSL2-Linux-Kernel.git
cd WSL2-Linux-Kernel
# chechout YOUR closest version
git checkout linux-msft-wsl-5.15.153.1 # or the right one
# extract your current kernel configuration (different distros may have this in different locations)
cp /proc/config.gz config.gz
gunzip config.gz
mv config .config

Here in .config you can then tweak some config file configurations, such as setting CONFIG_USB=y. Then do

sudo make menuconfig

and turn the other things you need. For instance, in my case I needed to use a PL2303-based device, so I made sure to enable

  # Device Drivers -> USB Support
  # Device Drivers -> USB Support -> USB announce new devices
  # Device Drivers -> USB Support -> USB Modem (CDC ACM) support
  # Device Drivers -> USB Support -> USB/IP
  # Device Drivers -> USB Support -> USB/IP -> VHCI HCD
  # NO MORE Device Drivers -> USB Support -> USB/IP -> Debug messages for USB/IP
  # Device Drivers -> USB Serial Converter Support
  # Device Drivers -> USB Serial Converter Support -> USB FTDI Single port Serial Driver

(note Debug messages is no longer required, so I disabled it). Now you're ready to compile:

sudo make -j 8
# copy the new kernel in a location you like on the Windows disk
cp arch/x86/boot/bzImage /mnt/c/Users/<user>/usb-bzImage

You then need to tell Windows to use the new kernel instead of the normal one. Open the file C:\Users\<your-user>\.wslconfig (create it if it doesn't exist), and write in there

[wsl2]
kernel=C:\\Users\\<your-user>\\usb-bzImage

Yes, the double backslashes are required, and yes, lines need to start at the first char of the line. Now, from the Windows terminal, turn down all the WSL2 distros active (save your work first), then reopen them:

wsl --shutdown
wsl

If everything is correct, your distro should fire up as usual, but this time you can connect serial USB devices with usbipd-win. In a Windows terminal

usbipd list # see which USB bus the device is attached to
usbipd bind --busid <n1>-<n2> # for this you'll need admin privileges
usbipd attach --wsl --busid <n1>-<n2>

The second step requires an admin terminal, but you'll need to do that only once for every device. Now, in the WSL2 dmesg, you should see the USB device correctly recognized and directed, generally to /dev/ttyUSB0 or similar

Upvotes: 1

nullromo
nullromo

Reputation: 2647

Following these steps (reproduced below), I was able to get access to the COM ports from WSL 2 on Windows 11. I plugged in 2 USB-Serial cables as shown, and I was able to use one COM port from Linux (with the code I was writing) and the other from Windows (with Termite).

2 USB-Serial adapters in 1 PC

  1. Download and install USBIPD-WIN
  2. Open PowerShell as an administrator.
  3. Obtain a list of USB devices using usbipd list.
  4. Find the bus ID of the device (e.g. 4-4) and use usbipd bind --busid <id> to share it with WSL.
  5. Use usbipd attach --wsl --busid <id> to attach the USB port to WSL.
  6. In WSL, you can use lsusb to see the device.

Upvotes: 13

kunif
kunif

Reputation: 4360

Status update

According to other answers, it seems that the addition of product functions has made it possible to use USB devices with WSL2.
Especially in v5.10.93.2, it seems that drivers for two types of USB serial interface chips are built in.

linux-msft-wsl-5.10.93.2

  • Enable CH341 and CP210X USB Serial drivers

linux-msft-wsl-5.10.60.1

  • Enable USB over IP support
  • Enable USB kernel configuration options for interacting with an Arduino over USB

The following is outdated information.

WSL 2.0 does not support serial ports.

Exceptions for using WSL 1 rather than WSL 2


The following options are possible.


Also, if you want to communicate between serial ports even if WSL2 cannot recognize USB serial, this method is also available.
Connecting to serial port (com port) over network

And as you can see from the above explanation, if you want to communicate between the processes of each OS, you can simply use a TCP/IP socket instead of the above mechanism.

Upvotes: 6

user16457328
user16457328

Reputation:

Run this in PowerShell or CMD to see if you use Version 1:

C:\>wsl -l -v
  NAME      STATE           VERSION
* Ubuntu    Running         1

If yes, here's some tested working code to read COM14 from linux command prompt:

#!perl -w

use strict;
$|=1; # autoflush

use Device::SerialPort;

my $port = Device::SerialPort->new("/dev/ttyS14");
$port->baudrate(115200); # Configure below to match your device
$port->databits(8);
$port->parity("none");
$port->stopbits(0);
$port->debug(1);

$port->read_char_time(0);       # don't wait for each character
$port->read_const_time(1);      # 0.001 second per unfulfilled "read" call

while (1) {
  my ($count_in, $str_in) = $port->read(255); # Supposedly must be 255 always
  if($count_in) {
    print $str_in;
  }
}

If you are running WSL2, you can backup, convert or copy your distribution to WSL1 via wsl --export, wsl --import, and wsl --set-version. See this question among others for details.

Upvotes: 0

Related Questions