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 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions dts/bindings/fs/zephyr,fstab-common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,8 @@ properties:

This causes the FS_MOUNT_FLAG_USE_DISK_ACCESS option to be set in
the mount descriptor generated for the file system.

mtp-enabled:
type: boolean
description: |
Provide File system access over USB MTP Protocol
1 change: 1 addition & 0 deletions include/zephyr/usb/usb_ch9.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ struct usb_association_descriptor {
#define USB_BCC_AUDIO 0x01
#define USB_BCC_CDC_CONTROL 0x02
#define USB_BCC_HID 0x03
#define USB_BCC_IMAGE 0x06
#define USB_BCC_MASS_STORAGE 0x08
#define USB_BCC_CDC_DATA 0x0A
#define USB_BCC_VIDEO 0x0E
Expand Down
9 changes: 9 additions & 0 deletions samples/subsys/usb/mtp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(mtp)

include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
9 changes: 9 additions & 0 deletions samples/subsys/usb/mtp/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

# Source common USB sample options used to initialize new experimental USB
# device stack. The scope of these options is limited to USB samples in project
# tree, you cannot use them in your own application.
source "samples/subsys/usb/common/Kconfig.sample_usbd"

source "Kconfig.zephyr"
81 changes: 81 additions & 0 deletions samples/subsys/usb/mtp/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
.. zephyr:code-sample:: usb-mtp
:name: USB MTP
:relevant-api: usbd_api _usb_device_core_api file_system_api

Expose the selected storage partition(s) as USB Media device using Media Transfer Protocol driver.

Overview
********

This sample app demonstrates the use of USB Media Transfer Protocol (MTP)
driver provided by the Zephyr project. It allows the device to be mounted
as a media device on the host system, enabling file transfers between the
host and device.
This sample can be found under :zephyr_file:`samples/subsys/usb/mtp` in the
Zephyr project tree.

Requirements
************

- USB device driver support.
- Storage media with Littlefs/FAT filesystem support.
- Partitions must be mounted before connecting the board to Host.

Building and Running
********************

This sample can be built for multiple boards which can support at least one storage parition,
in this example we will build it for the stm32f769i_disco board:

.. zephyr-app-commands::
:zephyr-app: samples/subsys/usb/mtp
:board: stm32f769i_disco
:goals: flash
:compact:

Running
=======

Plug the board into a host device, for example, a PC running Linux.
The board will be detected as shown by the Linux dmesg command:

.. code-block:: console
usb 9-1: new full-speed USB device number 112 using uhci_hcd
usb 9-1: New USB device found, idVendor=8086, idProduct=f8a1
usb 9-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 9-1: Product: Zephyr MTP
usb 9-1: Manufacturer: ZEPHYR
usb 9-1: SerialNumber: 0123456789AB
Once connected, the device should appear as a media device on your host system.
You can then:
- Browse the device storage
- Transfer files to/from the device
- Create/delete directories

The storage contents will persist across device reboots as long as the
filesystem is properly unmounted before disconnecting or resetting the device.

.. note::

Not All MTP Features are implemented, for example you can't move/copy
files from within the device, it must be done via Host.

Troubleshooting
===============

If the device is not recognized properly:

1. Ensure the storage medium is properly initialized
2. Check that the filesystem is mounted correctly
3. Verify USB configuration is correct for your board
4. Enable DEBUG logs on USB MTP driver to get more information

For debugging purposes, you can enable USB debug logs by setting the following
in your project's configuration:

.. code-block:: none
CONFIG_USBD_LOG_LEVEL_DBG=y
CONFIG_USBD_MTP_LOG_LEVEL_DBG=y
36 changes: 36 additions & 0 deletions samples/subsys/usb/mtp/boards/rpi_pico.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 Kelly Lord
*
* SPDX-License-Identifier: Apache-2.0
*/

&flash0 {
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;
};
};
};
54 changes: 54 additions & 0 deletions samples/subsys/usb/mtp/boards/stm32f769i_disco.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2025 Mohamed ElShahawi (extremegtx@hotmail.com)
*
* SPDX-License-Identifier: Apache-2.0
*/

/delete-node/ &storage_partition;

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

storage_partition: partition@1a0000 {
label = "storage";
reg = <0x001a0000 DT_SIZE_M(40)>;
};
storage_partition2: partition@2ba0000 {
label = "storage2";
reg = <0x2ba0000 DT_SIZE_M(20)>;
};
};
};

/ {
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;
};
lfs2: lfs2 {
compatible = "zephyr,fstab,littlefs";
read-size = <32>;
prog-size = <32>;
cache-size = <256>;
lookahead-size = <64>;
block-cycles = <512>;
partition = <&storage_partition2>;
mount-point = "/lfs2";
automount;
mtp-enabled;
};
};
};
24 changes: 24 additions & 0 deletions samples/subsys/usb/mtp/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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_WRN=y
CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y
CONFIG_USBD_MTP_LOG_LEVEL_ERR=y

CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n

CONFIG_FLASH=y
CONFIG_FLASH_MAP=y

CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=y

CONFIG_USBD_THREAD_STACK_SIZE=4096

CONFIG_USBD_LOG_LEVEL_DBG=y
CONFIG_USBD_MTP_LOG_LEVEL_DBG=y
CONFIG_LOG_BUFFER_SIZE=8192
11 changes: 11 additions & 0 deletions samples/subsys/usb/mtp/sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
sample:
name: USB MTP device class sample
tests:
sample.usb_device_next.mtp:
depends_on: usbd
tags: usb
harness: console
harness_config:
type: one_line
regex:
- "USB device support enabled"
60 changes: 60 additions & 0 deletions samples/subsys/usb/mtp/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2019 Intel Corporation
* Copyright (c) 2025 Mohamed ElShahawi (extremegtx@hotmail.com)
*
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @file
* @brief Sample app for USB MTP class
*
* Sample app for USB MTP class driver. By default MTP class driver will expose
* all storage partitions which has the flag `mtp-enabled`
*/

#include <sample_usbd.h>

#include <zephyr/kernel.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/usb/usbd.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(usb_mtp_sample, LOG_LEVEL_INF);

static void sample_msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg)
{
LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type));

if (usbd_can_detect_vbus(ctx)) {
if (msg->type == USBD_MSG_VBUS_READY) {
if (usbd_enable(ctx)) {
LOG_ERR("Failed to enable device support");
}
}

if (msg->type == USBD_MSG_VBUS_REMOVED) {
if (usbd_disable(ctx)) {
LOG_ERR("Failed to disable device support");
}
}
}
}

int main(void)
{
struct usbd_context *sample_usbd;

sample_usbd = sample_usbd_init_device(sample_msg_cb);
if (sample_usbd == NULL) {
LOG_ERR("Failed to initialize USB device");
return -1;
}

if (usbd_enable(sample_usbd)) {
LOG_ERR("Failed to enable device support");
return -1;
}

LOG_INF("USB device support enabled\n");
return 0;
}
6 changes: 6 additions & 0 deletions subsys/usb/device_next/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,10 @@ zephyr_linker_sources_ifdef(
SECTIONS class/usbd_dfu.ld
)

zephyr_library_sources_ifdef(
CONFIG_USBD_MTP_CLASS
class/usbd_mtp.c
class/usbd_mtp_class.c
)

zephyr_linker_sources(DATA_SECTIONS usbd_data.ld)
1 change: 1 addition & 0 deletions subsys/usb/device_next/class/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ rsource "Kconfig.hid"
rsource "Kconfig.midi2"
rsource "Kconfig.dfu"
rsource "Kconfig.uvc"
rsource "Kconfig.mtp"
35 changes: 35 additions & 0 deletions subsys/usb/device_next/class/Kconfig.mtp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright (c) 2025 Mohamed ElShahawi (extremegtx@hotmail.com)
#
# SPDX-License-Identifier: Apache-2.0

config USBD_MTP_CLASS
bool "USB MTP Class"
help
USB Media Transfer Protocol Device Class support.
Allow file transfer independent of storage file system.

if USBD_MTP_CLASS

config USBD_MTP_MAX_HANDLES
int "Max number of Object handles per Storage"
default 10
help
Maximum number of objects to be handled by MTP, including
stored, removed and added objects.

config RECYCLE_OBJECT_HANDLES
bool "Recycle Object Handles"
default n
help
Recycle object handles when the maximum number of objects is reached.
If disabled, new objects will not be added when the maximum number of
objects is reached. Although this option provide better usability,
it is against the MTP specification.

module = USBD_MTP
module-str = usbd mtp
default-count = 1
source "subsys/logging/Kconfig.template.log_config"

rsource "Kconfig.template.instances_count"
endif
Loading
Loading