Skip to content

usb: device_next: Add USB MTP class support #86832

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

ExtremeGTX
Copy link
Contributor

@ExtremeGTX ExtremeGTX commented Mar 10, 2025

Implement a basic version of USB MTP (Media transfer protocol) class which support
the necessary MTP commands to handle Dir/file transfer between a device and host.
Fixes: #54468

TODO:

  • Address FIXME comment(s): mainly handle cancel transaction request.
  • Test on USB Full speed (rpi_pico)
  • Test on another board than STM32F769i-DISCO
    • rpi_pico 2040
  • Remove Extensive logging
  • Make MAX_PACKET_SIZE value dependent on whether USB is HS/FS
  • Polishing the MTP Sample including updating the readme file
  • Improve Error handling

Thanks:

  • Zephyr USB Team for helping me understand how device_next works
  • HHD Software for supporting this project.

@ExtremeGTX
Copy link
Contributor Author

Dear Reviewers:

Could you please help me validate the current architecture first, then we can move to final polishing when I get the PR out of draft state.

Thanks a lot.

@ExtremeGTX ExtremeGTX force-pushed the usb_mtp_next_PR branch 2 times, most recently from 7874f45 to 748eb7e Compare March 10, 2025 03:37
@ExtremeGTX ExtremeGTX requested a review from kartben March 14, 2025 20:11
@ExtremeGTX ExtremeGTX force-pushed the usb_mtp_next_PR branch 2 times, most recently from f6bfa5e to 02a2fb9 Compare April 21, 2025 21:03
@ExtremeGTX ExtremeGTX requested a review from jfischer-no April 21, 2025 21:06
@tmon-nordic
Copy link
Contributor

The class fixup/polishing commits should be squashed together into the main MTP class implementation commit. Sample changes should go into separate commits.

@kartben kartben requested a review from Copilot April 24, 2025 01:01
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements basic USB MTP class support to enable file and directory transfers between a device and a host. Key changes include:

  • Adding a new MTP class header with necessary function declarations and context structure.
  • Providing a sample application to test and demonstrate the MTP functionality.
  • Updating USB descriptors, DTS bindings, and sample configuration to support MTP.

Reviewed Changes

Copilot reviewed 7 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
subsys/usb/device_next/class/usbd_mtp_class.h Introduces declarations for the USB MTP class support
samples/subsys/usb/mtp/src/main.c Implements a sample application to test the MTP class driver
samples/subsys/usb/mtp/sample.yaml Adds a sample configuration for the MTP device class
include/zephyr/usb/usb_ch9.h Updates USB descriptors to include the MTP image class type
dts/bindings/fs/zephyr,fstab-common.yaml Adds a filesystem binding property for enabling MTP file access
Files not reviewed (11)
  • samples/subsys/usb/mtp/CMakeLists.txt: Language not supported
  • samples/subsys/usb/mtp/Kconfig: Language not supported
  • samples/subsys/usb/mtp/README.rst: Language not supported
  • samples/subsys/usb/mtp/boards/rpi_pico.overlay: Language not supported
  • samples/subsys/usb/mtp/boards/stm32f769i_disco.overlay: Language not supported
  • samples/subsys/usb/mtp/prj.conf: Language not supported
  • subsys/usb/device_next/CMakeLists.txt: Language not supported
  • subsys/usb/device_next/class/Kconfig: Language not supported
  • subsys/usb/device_next/class/Kconfig.mtp: Language not supported
  • tests/subsys/usb/device_next/build_all.conf: Language not supported
  • tests/subsys/usb/device_next/build_all.overlay: Language not supported

@jfischer-no jfischer-no removed the request for review from kartben April 24, 2025 08:39
@jfischer-no jfischer-no self-assigned this Apr 24, 2025
@kartben kartben self-requested a review April 24, 2025 20:34
@ExtremeGTX ExtremeGTX force-pushed the usb_mtp_next_PR branch 2 times, most recently from 3bb7378 to 9910433 Compare April 24, 2025 21:51
@ExtremeGTX ExtremeGTX marked this pull request as ready for review April 24, 2025 21:51
@Finomnis
Copy link
Contributor

Finomnis commented May 12, 2025

Another bug report: copying text files to and from the device seems to truncate them to 52 bytes.

@ExtremeGTX
Copy link
Contributor Author

Another bug report: copying text files to and from the device seems to truncate them to 52 bytes.

Could you please share the logs with CONFIG_USBD_MTP_LOG_LEVEL_DBG=y enabled.
I tried to copy files of different lengths (10, 54, 190) bytes, also large files of ~600KB of types (png, pdf) to make sure that no corruption happens.

Above tests done while one CDC_ACM instance is enabled in addition to MTP on USB.

Thanks for testing and reporting back :)

Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
3 Security Hotspots

See analysis details on SonarQube Cloud

@Finomnis
Copy link
Contributor

Finomnis commented May 13, 2025

Sure :)

I compiled commit 12534fcad7e19672031e1bd6608359c199e10208.

Those are the files I had to modify:

samples/subsys/usb/mtp/prj.conf:

CONFIG_USB_DEVICE_STACK_NEXT=y
CONFIG_USBD_MTP_CLASS=y

CONFIG_SAMPLE_USBD_PRODUCT="USBD MTP sample"
CONFIG_SAMPLE_USBD_PID=0x0009

CONFIG_LOG=y
CONFIG_USBD_LOG_LEVEL_DBG=y
CONFIG_UDC_DRIVER_LOG_LEVEL_DBG=y
CONFIG_USBD_MTP_LOG_LEVEL_DBG=y
CONFIG_LOG_BUFFER_SIZE=131072

CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n

CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_LOAD_OFFSET=0x0
CONFIG_FLASH_LOAD_SIZE=0x100000

CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=y

CONFIG_USBD_THREAD_STACK_SIZE=3192
CONFIG_MAIN_STACK_SIZE=2048

samples/subsys/usb/mtp/boards/teensy40.overlay:

&w25q16jvuxim {
	partitions {
		compatible = "fixed-partitions";
		#address-cells = <1>;
		#size-cells = <1>;

		storage_partition: partition@100000 {
			label = "storage";
			reg = <0x100000  DT_SIZE_M(1)>;
		};
	};
};

/ {
	fstab {
		compatible = "zephyr,fstab";
		lfs1: lfs1 {
			compatible = "zephyr,fstab,littlefs";
			read-size = <32>;
			prog-size = <32>;
			cache-size = <256>;
			lookahead-size = <64>;
			block-cycles = <512>;
			partition = <&storage_partition>;
			mount-point = "/lfs1";
			automount;
			mtp-enabled;
		};
	};
};

Then I compiled and ran with

west build -b teensy40 samples/subsys/usb/mtp --pristine
west flash

Like previously mentioned, Windows 11, Zephyr SDK 0.17.0.

Here is the log file: (I annotated where I performed an action)

annotated_log_file_round_trip.txt

Note also that the modification time of the file broke in the process:
image

@Finomnis
Copy link
Contributor

Finomnis commented May 13, 2025

Another small insight: When enabling the shell by doing:

CONFIG_SHELL=y
CONFIG_FILE_SYSTEM_SHELL=y

And then running

fs cat /lfs1/loremipsum.txt

Then the file is there and complete.

So the problem must occur during transfer from device to PC.

@Finomnis
Copy link
Contributor

Finomnis commented May 13, 2025

Another bugreport: when connecting the device to the PC, one needs to enter the device directory in the explorer twice before the file shows up. When entering the first time, the directory shows as empty.

@matt-wood-ct
Copy link
Contributor

matt-wood-ct commented May 14, 2025

I gave your working branch a go on a NXP FRDM RW612 board today, few quirks...
overlay used:

/ {
	fstab {
		compatible = "zephyr,fstab";
		lfs1: lfs1 {
			compatible = "zephyr,fstab,littlefs";
			read-size = <32>;
			prog-size = <32>;
			cache-size = <256>;
			lookahead-size = <64>;
			block-cycles = <512>;
			partition = <&storage_partition>;
			mount-point = "/lfs1";
			automount;
			mtp-enabled;
		};
	};
};

I had to bump the main stack size up to get it to boot, lfs format would fault otherwise.

On Ubuntu 24.04 I had it crashing immediately on plugging in, after a quick debugging session I found that in MTP_CMD_HANDLER(MTP_OP_GET_OBJECT_HANDLES) storage_id was coming through as 0xF which caused a fault on the for loop, I added some error handling to avoid that crash, then I was able to get it to enumerate.

Once enumerated it appeared in my file explorer and somewhat worked, I could browse but writing would cause a crash and leave empty files on the FS. Testing the same setup on windows 10 had a little more success the files written had some data at the start but they were still incomplete (no crashes though).

This is a very good start, but certainly still need a lot of testing and polishing 😄 I will continue to watch this space and test occasionally, very keen to see this feature make it into main.

p.s. I noted the partial file we copied was also exactly 52 bytes long like the @Finomnis 's test file

p.p.s I think your sample needs MAIN_STACK_SIZE=2048 it only works on the pico because that overrides the value to 4096 anyway in https://github.com/ExtremeGTX/zephyr/blob/4c22fc9adade5bab654254626e6e2981d7714f2c/boards/raspberrypi/rpi_pico/Kconfig.defconfig

@ExtremeGTX
Copy link
Contributor Author

I tried to reproduce on both boards STM32F769i-DISCO and RPI Pico on Windows 10 and 11 using the file attached by @Finomnis and both are working fine, I even tested on another PC which both boards never attached to it before.

Although Teensy 4.0 and FRDM RW612 are different boards, both still use the same NXP UDC Driver, so for me it looks like it is either a problem with NXP UDC Driver or there is an edge case (triggered by NXP UDC) not covered in MTP Implementation, because from the logs I see that communication just stops after first packet which includes the necessary MTP headers + only (52 Bytes of data).

I might have access to one FRDM board and a Nordic board in the next week or the week after, will double check and report back here.

Thanks a lot for your efforts in verifying the implementation, appreciate your support :)

@ExtremeGTX
Copy link
Contributor Author

ExtremeGTX commented May 16, 2025

@Finomnis regarding file date issue, it is because it will require dependency on Hardware RTC which is a dependency didn't want to have (initially at least, later after stabilizing the implementation we can have a Kconfig to enable the integration) or File system supports storing file properties which is not available in a FS like Littlefs.

Edit: Typo fix

@Finomnis
Copy link
Contributor

@Finomnis regarding file data issue, it is because it will require dependency on Hardware RTC which is a dependency didn't want to have (initially at least, later after stabilizing the implementation we can have a Kconfig to enable the integration) or File system supports storing file properties which is not available in a FS like Littlefs.

I get that, no problem.

Regarding the other issue... I might try to improve the current implementation, but not within the next weeks, I'm busy with life. But later I might join your efforts.

@matt-wood-ct
Copy link
Contributor

matt-wood-ct commented May 19, 2025

This morning I tried on a nucleo_h723zg board, can confirm it appears to work flawlessly on ubuntu and windows on that platform, it is likely a NXP USB issue. If you could look into that it would be much appreciated as we are interesting in utilising this on an NXP platform on an upcoming project. 😄

@ExtremeGTX
Copy link
Contributor Author

Hi @dleach02 and @mmahadevan108,
Could you please help ? @Finomnis and @matt-wood-ct are facing transfer issues on NXP Based boards although the same class implementation is verified to work on other platforms (at least ST and RPi).

Thanks in advance :)

@Finomnis
Copy link
Contributor

I didn't forget this, but I'm still busy with personal life. Might come back to this in a couple of weeks maybe.

@ExtremeGTX
Copy link
Contributor Author

@Finomnis I did couple of improvements with Minor re-arch for managing commands states.
you can feel free to list those improvements you wish for and I may handle them.

@ExtremeGTX
Copy link
Contributor Author

Rebase update:

  • Fix SonarQube issues where it makes sense.

@ExtremeGTX
Copy link
Contributor Author

@nashif @tmon-nordic any idea why strnlen is not available in twister -T tests/subsys/usb/device_next/ ?

Implement a basic version of USB MTP (Media transfer protocol) class
which support the necessary MTP commands to handle Dir/file
transfer between a device and host.

Signed-off-by: Mohamed ElShahawi <ExtremeGTX@hotmail.com>
Add a sample application that demonstrates how to use the new USB MTP
device class. This shows how to set up the device tree to expose
storage partitions to a host over USB using MTP.
Files/Dirs can be accessed from host without host supportfor the
underlying filesystem like littlefs.

Signed-off-by: Mohamed ElShahawi <ExtremeGTX@hotmail.com>
Copy link

sonarqubecloud bot commented Jul 5, 2025

@DenisD3D
Copy link

DenisD3D commented Jul 6, 2025

Hello,
I gave your PR a shoot on my stm32l562e_dk board. It include a 512Mb mx25l51245g flash i wanted to use (The littlefs sample works).

First, I had to increase CONFIG_USBD_THREAD_STACK_SIZE to 4096 not to get stack overflows.
Also now I'm getting this error when I connect the usb cable to the board.

[00:00:00.455,000] <inf> usb_mtp_sample: USBD message: New device configuration
[00:00:00.536,000] <err> os: ***** BUS FAULT *****
[00:00:00.536,000] <err> os:   Precise data bus error
[00:00:00.536,000] <err> os:   BFAR Address: 0xc
[00:00:00.536,000] <err> os: r0/a1:  0x20000258  r1/a2:  0x00000000  r2/a3:  0x20008920
[00:00:00.536,000] <err> os: r3/a4:  0x20002a54 r12/ip:  0x20005158 r14/lr:  0x080051d9
[00:00:00.536,000] <err> os:  xpsr:  0x61000000
[00:00:00.536,000] <err> os: Faulting instruction address (r15/pc): 0x08005894
[00:00:00.536,000] <err> os: >>> ZEPHYR FATAL ERROR 25: Unknown error on CPU 0
[00:00:00.536,000] <err> os: Current thread: 0x20002120 (unknown)
[00:00:00.625,000] <err> os: Halting system

Using a debugger, I traced it to the line struct mtp_container *mtp_command = (struct mtp_container *)buf_in->data; in usbd_mtp_class.c where buf_in appear to be null.
I'm using a Linux Fedora 42 and the board USB C port. It successfully appear in the dmesg log but then crash.

[17728.372682] usb 1-1: new full-speed USB device number 28 using xhci_hcd
[17728.498019] usb 1-1: New USB device found, idVendor=2fe3, idProduct=0009, bcdDevice= 4.02
[17728.498023] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[17728.498024] usb 1-1: Product: USBD MTP sample
[17728.498026] usb 1-1: Manufacturer: Zephyr Project
[17728.498027] usb 1-1: SerialNumber: 2034354E323650030010000B

I'm not export in the usb protocol so not really sure what to test now.
Denis

@ExtremeGTX
Copy link
Contributor Author

@DenisD3D Thanks for your feedback.
Could you please add the following KCONFIGs to your project/mtp_sample
And share full logs from booting till the crash ?
Thank you!

@Finomnis
Copy link
Contributor

Finomnis commented Jul 8, 2025

I think you forgot to attach the actual kconfig values :)

@ExtremeGTX
Copy link
Contributor Author

ExtremeGTX commented Jul 9, 2025

I think you forgot to attach the actual kconfig values :)

Sorry 🤦, here you go

CONFIG_USBD_LOG_LEVEL_DBG=y
CONFIG_USBD_MTP_LOG_LEVEL_DBG=y

@DenisD3D
Copy link

DenisD3D commented Jul 9, 2025

Hello,
Thanks for investigating
Here are the full logs from my stm32l562e_dk: mtp_logs.txt
Denis

@DenisD3D
Copy link

Hi @ExtremeGTX, did you had time to take a look on this ? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support the USB MTP feature.
8 participants