Skip to content

Commit 7874f45

Browse files
committed
USB: Device_next: Add USB MTP class support
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 <[email protected]>
1 parent df53184 commit 7874f45

File tree

16 files changed

+2280
-0
lines changed

16 files changed

+2280
-0
lines changed

dts/bindings/fs/zephyr,fstab-common.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,8 @@ properties:
4949
5050
This causes the FS_MOUNT_FLAG_USE_DISK_ACCESS option to be set in
5151
the mount descriptor generated for the file system.
52+
53+
mtp-enabled:
54+
type: boolean
55+
description: |
56+
Provide File system access over USB MTP Protocol

include/zephyr/usb/usb_ch9.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ struct usb_association_descriptor {
257257
#define USB_BCC_AUDIO 0x01
258258
#define USB_BCC_CDC_CONTROL 0x02
259259
#define USB_BCC_HID 0x03
260+
#define USB_BCC_IMAGE 0x06
260261
#define USB_BCC_MASS_STORAGE 0x08
261262
#define USB_BCC_CDC_DATA 0x0A
262263
#define USB_BCC_VIDEO 0x0E

samples/subsys/usb/mtp/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(mtp)
6+
7+
include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)
8+
FILE(GLOB app_sources src/*.c)
9+
target_sources(app PRIVATE ${app_sources})

samples/subsys/usb/mtp/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2023 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Source common USB sample options used to initialize new experimental USB
5+
# device stack. The scope of these options is limited to USB samples in project
6+
# tree, you cannot use them in your own application.
7+
source "samples/subsys/usb/common/Kconfig.sample_usbd"
8+
9+
source "Kconfig.zephyr"

samples/subsys/usb/mtp/README.rst

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
.. zephyr:code-sample:: usb-cdc-acm
2+
:name: USB CDC-ACM
3+
:relevant-api: usbd_api _usb_device_core_api uart_interface
4+
5+
Use USB CDC-ACM driver to implement a serial port echo.
6+
7+
Overview
8+
********
9+
10+
This sample app demonstrates use of a USB Communication Device Class (CDC)
11+
Abstract Control Model (ACM) driver provided by the Zephyr project.
12+
Received data from the serial port is echoed back to the same port
13+
provided by this driver.
14+
This sample can be found under :zephyr_file:`samples/subsys/usb/cdc_acm` in the
15+
Zephyr project tree.
16+
17+
Requirements
18+
************
19+
20+
This project requires an USB device driver, which is available for multiple
21+
boards supported in Zephyr.
22+
23+
Building and Running
24+
********************
25+
26+
Reel Board
27+
===========
28+
29+
To see the console output of the app, open a serial port emulator and
30+
attach it to the USB to TTL Serial cable. Build and flash the project:
31+
32+
.. zephyr-app-commands::
33+
:zephyr-app: samples/subsys/usb/cdc_acm
34+
:board: reel_board
35+
:goals: flash
36+
:compact:
37+
38+
Running
39+
=======
40+
41+
Plug the board into a host device, for example, a PC running Linux.
42+
The board will be detected as shown by the Linux dmesg command:
43+
44+
.. code-block:: console
45+
46+
usb 9-1: new full-speed USB device number 112 using uhci_hcd
47+
usb 9-1: New USB device found, idVendor=8086, idProduct=f8a1
48+
usb 9-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
49+
usb 9-1: Product: CDC-ACM
50+
usb 9-1: Manufacturer: Intel
51+
usb 9-1: SerialNumber: 00.01
52+
cdc_acm 9-1:1.0: ttyACM1: USB ACM device
53+
54+
The app prints on serial output (UART1), used for the console:
55+
56+
.. code-block:: console
57+
58+
Wait for DTR
59+
60+
Open a serial port emulator, for example minicom
61+
and attach it to detected CDC ACM device:
62+
63+
.. code-block:: console
64+
65+
minicom --device /dev/ttyACM1
66+
67+
The app should respond on serial output with:
68+
69+
.. code-block:: console
70+
71+
DTR set, start test
72+
Baudrate detected: 115200
73+
74+
And on ttyACM device, provided by zephyr USB device stack:
75+
76+
.. code-block:: console
77+
78+
Send characters to the UART device
79+
Characters read:
80+
81+
The characters entered in serial port emulator will be echoed back.
82+
83+
Troubleshooting
84+
===============
85+
86+
If the ModemManager runs on your operating system, it will try
87+
to access the CDC ACM device and maybe you can see several characters
88+
including "AT" on the terminal attached to the CDC ACM device.
89+
You can add or extend the udev rule for your board to inform
90+
ModemManager to skip the CDC ACM device.
91+
For this example, it would look like this:
92+
93+
.. code-block:: none
94+
95+
ATTRS{idVendor}=="8086" ATTRS{idProduct}=="f8a1", ENV{ID_MM_DEVICE_IGNORE}="1"
96+
97+
You can use
98+
``/lib/udev/rules.d/77-mm-usb-device-blacklist.rules`` as reference.

samples/subsys/usb/mtp/app.overlay

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/ {
2+
fstab {
3+
compatible = "zephyr,fstab";
4+
lfs1: lfs1 {
5+
compatible = "zephyr,fstab,littlefs";
6+
read-size = <32>;
7+
prog-size = <32>;
8+
cache-size = <256>;
9+
lookahead-size = <64>;
10+
block-cycles = <512>;
11+
partition = <&storage_partition>;
12+
mount-point = "/lfs1";
13+
automount;
14+
mtp-enabled;
15+
};
16+
};
17+
};
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
2+
/delete-node/ &storage_partition;
3+
4+
5+
&mx25l51245g {
6+
partitions {
7+
compatible = "fixed-partitions";
8+
#address-cells = <1>;
9+
#size-cells = <1>;
10+
11+
storage_partition: partition@1a0000 {
12+
label = "storage";
13+
reg = <0x001a0000 DT_SIZE_M(40)>;
14+
};
15+
storage_partition2: partition@2ba0000 {
16+
label = "storage2";
17+
reg = <0x2ba0000 DT_SIZE_M(20)>;
18+
};
19+
};
20+
};
21+
22+
23+
24+
/ {
25+
fstab {
26+
compatible = "zephyr,fstab";
27+
lfs1: lfs1 {
28+
compatible = "zephyr,fstab,littlefs";
29+
read-size = <32>;
30+
prog-size = <32>;
31+
cache-size = <256>;
32+
lookahead-size = <64>;
33+
block-cycles = <512>;
34+
partition = <&storage_partition>;
35+
mount-point = "/lfs1";
36+
automount;
37+
mtp-enabled;
38+
};
39+
lfs2: lfs2 {
40+
compatible = "zephyr,fstab,littlefs";
41+
read-size = <32>;
42+
prog-size = <32>;
43+
cache-size = <256>;
44+
lookahead-size = <64>;
45+
block-cycles = <512>;
46+
partition = <&storage_partition2>;
47+
mount-point = "/lfs2";
48+
automount;
49+
mtp-enabled;
50+
};
51+
// Not Working
52+
// sd0: sd0 {
53+
// compatible = "zephyr,fstab-common";
54+
// partition = <&sdmmc2>;
55+
// mount-point = "/SD:";
56+
// automount;
57+
// };
58+
};
59+
};

samples/subsys/usb/mtp/prj.conf

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
CONFIG_USB_DEVICE_STACK_NEXT=y
2+
CONFIG_STDOUT_CONSOLE=y
3+
CONFIG_USBD_MTP_CLASS=y
4+
CONFIG_USBD_MTP_MAX_HANDLES=30
5+
6+
CONFIG_LOG=y
7+
#CONFIG_USBD_LOG_LEVEL_WRN=y
8+
CONFIG_SAMPLE_USBD_PRODUCT="USBD MTP sample"
9+
CONFIG_SAMPLE_USBD_PID=0x0009
10+
11+
12+
13+
14+
15+
16+
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
17+
18+
CONFIG_FLASH=y
19+
CONFIG_FLASH_MAP=y
20+
21+
CONFIG_MAIN_STACK_SIZE=2048
22+
CONFIG_FILE_SYSTEM=y
23+
CONFIG_FILE_SYSTEM_MKFS=y
24+
CONFIG_FILE_SYSTEM_LITTLEFS=y
25+
#CONFIG_FS_LITTLEFS_FMP_DEV=y
26+
27+
CONFIG_SHELL=y
28+
CONFIG_FILE_SYSTEM_SHELL=y
29+
CONFIG_HEAP_MEM_POOL_SIZE=16384
30+
31+
#CONFIG_DISK_DRIVERS=y
32+
#CONFIG_DISK_ACCESS=y
33+
#CONFIG_DISK_DRIVER_FLASH=y
34+
35+
#CONFIG_USB_DEVICE_LOG_LEVEL_DBG=y
36+
CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=5
37+
CONFIG_LOG_BUFFER_SIZE=65536
38+
39+
CONFIG_USBD_LOG_LEVEL_WRN=y
40+
#CONFIG_USBD_LOG_LEVEL_DBG=y
41+
42+
#CONFIG_SAMPLE_USBD_PID=0x6860
43+
#CONFIG_SAMPLE_USBD_PRODUCT="SAMSUNG_Android"
44+
#CONFIG_SAMPLE_USBD_MANUFACTURER="SAMSUNG"
45+
46+
47+
#SDCARD
48+
CONFIG_DISK_ACCESS=y
49+
CONFIG_DISK_DRIVER_SDMMC=y
50+
CONFIG_SDMMC_STM32=y
51+
CONFIG_SDMMC_SUBSYS=y
52+
53+
54+
CONFIG_FAT_FILESYSTEM_ELM=y
55+
56+
CONFIG_USBD_THREAD_STACK_SIZE=2048
57+
58+
59+
CONFIG_OUTPUT_DISASSEMBLY=y
60+
CONFIG_OUTPUT_DISASSEMBLY_WITH_SOURCE=y
61+
CONFIG_FLASH_SHELL=y
62+
CONFIG_HWINFO_SHELL=y
63+
CONFIG_LOG_CMDS=y
64+
CONFIG_USBD_MTP_LOG_LEVEL_DBG=y

samples/subsys/usb/mtp/sample.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
sample:
2+
name: MTP USB
3+
tests:
4+
sample.usb.mtp:
5+
depends_on: usb_device
6+
tags: usb
7+
arch_exclude: posix
8+
harness: console
9+
harness_config:
10+
type: one_line
11+
regex:
12+
- "Wait for DTR"
13+
sample.usb_device_next.mtp:
14+
depends_on: usbd
15+
tags: usb
16+
extra_args: CONF_FILE="usbd_next_prj.conf"
17+
integration_platforms:
18+
- nrf52840dk/nrf52840
19+
- nrf54h20dk/nrf54h20/cpuapp
20+
- frdm_k64f
21+
- stm32f723e_disco
22+
- nucleo_f413zh
23+
- mimxrt685_evk/mimxrt685s/cm33
24+
- mimxrt1060_evk
25+
harness: console
26+
harness_config:
27+
type: one_line
28+
regex:
29+
- "Wait for DTR"
30+
sample.usb.mtp.buildonly:
31+
depends_on: usb_device
32+
tags: usb
33+
arch_allow: posix
34+
build_only: true
35+
integration_platforms:
36+
- native_sim

samples/subsys/usb/mtp/src/main.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2019 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file
9+
* @brief Sample echo app for MTP class
10+
*
11+
* Sample app for USB MTP class driver.
12+
*/
13+
14+
#include <sample_usbd.h>
15+
16+
#include <stdio.h>
17+
#include <string.h>
18+
#include <zephyr/device.h>
19+
#include <zephyr/kernel.h>
20+
21+
#include <zephyr/usb/usb_device.h>
22+
#include <zephyr/usb/usbd.h>
23+
#include <zephyr/logging/log.h>
24+
LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
25+
26+
static struct usbd_context *sample_usbd;
27+
28+
static void sample_msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg)
29+
{
30+
LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type));
31+
32+
if (usbd_can_detect_vbus(ctx)) {
33+
if (msg->type == USBD_MSG_VBUS_READY) {
34+
if (usbd_enable(ctx)) {
35+
LOG_ERR("Failed to enable device support");
36+
}
37+
}
38+
39+
if (msg->type == USBD_MSG_VBUS_REMOVED) {
40+
if (usbd_disable(ctx)) {
41+
LOG_ERR("Failed to disable device support");
42+
}
43+
}
44+
}
45+
}
46+
47+
static int enable_usb_device_next(void)
48+
{
49+
int err;
50+
51+
sample_usbd = sample_usbd_init_device(sample_msg_cb);
52+
if (sample_usbd == NULL) {
53+
LOG_ERR("Failed to initialize USB device");
54+
return -ENODEV;
55+
}
56+
57+
if (!usbd_can_detect_vbus(sample_usbd)) {
58+
err = usbd_enable(sample_usbd);
59+
if (err) {
60+
LOG_ERR("Failed to enable device support");
61+
return err;
62+
}
63+
}
64+
65+
LOG_INF("USB device support enabled");
66+
67+
return 0;
68+
}
69+
70+
71+
int main(void)
72+
{
73+
int ret;
74+
75+
ret = enable_usb_device_next();
76+
77+
return 0;
78+
}

0 commit comments

Comments
 (0)