Enabling USB for Cubieboard QEMU

Enabling USB for Cubieboard QEMU

Embedded systems support various serial or parallel interfaces for communication. In some of the posts in MistraSolutions blog interfaces like SPI and I2C were covered.

Today, one more serial interface will be covered, which is USB (Universal Serial Bus). We will not go into details of creating a custom USB device, but into using the USB bus on the Cubieboard emulated in QEMU.

USB support in QEMU provides instructions on some of the features supported by QEMU, like adding a virtual USB storage or HID device (mouse, keyboard, tablet).

The practical thing about USB is that it is a standard protocol and that even a real (physical) device can be connected to a QEMU instance.

Enabling USB for Cubieboard QEMU

QEMU Cubieboard supports for USB emulation, but it is not enabled by default. This can be observed by starting QEMU emulation, where following messages will be printed in the U-Boot and Linux boot log:

[ U-Boot log ]
...
starting USB...
Bus usb@1c14000: USB EHCI 0.00
Bus usb@1c14400: USB OHCI 0.0
Bus usb@1c1c000: USB EHCI 0.00
Bus usb@1c1c400: USB OHCI 0.0
scanning bus usb@1c14000 for devices... 1 USB Device(s) found
scanning bus usb@1c14400 for devices... 1 USB Device(s) found
scanning bus usb@1c1c000 for devices... 1 USB Device(s) found
scanning bus usb@1c1c400 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
...
Starting kernel ...
...
[    0.736588] ehci-platform 1c14000.usb: EHCI Host Controller
[    0.737300] ehci-platform 1c14000.usb: new USB bus registered, assigned bus number 1
[    0.739015] ehci-platform 1c1c000.usb: EHCI Host Controller
[    0.739360] ehci-platform 1c1c000.usb: new USB bus registered, assigned bus number 2
[    0.741614] ohci-platform 1c14400.usb: Generic Platform OHCI controller
[    0.742047] ohci-platform 1c14400.usb: new USB bus registered, assigned bus number 3
[    0.743662] clk: Disabling unused clocks
[    0.748461] ohci-platform 1c1c400.usb: Generic Platform OHCI controller
[    0.748792] ohci-platform 1c1c400.usb: new USB bus registered, assigned bus number 4
[    0.750701] ohci-platform 1c14400.usb: irq 107, io mem 0x01c14400
[    0.751755] ohci-platform 1c1c400.usb: irq 108, io mem 0x01c1c400
[    0.755512] ehci-platform 1c1c000.usb: can't setup: -110
[    0.755924] ehci-platform 1c1c000.usb: USB bus 2 deregistered
[    0.756801] ehci-platform: probe of 1c1c000.usb failed with error -110
[    0.760776] ehci-platform 1c14000.usb: can't setup: -110
[    0.761187] ehci-platform 1c14000.usb: USB bus 1 deregistered
[    0.761841] ehci-platform: probe of 1c14000.usb failed with error -110
[    0.816298] ohci-platform 1c1c400.usb: init err (00000000 0000)
[    0.817222] ohci-platform 1c1c400.usb: can't start
[    0.819682] ohci-platform 1c1c400.usb: startup error -75
[    0.820272] ohci-platform 1c1c400.usb: USB bus 4 deregistered
[    0.821419] ohci-platform: probe of 1c1c400.usb failed with error -75
[    0.822710] ohci-platform 1c14400.usb: init err (00000000 0000)
[    0.823681] ohci-platform 1c14400.usb: can't start
[    0.824342] ohci-platform 1c14400.usb: startup error -75
[    0.824998] ohci-platform 1c14400.usb: USB bus 3 deregistered
[    0.825782] ohci-platform: probe of 1c14400.usb failed with error -75
...

Luckily, USB can be enabled for any board (that has support for emulation of USB controller) by passing -usb when starting the QEMU emulation. The command to enable USB emulation is

qemu-system-arm \
    -M cubieboard \
    -m 1G \
    -net nic \
    -net tap,ifname=qemu-tap0,script=no,downscript=no \
    -sd sd.img \
    -nographic \
    -usb

In the U-Boot and Linux logs we can see that the USB is now recognized.

[ U-Boot log ]
...
starting USB...
Bus usb@1c14000: USB EHCI 1.00
Bus usb@1c14400: USB OHCI 1.0
Bus usb@1c1c000: USB EHCI 1.00
Bus usb@1c1c400: USB OHCI 1.0
scanning bus usb@1c14000 for devices... 1 USB Device(s) found
scanning bus usb@1c14400 for devices... 1 USB Device(s) found
scanning bus usb@1c1c000 for devices... 1 USB Device(s) found
scanning bus usb@1c1c400 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
...
Starting kernel ...
...
[    0.776150] ehci-platform 1c14000.usb: EHCI Host Controller
[    0.776700] ehci-platform 1c14000.usb: new USB bus registered, assigned bus number 1
[    0.780998] ehci-platform 1c14000.usb: irq 105, io mem 0x01c14000
[    0.785543] ehci-platform 1c1c000.usb: EHCI Host Controller
[    0.786053] ehci-platform 1c1c000.usb: new USB bus registered, assigned bus number 2
[    0.787271] ohci-platform 1c14400.usb: Generic Platform OHCI controller
[    0.787815] ohci-platform 1c14400.usb: new USB bus registered, assigned bus number 3
[    0.789564] ohci-platform 1c1c400.usb: Generic Platform OHCI controller
[    0.790236] ohci-platform 1c1c400.usb: new USB bus registered, assigned bus number 4
[    0.792127] ohci-platform 1c14400.usb: irq 107, io mem 0x01c14400
[    0.793064] ohci-platform 1c1c400.usb: irq 108, io mem 0x01c1c400
[    0.793743] ehci-platform 1c1c000.usb: irq 106, io mem 0x01c1c000
[    0.807429] ehci-platform 1c14000.usb: USB 2.0 started, EHCI 1.00
[    0.812146] hub 1-0:1.0: USB hub found
[    0.812780] hub 1-0:1.0: 6 ports detected
[    0.837361] ehci-platform 1c1c000.usb: USB 2.0 started, EHCI 1.00
[    0.839332] hub 2-0:1.0: USB hub found
[    0.840711] hub 2-0:1.0: 6 ports detected
[    0.858951] hub 4-0:1.0: USB hub found
[    0.859470] hub 4-0:1.0: 3 ports detected
[    0.861435] hub 3-0:1.0: USB hub found
[    0.861778] hub 3-0:1.0: 3 ports detected

USB Storage device

The posts so far provided instructions on how to use SD card connected to Cubieboard in QEMU. Sometimes it is useful to use some extra memory storage types, like a USB drive.

If we want to add a USB drive to the QEMU emulated Cubieboard, first we need to create a USB drive image file usb.img, as well as partition and format it.

In this example we will create a 1GB USB drive with one FAT32 partition.

# Create a USB drive image
dd if=/dev/zero of=usb.img bs=1M count=1024
# Use sfdisk to partition it (single FAT32 partition)
sfdisk usb.img << EOF
,,c
EOF

Once partition is made, it needs to be formatted. In order to do it, the image should be made available to the system using kpartx. Running the kpartx command with -v will print the loop mapper partition that is assigned.

sudo kpartx -av ./usb.img
add map loop0p1 (252:0): 0 2095104 linear 7:0 2048

Based on this output, we can format the partition using

sudo mkfs.vfat /dev/mapper/loop0p1

Use the correct path based on the kpartx output.

We will also place file test.txt in the newly created partition, with the following content

Hello from USB drive in QEMU Cubieboard

In order to do it, the partition needs to be mounted. Following code can be used to do it

mkdir -p /tmp/usb
sudo mount /dev/mapper/loop0p1 /tmp/usb
sudo tee /tmp/usb/test.txt << EOF
Hello from USB drive in QEMU Cubieboard
EOF

After the file is created, the partition should be umounted, and image removed from the system

sudo umount /tmp/usb
sudo kpartx -d ./usb.img

The QEMU can now be started with a USB drive attached using

qemu-system-arm \
    -M cubieboard \
    -m 1G \
    -net nic \
    -net tap,ifname=qemu-tap0,script=no,downscript=no \
    -usb \
    -device usb-storage,bus=usb-bus.0,drive=stick \
    -drive if=none,id=stick,file=usb.img \
    -sd sd.img \
    -nographic
U-Boot 2024.01-g (Jan 08 2024 - 15:37:48 +0000) Allwinner Technology
...
starting USB...
Bus usb@1c14000: USB EHCI 1.00
Bus usb@1c14400: USB OHCI 1.0
Bus usb@1c1c000: USB EHCI 1.00
Bus usb@1c1c400: USB OHCI 1.0
scanning bus usb@1c14000 for devices... 2 USB Device(s) found
scanning bus usb@1c14400 for devices... 1 USB Device(s) found
scanning bus usb@1c1c000 for devices... 1 USB Device(s) found
scanning bus usb@1c1c400 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 1 Storage Device(s) found
...
[    1.373968] usb-storage 1-1:1.0: USB Mass Storage device detected
[    1.375835] scsi host1: usb-storage 1-1:1.0
[    2.436405] scsi 1:0:0:0: Direct-Access     QEMU     QEMU HARDDISK    2.5+ PQ: 0 ANSI: 5
[    2.438455] sd 1:0:0:0: Attached scsi generic sg0 type 0
[    2.508795] sd 1:0:0:0: [sda] 2097152 512-byte logical blocks: (1.07 GB/1.00 GiB)
[    2.513932] sd 1:0:0:0: [sda] Write Protect is off
[    2.521230] sd 1:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[    2.538341]  sda: sda1
[    2.541121] sd 1:0:0:0: [sda] Attached SCSI disk
...

Kernel should be built with CONFIG_USB_STORAGE option enabled.

After QEMU is started, the USB drive can be mounted using

mkdir -p /tmp/usb
mount /dev/sda1 /tmp/usb

This will provide access to the files and we can confirm that the test.txt is present with the predefined content.

USB mount check

USB passthrough

USB passthrough is a very interesting feature, where a physical device can be passed from the host to the QEMU system that is being emulated. The passthrough can be done on the VID:PID, or on the explicit USB port on the host.

For example, if a USB drive is attached to the host, the lsusb output could be

lsusb
Bus 002 Device 002: ID 0781:5597 SanDisk Corp. Cruzer Glide 3.0
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

The VID:PID for the USB drive is 0781:5597, so in order to pass this device to QEMU a following command can be used

qemu-system-arm \
    -M cubieboard \
    -m 1G \
    -net nic \
    -net tap,ifname=qemu-tap0,script=no,downscript=no \
    -usb \
    -device usb-host,vendorid=0x0781,productid=0x5597 \
    -sd sd.img \
    -nographic
[    2.033214] usb-storage 2-1:1.0: USB Mass Storage device detected
[    2.094059] scsi host1: usb-storage 2-1:1.0
[    3.148767] scsi 1:0:0:0: Direct-Access     SanDisk  Cruzer Glide 3.0 1.00 PQ: 0 ANSI: 6
[    3.157951] sd 1:0:0:0: Attached scsi generic sg0 type 0
[    3.187860] sd 1:0:0:0: [sda] 30605312 512-byte logical blocks: (15.7 GB/14.6 GiB)
[    3.206973] sd 1:0:0:0: [sda] Write Protect is off
[    3.224366] sd 1:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
[    3.455618]  sda: sda1
[    3.503294] sd 1:0:0:0: [sda] Attached SCSI removable disk

Again, the USB drive can be mounted and file test.txt can be accessed to validate the expected content.

USB mount check phys

Summary

QEMU has built-in support for USB device emulation, with some of the common classes implemented.

This post provides a short overview of steps needed to enable and use USB for QEMU Cubieboard. Using these commands more features can be added to the emulated system.

These commands are also applicable to other systems that can be emulated in QEMU, which have support for the USB controller.

Subscribe
If you would like to get information as soon as new content is published, please subscribe to the "MistraSolutions newsletter".