Bladeren bron

feat(class/mtp): support mtp device

Signed-off-by: sakumisu <1203593632@qq.com>
sakumisu 7 maanden geleden
bovenliggende
commit
fe24f8d4ba

+ 5 - 0
Kconfig

@@ -118,6 +118,11 @@ if CHERRYUSB
             prompt "Enable usb cdc ncm device"
             prompt "Enable usb cdc ncm device"
             default n
             default n
 
 
+        config CHERRYUSB_DEVICE_MTP
+            bool
+            prompt "Enable usb mtp device, it is commercial charge"
+            default n
+
         config CHERRYUSB_DEVICE_DFU
         config CHERRYUSB_DEVICE_DFU
             bool
             bool
             prompt "Enable usb dfu device"
             prompt "Enable usb dfu device"

+ 5 - 0
Kconfig.rtt

@@ -120,6 +120,11 @@ if RT_USING_CHERRYUSB
             prompt "Enable usb cdc ncm device"
             prompt "Enable usb cdc ncm device"
             default n
             default n
 
 
+        config RT_CHERRYUSB_DEVICE_MTP
+            bool
+            prompt "Enable usb mtp device, it is commercial charge"
+            default n
+
         config RT_CHERRYUSB_DEVICE_DFU
         config RT_CHERRYUSB_DEVICE_DFU
             bool
             bool
             prompt "Enable usb dfu device"
             prompt "Enable usb dfu device"

+ 5 - 0
Kconfig.rttpkg

@@ -119,6 +119,11 @@ if PKG_USING_CHERRYUSB
             prompt "Enable usb cdc ncm device"
             prompt "Enable usb cdc ncm device"
             default n
             default n
 
 
+        config PKG_CHERRYUSB_DEVICE_MTP
+            bool
+            prompt "Enable usb mtp device, it is commercial charge"
+            default n
+
         config PKG_CHERRYUSB_DEVICE_DFU
         config PKG_CHERRYUSB_DEVICE_DFU
             bool
             bool
             prompt "Enable usb dfu device"
             prompt "Enable usb dfu device"

+ 2 - 0
README.md

@@ -71,6 +71,7 @@ CherryUSB Device Stack has the following functions:
 - Support Device Firmware Upgrade CLASS (DFU)
 - Support Device Firmware Upgrade CLASS (DFU)
 - Support USB MIDI CLASS (MIDI)
 - Support USB MIDI CLASS (MIDI)
 - Support Remote NDIS (RNDIS)
 - Support Remote NDIS (RNDIS)
+- Support Media Transfer Protocol (MTP)
 - Support WINUSB1.0, WINUSB2.0, WEBUSB, BOS
 - Support WINUSB1.0, WINUSB2.0, WEBUSB, BOS
 - Support Vendor class
 - Support Vendor class
 - Support UF2
 - Support UF2
@@ -88,6 +89,7 @@ CherryUSB Device Stack resource usage (GCC 10.2 with -O2):
 |usbd_audio.c   |  ~1500          | 0                         | 0            | 0                |
 |usbd_audio.c   |  ~1500          | 0                         | 0            | 0                |
 |usbd_video.c   |  ~3700          | 0                         | 132 * bus    | 0                |
 |usbd_video.c   |  ~3700          | 0                         | 132 * bus    | 0                |
 |usbd_rndis.c   |  ~4000          | 2 * 1580(default)+156+8   | 80           | 0                |
 |usbd_rndis.c   |  ~4000          | 2 * 1580(default)+156+8   | 80           | 0                |
+|usbd_mtp.c     |  ~9000          | 2048(default)+128         | sizeof(struct mtp_object) * n| 0 |
 
 
 ## Host Stack Overview
 ## Host Stack Overview
 
 

+ 2 - 0
README_zh.md

@@ -71,6 +71,7 @@ CherryUSB Device 协议栈当前实现以下功能:
 - 支持 Device Firmware Upgrade CLASS (DFU)
 - 支持 Device Firmware Upgrade CLASS (DFU)
 - 支持 USB MIDI CLASS (MIDI)
 - 支持 USB MIDI CLASS (MIDI)
 - 支持 Remote NDIS (RNDIS)
 - 支持 Remote NDIS (RNDIS)
+- 支持 Media Transfer Protocol (MTP)
 - 支持 WINUSB1.0、WINUSB2.0、WEBUSB、BOS
 - 支持 WINUSB1.0、WINUSB2.0、WEBUSB、BOS
 - 支持 Vendor 类 class
 - 支持 Vendor 类 class
 - 支持 UF2
 - 支持 UF2
@@ -88,6 +89,7 @@ CherryUSB Device 协议栈资源占用说明(GCC 10.2 with -O2):
 |usbd_audio.c   |  ~1500          | 0                         | 0            | 0                |
 |usbd_audio.c   |  ~1500          | 0                         | 0            | 0                |
 |usbd_video.c   |  ~3700          | 0                         | 132 * bus    | 0                |
 |usbd_video.c   |  ~3700          | 0                         | 132 * bus    | 0                |
 |usbd_rndis.c   |  ~4000          | 2 * 1580(default)+156+8   | 80           | 0                |
 |usbd_rndis.c   |  ~4000          | 2 * 1580(default)+156+8   | 80           | 0                |
+|usbd_mtp.c     |  ~9000          | 2048(default)+128         | sizeof(struct mtp_object) * n| 0 |
 
 
 ## Host 协议栈简介
 ## Host 协议栈简介
 
 

+ 22 - 0
cherryusb_config_template.h

@@ -107,6 +107,28 @@
 #define CONFIG_USBDEV_MSC_STACKSIZE 2048
 #define CONFIG_USBDEV_MSC_STACKSIZE 2048
 #endif
 #endif
 
 
+#ifndef CONFIG_USBDEV_MTP_MAX_BUFSIZE
+#define CONFIG_USBDEV_MTP_MAX_BUFSIZE 2048
+#endif
+
+#ifndef CONFIG_USBDEV_MTP_MAX_OBJECTS
+#define CONFIG_USBDEV_MTP_MAX_OBJECTS 256
+#endif
+
+#ifndef CONFIG_USBDEV_MTP_MAX_PATHNAME
+#define CONFIG_USBDEV_MTP_MAX_PATHNAME 256
+#endif
+
+#define CONFIG_USBDEV_MTP_THREAD
+
+#ifndef CONFIG_USBDEV_MTP_PRIO
+#define CONFIG_USBDEV_MTP_PRIO 4
+#endif
+
+#ifndef CONFIG_USBDEV_MTP_STACKSIZE
+#define CONFIG_USBDEV_MTP_STACKSIZE 4096
+#endif
+
 #ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
 #ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
 #define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
 #define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
 #endif
 #endif

+ 683 - 0
class/mtp/usb_mtp.h

@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (c) 2025, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_MTP_H
+#define USB_MTP_H
+
+// clang-format off
+#define MTP_STANDARD_VERSION            100
+
+// Container Types
+#define MTP_CONTAINER_TYPE_UNDEFINED    0
+#define MTP_CONTAINER_TYPE_COMMAND      1
+#define MTP_CONTAINER_TYPE_DATA         2
+#define MTP_CONTAINER_TYPE_RESPONSE     3
+#define MTP_CONTAINER_TYPE_EVENT        4
+
+// Container Offsets
+#define MTP_CONTAINER_LENGTH_OFFSET             0
+#define MTP_CONTAINER_TYPE_OFFSET               4
+#define MTP_CONTAINER_CODE_OFFSET               6
+#define MTP_CONTAINER_TRANSACTION_ID_OFFSET     8
+#define MTP_CONTAINER_PARAMETER_OFFSET          12
+#define MTP_CONTAINER_HEADER_SIZE               12
+
+// Maximum buffer size for a MTP packet.
+#define MTP_BUFFER_SIZE 16384
+
+// MTP Data Types
+#define MTP_TYPE_UNDEFINED      0x0000          // Undefined
+#define MTP_TYPE_INT8           0x0001          // Signed 8-bit integer
+#define MTP_TYPE_UINT8          0x0002          // Unsigned 8-bit integer
+#define MTP_TYPE_INT16          0x0003          // Signed 16-bit integer
+#define MTP_TYPE_UINT16         0x0004          // Unsigned 16-bit integer
+#define MTP_TYPE_INT32          0x0005          // Signed 32-bit integer
+#define MTP_TYPE_UINT32         0x0006          // Unsigned 32-bit integer
+#define MTP_TYPE_INT64          0x0007          // Signed 64-bit integer
+#define MTP_TYPE_UINT64         0x0008          // Unsigned 64-bit integer
+#define MTP_TYPE_INT128         0x0009          // Signed 128-bit integer
+#define MTP_TYPE_UINT128        0x000A          // Unsigned 128-bit integer
+#define MTP_TYPE_AINT8          0x4001          // Array of signed 8-bit integers
+#define MTP_TYPE_AUINT8         0x4002          // Array of unsigned 8-bit integers
+#define MTP_TYPE_AINT16         0x4003          // Array of signed 16-bit integers
+#define MTP_TYPE_AUINT16        0x4004          // Array of unsigned 16-bit integers
+#define MTP_TYPE_AINT32         0x4005          // Array of signed 32-bit integers
+#define MTP_TYPE_AUINT32        0x4006          // Array of unsigned 32-bit integers
+#define MTP_TYPE_AINT64         0x4007          // Array of signed 64-bit integers
+#define MTP_TYPE_AUINT64        0x4008          // Array of unsigned 64-bit integers
+#define MTP_TYPE_AINT128        0x4009          // Array of signed 128-bit integers
+#define MTP_TYPE_AUINT128       0x400A          // Array of unsigned 128-bit integers
+#define MTP_TYPE_STR            0xFFFF          // Variable-length Unicode string
+
+// MTP Format Codes
+#define MTP_FORMAT_UNDEFINED                            0x3000   // Undefined object
+#define MTP_FORMAT_ASSOCIATION                          0x3001   // Association (for example, a folder)
+#define MTP_FORMAT_SCRIPT                               0x3002   // Device model-specific script
+#define MTP_FORMAT_EXECUTABLE                           0x3003   // Device model-specific binary executable
+#define MTP_FORMAT_TEXT                                 0x3004   // Text file
+#define MTP_FORMAT_HTML                                 0x3005   // Hypertext Markup Language file (text)
+#define MTP_FORMAT_DPOF                                 0x3006   // Digital Print Order Format file (text)
+#define MTP_FORMAT_AIFF                                 0x3007   // Audio clip
+#define MTP_FORMAT_WAV                                  0x3008   // Audio clip
+#define MTP_FORMAT_MP3                                  0x3009   // Audio clip
+#define MTP_FORMAT_AVI                                  0x300A   // Video clip
+#define MTP_FORMAT_MPEG                                 0x300B   // Video clip
+#define MTP_FORMAT_ASF                                  0x300C   // Microsoft Advanced Streaming Format (video)
+#define MTP_FORMAT_DEFINED                              0x3800   // Unknown image object
+#define MTP_FORMAT_EXIF_JPEG                            0x3801   // Exchangeable File Format, JEIDA standard
+#define MTP_FORMAT_TIFF_EP                              0x3802   // Tag Image File Format for Electronic Photography
+#define MTP_FORMAT_FLASHPIX                             0x3803   // Structured Storage Image Format
+#define MTP_FORMAT_BMP                                  0x3804   // Microsoft Windows Bitmap file
+#define MTP_FORMAT_CIFF                                 0x3805   // Canon Camera Image File Format
+#define MTP_FORMAT_GIF                                  0x3807   // Graphics Interchange Format
+#define MTP_FORMAT_JFIF                                 0x3808   // JPEG File Interchange Format
+#define MTP_FORMAT_CD                                   0x3809   // PhotoCD Image Pac
+#define MTP_FORMAT_PICT                                 0x380A   // Quickdraw Image Format
+#define MTP_FORMAT_PNG                                  0x380B   // Portable Network Graphics
+#define MTP_FORMAT_TIFF                                 0x380D   // Tag Image File Format
+#define MTP_FORMAT_TIFF_IT                              0x380E   // Tag Image File Format for Information Technology (graphic arts)
+#define MTP_FORMAT_JP2                                  0x380F   // JPEG2000 Baseline File Format
+#define MTP_FORMAT_JPX                                  0x3810   // JPEG2000 Extended File Format
+#define MTP_FORMAT_DNG                                  0x3811   // Digital Negative
+#define MTP_FORMAT_HEIF                                 0x3812   // HEIF images
+#define MTP_FORMAT_UNDEFINED_FIRMWARE                   0xB802
+#define MTP_FORMAT_WINDOWS_IMAGE_FORMAT                 0xB881
+#define MTP_FORMAT_UNDEFINED_AUDIO                      0xB900
+#define MTP_FORMAT_WMA                                  0xB901
+#define MTP_FORMAT_OGG                                  0xB902
+#define MTP_FORMAT_AAC                                  0xB903
+#define MTP_FORMAT_AUDIBLE                              0xB904
+#define MTP_FORMAT_FLAC                                 0xB906
+#define MTP_FORMAT_UNDEFINED_VIDEO                      0xB980
+#define MTP_FORMAT_WMV                                  0xB981
+#define MTP_FORMAT_MP4_CONTAINER                        0xB982  // ISO 14496-1
+#define MTP_FORMAT_MP2                                  0xB983
+#define MTP_FORMAT_3GP_CONTAINER                        0xB984  // 3GPP file format. Details: http://www.3gpp.org/ftp/Specs/html-info/26244.htm (page title - \u201cTransparent end-to-end packet switched streaming service, 3GPP file format\u201d).
+#define MTP_FORMAT_UNDEFINED_COLLECTION                 0xBA00
+#define MTP_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM            0xBA01
+#define MTP_FORMAT_ABSTRACT_IMAGE_ALBUM                 0xBA02
+#define MTP_FORMAT_ABSTRACT_AUDIO_ALBUM                 0xBA03
+#define MTP_FORMAT_ABSTRACT_VIDEO_ALBUM                 0xBA04
+#define MTP_FORMAT_ABSTRACT_AV_PLAYLIST                 0xBA05
+#define MTP_FORMAT_ABSTRACT_CONTACT_GROUP               0xBA06
+#define MTP_FORMAT_ABSTRACT_MESSAGE_FOLDER              0xBA07
+#define MTP_FORMAT_ABSTRACT_CHAPTERED_PRODUCTION        0xBA08
+#define MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST              0xBA09
+#define MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST              0xBA0A
+#define MTP_FORMAT_ABSTRACT_MEDIACAST                   0xBA0B // For use with mediacasts; references multimedia enclosures of RSS feeds or episodic content
+#define MTP_FORMAT_WPL_PLAYLIST                         0xBA10
+#define MTP_FORMAT_M3U_PLAYLIST                         0xBA11
+#define MTP_FORMAT_MPL_PLAYLIST                         0xBA12
+#define MTP_FORMAT_ASX_PLAYLIST                         0xBA13
+#define MTP_FORMAT_PLS_PLAYLIST                         0xBA14
+#define MTP_FORMAT_UNDEFINED_DOCUMENT                   0xBA80
+#define MTP_FORMAT_ABSTRACT_DOCUMENT                    0xBA81
+#define MTP_FORMAT_XML_DOCUMENT                         0xBA82
+#define MTP_FORMAT_MS_WORD_DOCUMENT                     0xBA83
+#define MTP_FORMAT_MHT_COMPILED_HTML_DOCUMENT           0xBA84
+#define MTP_FORMAT_MS_EXCEL_SPREADSHEET                 0xBA85
+#define MTP_FORMAT_MS_POWERPOINT_PRESENTATION           0xBA86
+#define MTP_FORMAT_UNDEFINED_MESSAGE                    0xBB00
+#define MTP_FORMAT_ABSTRACT_MESSSAGE                    0xBB01
+#define MTP_FORMAT_UNDEFINED_CONTACT                    0xBB80
+#define MTP_FORMAT_ABSTRACT_CONTACT                     0xBB81
+#define MTP_FORMAT_VCARD_2                              0xBB82
+
+// MTP Object Property Codes
+#define MTP_PROPERTY_STORAGE_ID                             0xDC01
+#define MTP_PROPERTY_OBJECT_FORMAT                          0xDC02
+#define MTP_PROPERTY_PROTECTION_STATUS                      0xDC03
+#define MTP_PROPERTY_OBJECT_SIZE                            0xDC04
+#define MTP_PROPERTY_ASSOCIATION_TYPE                       0xDC05
+#define MTP_PROPERTY_ASSOCIATION_DESC                       0xDC06
+#define MTP_PROPERTY_OBJECT_FILE_NAME                       0xDC07
+#define MTP_PROPERTY_DATE_CREATED                           0xDC08
+#define MTP_PROPERTY_DATE_MODIFIED                          0xDC09
+#define MTP_PROPERTY_KEYWORDS                               0xDC0A
+#define MTP_PROPERTY_PARENT_OBJECT                          0xDC0B
+#define MTP_PROPERTY_ALLOWED_FOLDER_CONTENTS                0xDC0C
+#define MTP_PROPERTY_HIDDEN                                 0xDC0D
+#define MTP_PROPERTY_SYSTEM_OBJECT                          0xDC0E
+#define MTP_PROPERTY_PERSISTENT_UID                         0xDC41
+#define MTP_PROPERTY_SYNC_ID                                0xDC42
+#define MTP_PROPERTY_PROPERTY_BAG                           0xDC43
+#define MTP_PROPERTY_NAME                                   0xDC44
+#define MTP_PROPERTY_CREATED_BY                             0xDC45
+#define MTP_PROPERTY_ARTIST                                 0xDC46
+#define MTP_PROPERTY_DATE_AUTHORED                          0xDC47
+#define MTP_PROPERTY_DESCRIPTION                            0xDC48
+#define MTP_PROPERTY_URL_REFERENCE                          0xDC49
+#define MTP_PROPERTY_LANGUAGE_LOCALE                        0xDC4A
+#define MTP_PROPERTY_COPYRIGHT_INFORMATION                  0xDC4B
+#define MTP_PROPERTY_SOURCE                                 0xDC4C
+#define MTP_PROPERTY_ORIGIN_LOCATION                        0xDC4D
+#define MTP_PROPERTY_DATE_ADDED                             0xDC4E
+#define MTP_PROPERTY_NON_CONSUMABLE                         0xDC4F
+#define MTP_PROPERTY_CORRUPT_UNPLAYABLE                     0xDC50
+#define MTP_PROPERTY_PRODUCER_SERIAL_NUMBER                 0xDC51
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_FORMAT           0xDC81
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_SIZE             0xDC82
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_HEIGHT           0xDC83
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_WIDTH            0xDC84
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DURATION         0xDC85
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DATA             0xDC86
+#define MTP_PROPERTY_WIDTH                                  0xDC87
+#define MTP_PROPERTY_HEIGHT                                 0xDC88
+#define MTP_PROPERTY_DURATION                               0xDC89
+#define MTP_PROPERTY_RATING                                 0xDC8A
+#define MTP_PROPERTY_TRACK                                  0xDC8B
+#define MTP_PROPERTY_GENRE                                  0xDC8C
+#define MTP_PROPERTY_CREDITS                                0xDC8D
+#define MTP_PROPERTY_LYRICS                                 0xDC8E
+#define MTP_PROPERTY_SUBSCRIPTION_CONTENT_ID                0xDC8F
+#define MTP_PROPERTY_PRODUCED_BY                            0xDC90
+#define MTP_PROPERTY_USE_COUNT                              0xDC91
+#define MTP_PROPERTY_SKIP_COUNT                             0xDC92
+#define MTP_PROPERTY_LAST_ACCESSED                          0xDC93
+#define MTP_PROPERTY_PARENTAL_RATING                        0xDC94
+#define MTP_PROPERTY_META_GENRE                             0xDC95
+#define MTP_PROPERTY_COMPOSER                               0xDC96
+#define MTP_PROPERTY_EFFECTIVE_RATING                       0xDC97
+#define MTP_PROPERTY_SUBTITLE                               0xDC98
+#define MTP_PROPERTY_ORIGINAL_RELEASE_DATE                  0xDC99
+#define MTP_PROPERTY_ALBUM_NAME                             0xDC9A
+#define MTP_PROPERTY_ALBUM_ARTIST                           0xDC9B
+#define MTP_PROPERTY_MOOD                                   0xDC9C
+#define MTP_PROPERTY_DRM_STATUS                             0xDC9D
+#define MTP_PROPERTY_SUB_DESCRIPTION                        0xDC9E
+#define MTP_PROPERTY_IS_CROPPED                             0xDCD1
+#define MTP_PROPERTY_IS_COLOUR_CORRECTED                    0xDCD2
+#define MTP_PROPERTY_IMAGE_BIT_DEPTH                        0xDCD3
+#define MTP_PROPERTY_F_NUMBER                               0xDCD4
+#define MTP_PROPERTY_EXPOSURE_TIME                          0xDCD5
+#define MTP_PROPERTY_EXPOSURE_INDEX                         0xDCD6
+#define MTP_PROPERTY_TOTAL_BITRATE                          0xDE91
+#define MTP_PROPERTY_BITRATE_TYPE                           0xDE92
+#define MTP_PROPERTY_SAMPLE_RATE                            0xDE93
+#define MTP_PROPERTY_NUMBER_OF_CHANNELS                     0xDE94
+#define MTP_PROPERTY_AUDIO_BIT_DEPTH                        0xDE95
+#define MTP_PROPERTY_SCAN_TYPE                              0xDE97
+#define MTP_PROPERTY_AUDIO_WAVE_CODEC                       0xDE99
+#define MTP_PROPERTY_AUDIO_BITRATE                          0xDE9A
+#define MTP_PROPERTY_VIDEO_FOURCC_CODEC                     0xDE9B
+#define MTP_PROPERTY_VIDEO_BITRATE                          0xDE9C
+#define MTP_PROPERTY_FRAMES_PER_THOUSAND_SECONDS            0xDE9D
+#define MTP_PROPERTY_KEYFRAME_DISTANCE                      0xDE9E
+#define MTP_PROPERTY_BUFFER_SIZE                            0xDE9F
+#define MTP_PROPERTY_ENCODING_QUALITY                       0xDEA0
+#define MTP_PROPERTY_ENCODING_PROFILE                       0xDEA1
+#define MTP_PROPERTY_DISPLAY_NAME                           0xDCE0
+#define MTP_PROPERTY_BODY_TEXT                              0xDCE1
+#define MTP_PROPERTY_SUBJECT                                0xDCE2
+#define MTP_PROPERTY_PRIORITY                               0xDCE3
+#define MTP_PROPERTY_GIVEN_NAME                             0xDD00
+#define MTP_PROPERTY_MIDDLE_NAMES                           0xDD01
+#define MTP_PROPERTY_FAMILY_NAME                            0xDD02
+#define MTP_PROPERTY_PREFIX                                 0xDD03
+#define MTP_PROPERTY_SUFFIX                                 0xDD04
+#define MTP_PROPERTY_PHONETIC_GIVEN_NAME                    0xDD05
+#define MTP_PROPERTY_PHONETIC_FAMILY_NAME                   0xDD06
+#define MTP_PROPERTY_EMAIL_PRIMARY                          0xDD07
+#define MTP_PROPERTY_EMAIL_PERSONAL_1                       0xDD08
+#define MTP_PROPERTY_EMAIL_PERSONAL_2                       0xDD09
+#define MTP_PROPERTY_EMAIL_BUSINESS_1                       0xDD0A
+#define MTP_PROPERTY_EMAIL_BUSINESS_2                       0xDD0B
+#define MTP_PROPERTY_EMAIL_OTHERS                           0xDD0C
+#define MTP_PROPERTY_PHONE_NUMBER_PRIMARY                   0xDD0D
+#define MTP_PROPERTY_PHONE_NUMBER_PERSONAL                  0xDD0E
+#define MTP_PROPERTY_PHONE_NUMBER_PERSONAL_2                0xDD0F
+#define MTP_PROPERTY_PHONE_NUMBER_BUSINESS                  0xDD10
+#define MTP_PROPERTY_PHONE_NUMBER_BUSINESS_2                0xDD11
+#define MTP_PROPERTY_PHONE_NUMBER_MOBILE                    0xDD12
+#define MTP_PROPERTY_PHONE_NUMBER_MOBILE_2                  0xDD13
+#define MTP_PROPERTY_FAX_NUMBER_PRIMARY                     0xDD14
+#define MTP_PROPERTY_FAX_NUMBER_PERSONAL                    0xDD15
+#define MTP_PROPERTY_FAX_NUMBER_BUSINESS                    0xDD16
+#define MTP_PROPERTY_PAGER_NUMBER                           0xDD17
+#define MTP_PROPERTY_PHONE_NUMBER_OTHERS                    0xDD18
+#define MTP_PROPERTY_PRIMARY_WEB_ADDRESS                    0xDD19
+#define MTP_PROPERTY_PERSONAL_WEB_ADDRESS                   0xDD1A
+#define MTP_PROPERTY_BUSINESS_WEB_ADDRESS                   0xDD1B
+#define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS              0xDD1C
+#define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_2            0xDD1D
+#define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_3            0xDD1E
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_FULL           0xDD1F
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_1         0xDD20
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_2         0xDD21
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_CITY           0xDD22
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_REGION         0xDD23
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_POSTAL_CODE    0xDD24
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_COUNTRY        0xDD25
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_FULL           0xDD26
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_1         0xDD27
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_2         0xDD28
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_CITY           0xDD29
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_REGION         0xDD2A
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_POSTAL_CODE    0xDD2B
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_COUNTRY        0xDD2C
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_FULL              0xDD2D
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_1            0xDD2E
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_2            0xDD2F
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_CITY              0xDD30
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_REGION            0xDD31
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_POSTAL_CODE       0xDD32
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_COUNTRY           0xDD33
+#define MTP_PROPERTY_ORGANIZATION_NAME                      0xDD34
+#define MTP_PROPERTY_PHONETIC_ORGANIZATION_NAME             0xDD35
+#define MTP_PROPERTY_ROLE                                   0xDD36
+#define MTP_PROPERTY_BIRTHDATE                              0xDD37
+#define MTP_PROPERTY_MESSAGE_TO                             0xDD40
+#define MTP_PROPERTY_MESSAGE_CC                             0xDD41
+#define MTP_PROPERTY_MESSAGE_BCC                            0xDD42
+#define MTP_PROPERTY_MESSAGE_READ                           0xDD43
+#define MTP_PROPERTY_MESSAGE_RECEIVED_TIME                  0xDD44
+#define MTP_PROPERTY_MESSAGE_SENDER                         0xDD45
+#define MTP_PROPERTY_ACTIVITY_BEGIN_TIME                    0xDD50
+#define MTP_PROPERTY_ACTIVITY_END_TIME                      0xDD51
+#define MTP_PROPERTY_ACTIVITY_LOCATION                      0xDD52
+#define MTP_PROPERTY_ACTIVITY_REQUIRED_ATTENDEES            0xDD54
+#define MTP_PROPERTY_ACTIVITY_OPTIONAL_ATTENDEES            0xDD55
+#define MTP_PROPERTY_ACTIVITY_RESOURCES                     0xDD56
+#define MTP_PROPERTY_ACTIVITY_ACCEPTED                      0xDD57
+#define MTP_PROPERTY_ACTIVITY_TENTATIVE                     0xDD58
+#define MTP_PROPERTY_ACTIVITY_DECLINED                      0xDD59
+#define MTP_PROPERTY_ACTIVITY_REMAINDER_TIME                0xDD5A
+#define MTP_PROPERTY_ACTIVITY_OWNER                         0xDD5B
+#define MTP_PROPERTY_ACTIVITY_STATUS                        0xDD5C
+#define MTP_PROPERTY_OWNER                                  0xDD5D
+#define MTP_PROPERTY_EDITOR                                 0xDD5E
+#define MTP_PROPERTY_WEBMASTER                              0xDD5F
+#define MTP_PROPERTY_URL_SOURCE                             0xDD60
+#define MTP_PROPERTY_URL_DESTINATION                        0xDD61
+#define MTP_PROPERTY_TIME_BOOKMARK                          0xDD62
+#define MTP_PROPERTY_OBJECT_BOOKMARK                        0xDD63
+#define MTP_PROPERTY_BYTE_BOOKMARK                          0xDD64
+#define MTP_PROPERTY_LAST_BUILD_DATE                        0xDD70
+#define MTP_PROPERTY_TIME_TO_LIVE                           0xDD71
+#define MTP_PROPERTY_MEDIA_GUID                             0xDD72
+
+// MTP Device Property Codes
+#define MTP_DEVICE_PROPERTY_UNDEFINED                       0x5000
+#define MTP_DEVICE_PROPERTY_BATTERY_LEVEL                   0x5001
+#define MTP_DEVICE_PROPERTY_FUNCTIONAL_MODE                 0x5002
+#define MTP_DEVICE_PROPERTY_IMAGE_SIZE                      0x5003
+#define MTP_DEVICE_PROPERTY_COMPRESSION_SETTING             0x5004
+#define MTP_DEVICE_PROPERTY_WHITE_BALANCE                   0x5005
+#define MTP_DEVICE_PROPERTY_RGB_GAIN                        0x5006
+#define MTP_DEVICE_PROPERTY_F_NUMBER                        0x5007
+#define MTP_DEVICE_PROPERTY_FOCAL_LENGTH                    0x5008
+#define MTP_DEVICE_PROPERTY_FOCUS_DISTANCE                  0x5009
+#define MTP_DEVICE_PROPERTY_FOCUS_MODE                      0x500A
+#define MTP_DEVICE_PROPERTY_EXPOSURE_METERING_MODE          0x500B
+#define MTP_DEVICE_PROPERTY_FLASH_MODE                      0x500C
+#define MTP_DEVICE_PROPERTY_EXPOSURE_TIME                   0x500D
+#define MTP_DEVICE_PROPERTY_EXPOSURE_PROGRAM_MODE           0x500E
+#define MTP_DEVICE_PROPERTY_EXPOSURE_INDEX                  0x500F
+#define MTP_DEVICE_PROPERTY_EXPOSURE_BIAS_COMPENSATION      0x5010
+#define MTP_DEVICE_PROPERTY_DATETIME                        0x5011
+#define MTP_DEVICE_PROPERTY_CAPTURE_DELAY                   0x5012
+#define MTP_DEVICE_PROPERTY_STILL_CAPTURE_MODE              0x5013
+#define MTP_DEVICE_PROPERTY_CONTRAST                        0x5014
+#define MTP_DEVICE_PROPERTY_SHARPNESS                       0x5015
+#define MTP_DEVICE_PROPERTY_DIGITAL_ZOOM                    0x5016
+#define MTP_DEVICE_PROPERTY_EFFECT_MODE                     0x5017
+#define MTP_DEVICE_PROPERTY_BURST_NUMBER                    0x5018
+#define MTP_DEVICE_PROPERTY_BURST_INTERVAL                  0x5019
+#define MTP_DEVICE_PROPERTY_TIMELAPSE_NUMBER                0x501A
+#define MTP_DEVICE_PROPERTY_TIMELAPSE_INTERVAL              0x501B
+#define MTP_DEVICE_PROPERTY_FOCUS_METERING_MODE             0x501C
+#define MTP_DEVICE_PROPERTY_UPLOAD_URL                      0x501D
+#define MTP_DEVICE_PROPERTY_ARTIST                          0x501E
+#define MTP_DEVICE_PROPERTY_COPYRIGHT_INFO                  0x501F
+#define MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER         0xD401
+#define MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME            0xD402
+#define MTP_DEVICE_PROPERTY_VOLUME                          0xD403
+#define MTP_DEVICE_PROPERTY_SUPPORTED_FORMATS_ORDERED       0xD404
+#define MTP_DEVICE_PROPERTY_DEVICE_ICON                     0xD405
+#define MTP_DEVICE_PROPERTY_PLAYBACK_RATE                   0xD410
+#define MTP_DEVICE_PROPERTY_PLAYBACK_OBJECT                 0xD411
+#define MTP_DEVICE_PROPERTY_PLAYBACK_CONTAINER_INDEX        0xD412
+#define MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO  0xD406
+#define MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE           0xD407
+
+// MTP Operation Codes
+#define MTP_OPERATION_GET_DEVICE_INFO                       0x1001
+#define MTP_OPERATION_OPEN_SESSION                          0x1002
+#define MTP_OPERATION_CLOSE_SESSION                         0x1003
+#define MTP_OPERATION_GET_STORAGE_IDS                       0x1004
+#define MTP_OPERATION_GET_STORAGE_INFO                      0x1005
+#define MTP_OPERATION_GET_NUM_OBJECTS                       0x1006
+#define MTP_OPERATION_GET_OBJECT_HANDLES                    0x1007
+#define MTP_OPERATION_GET_OBJECT_INFO                       0x1008
+#define MTP_OPERATION_GET_OBJECT                            0x1009
+#define MTP_OPERATION_GET_THUMB                             0x100A
+#define MTP_OPERATION_DELETE_OBJECT                         0x100B
+#define MTP_OPERATION_SEND_OBJECT_INFO                      0x100C
+#define MTP_OPERATION_SEND_OBJECT                           0x100D
+#define MTP_OPERATION_INITIATE_CAPTURE                      0x100E
+#define MTP_OPERATION_FORMAT_STORE                          0x100F
+#define MTP_OPERATION_RESET_DEVICE                          0x1010
+#define MTP_OPERATION_SELF_TEST                             0x1011
+#define MTP_OPERATION_SET_OBJECT_PROTECTION                 0x1012
+#define MTP_OPERATION_POWER_DOWN                            0x1013
+#define MTP_OPERATION_GET_DEVICE_PROP_DESC                  0x1014
+#define MTP_OPERATION_GET_DEVICE_PROP_VALUE                 0x1015
+#define MTP_OPERATION_SET_DEVICE_PROP_VALUE                 0x1016
+#define MTP_OPERATION_RESET_DEVICE_PROP_VALUE               0x1017
+#define MTP_OPERATION_TERMINATE_OPEN_CAPTURE                0x1018
+#define MTP_OPERATION_MOVE_OBJECT                           0x1019
+#define MTP_OPERATION_COPY_OBJECT                           0x101A
+#define MTP_OPERATION_GET_PARTIAL_OBJECT                    0x101B
+#define MTP_OPERATION_INITIATE_OPEN_CAPTURE                 0x101C
+#define MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED            0x9801
+#define MTP_OPERATION_GET_OBJECT_PROP_DESC                  0x9802
+#define MTP_OPERATION_GET_OBJECT_PROP_VALUE                 0x9803
+#define MTP_OPERATION_SET_OBJECT_PROP_VALUE                 0x9804
+#define MTP_OPERATION_GET_OBJECT_PROP_LIST                  0x9805
+#define MTP_OPERATION_SET_OBJECT_PROP_LIST                  0x9806
+#define MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC          0x9807
+#define MTP_OPERATION_SEND_OBJECT_PROP_LIST                 0x9808
+#define MTP_OPERATION_GET_OBJECT_REFERENCES                 0x9810
+#define MTP_OPERATION_SET_OBJECT_REFERENCES                 0x9811
+#define MTP_OPERATION_SKIP                                  0x9820
+
+// Android extensions for direct file IO
+
+// Same as GetPartialObject, but with 64 bit offset
+#define MTP_OPERATION_GET_PARTIAL_OBJECT_64                 0x95C1
+// Same as GetPartialObject64, but copying host to device
+#define MTP_OPERATION_SEND_PARTIAL_OBJECT                   0x95C2
+// Truncates file to 64 bit length
+#define MTP_OPERATION_TRUNCATE_OBJECT                       0x95C3
+// Must be called before using SendPartialObject and TruncateObject
+#define MTP_OPERATION_BEGIN_EDIT_OBJECT                     0x95C4
+// Called to commit changes made by SendPartialObject and TruncateObject
+#define MTP_OPERATION_END_EDIT_OBJECT                       0x95C5
+
+// MTP Response Codes
+#define MTP_RESPONSE_UNDEFINED                                  0x2000
+#define MTP_RESPONSE_OK                                         0x2001
+#define MTP_RESPONSE_GENERAL_ERROR                              0x2002
+#define MTP_RESPONSE_SESSION_NOT_OPEN                           0x2003
+#define MTP_RESPONSE_INVALID_TRANSACTION_ID                     0x2004
+#define MTP_RESPONSE_OPERATION_NOT_SUPPORTED                    0x2005
+#define MTP_RESPONSE_PARAMETER_NOT_SUPPORTED                    0x2006
+#define MTP_RESPONSE_INCOMPLETE_TRANSFER                        0x2007
+#define MTP_RESPONSE_INVALID_STORAGE_ID                         0x2008
+#define MTP_RESPONSE_INVALID_OBJECT_HANDLE                      0x2009
+#define MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED                  0x200A
+#define MTP_RESPONSE_INVALID_OBJECT_FORMAT_CODE                 0x200B
+#define MTP_RESPONSE_STORAGE_FULL                               0x200C
+#define MTP_RESPONSE_OBJECT_WRITE_PROTECTED                     0x200D
+#define MTP_RESPONSE_STORE_READ_ONLY                            0x200E
+#define MTP_RESPONSE_ACCESS_DENIED                              0x200F
+#define MTP_RESPONSE_NO_THUMBNAIL_PRESENT                       0x2010
+#define MTP_RESPONSE_SELF_TEST_FAILED                           0x2011
+#define MTP_RESPONSE_PARTIAL_DELETION                           0x2012
+#define MTP_RESPONSE_STORE_NOT_AVAILABLE                        0x2013
+#define MTP_RESPONSE_SPECIFICATION_BY_FORMAT_UNSUPPORTED        0x2014
+#define MTP_RESPONSE_NO_VALID_OBJECT_INFO                       0x2015
+#define MTP_RESPONSE_INVALID_CODE_FORMAT                        0x2016
+#define MTP_RESPONSE_UNKNOWN_VENDOR_CODE                        0x2017
+#define MTP_RESPONSE_CAPTURE_ALREADY_TERMINATED                 0x2018
+#define MTP_RESPONSE_DEVICE_BUSY                                0x2019
+#define MTP_RESPONSE_INVALID_PARENT_OBJECT                      0x201A
+#define MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT                 0x201B
+#define MTP_RESPONSE_INVALID_DEVICE_PROP_VALUE                  0x201C
+#define MTP_RESPONSE_INVALID_PARAMETER                          0x201D
+#define MTP_RESPONSE_SESSION_ALREADY_OPEN                       0x201E
+#define MTP_RESPONSE_TRANSACTION_CANCELLED                      0x201F
+#define MTP_RESPONSE_SPECIFICATION_OF_DESTINATION_UNSUPPORTED   0x2020
+#define MTP_RESPONSE_INVALID_OBJECT_PROP_CODE                   0xA801
+#define MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT                 0xA802
+#define MTP_RESPONSE_INVALID_OBJECT_PROP_VALUE                  0xA803
+#define MTP_RESPONSE_INVALID_OBJECT_REFERENCE                   0xA804
+#define MTP_RESPONSE_GROUP_NOT_SUPPORTED                        0xA805
+#define MTP_RESPONSE_INVALID_DATASET                            0xA806
+#define MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED         0xA807
+#define MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED         0xA808
+#define MTP_RESPONSE_OBJECT_TOO_LARGE                           0xA809
+#define MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED                  0xA80A
+#define MTP_RESPONSE_NO_RESPONSE                                0xFFFF
+
+// MTP Event Codes
+#define MTP_EVENT_UNDEFINED                         0x4000
+#define MTP_EVENT_CANCEL_TRANSACTION                0x4001
+#define MTP_EVENT_OBJECT_ADDED                      0x4002
+#define MTP_EVENT_OBJECT_REMOVED                    0x4003
+#define MTP_EVENT_STORE_ADDED                       0x4004
+#define MTP_EVENT_STORE_REMOVED                     0x4005
+#define MTP_EVENT_DEVICE_PROP_CHANGED               0x4006
+#define MTP_EVENT_OBJECT_INFO_CHANGED               0x4007
+#define MTP_EVENT_DEVICE_INFO_CHANGED               0x4008
+#define MTP_EVENT_REQUEST_OBJECT_TRANSFER           0x4009
+#define MTP_EVENT_STORE_FULL                        0x400A
+#define MTP_EVENT_DEVICE_RESET                      0x400B
+#define MTP_EVENT_STORAGE_INFO_CHANGED              0x400C
+#define MTP_EVENT_CAPTURE_COMPLETE                  0x400D
+#define MTP_EVENT_UNREPORTED_STATUS                 0x400E
+#define MTP_EVENT_OBJECT_PROP_CHANGED               0xC801
+#define MTP_EVENT_OBJECT_PROP_DESC_CHANGED          0xC802
+#define MTP_EVENT_OBJECT_REFERENCES_CHANGED         0xC803
+
+// Storage Type
+#define MTP_STORAGE_FIXED_ROM                       0x0001
+#define MTP_STORAGE_REMOVABLE_ROM                   0x0002
+#define MTP_STORAGE_FIXED_RAM                       0x0003
+#define MTP_STORAGE_REMOVABLE_RAM                   0x0004
+
+// Storage File System
+#define MTP_STORAGE_FILESYSTEM_FLAT                 0x0001
+#define MTP_STORAGE_FILESYSTEM_HIERARCHICAL         0x0002
+#define MTP_STORAGE_FILESYSTEM_DCF                  0x0003
+
+// Storage Access Capability
+#define MTP_STORAGE_READ_WRITE                      0x0000
+#define MTP_STORAGE_READ_ONLY_WITHOUT_DELETE        0x0001
+#define MTP_STORAGE_READ_ONLY_WITH_DELETE           0x0002
+
+// Association Type
+#define MTP_ASSOCIATION_TYPE_UNDEFINED              0x0000
+#define MTP_ASSOCIATION_TYPE_GENERIC_FOLDER         0x0001
+
+// MTP class reqeusts
+#define MTP_REQUEST_CANCEL              0x64
+#define MTP_REQUEST_GET_EXT_EVENT_DATA  0x65
+#define MTP_REQUEST_RESET               0x66
+#define MTP_REQUEST_GET_DEVICE_STATUS   0x67
+// clang-format on
+
+#define USB_MTP_CLASS 0x06
+
+#define USB_MTP_SUB_CLASS 0x01U
+#define USB_MTP_PROTOCOL  0x01U
+
+struct mtp_header {
+    uint32_t conlen;
+    uint16_t contype;
+    uint16_t code;
+    uint32_t trans_id;
+    uint32_t param[];
+};
+
+struct mtp_string {
+    uint8_t len;
+    uint16_t string[255];
+};
+
+struct mtp_device_info {
+    uint16_t StandardVersion;
+    uint32_t VendorExtensionID;
+    uint16_t VendorExtensionVersion;
+    uint8_t VendorExtensionDesc_len;
+    uint16_t VendorExtensionDesc[255];
+    uint16_t FunctionalMode;
+    uint32_t OperationsSupported_len;
+    uint16_t OperationsSupported[255];
+    uint32_t EventsSupported_len;
+    uint16_t EventsSupported[255];
+    uint32_t DevicePropertiesSupported_len;
+    uint16_t DevicePropertiesSupported[255];
+    uint32_t CaptureFormats_len;
+    uint16_t CaptureFormats[255];
+    uint32_t ImageFormats_len;
+    uint16_t ImageFormats[255];
+    uint8_t Manufacturer_len;
+    uint16_t Manufacturer[255];
+    uint8_t Model_len;
+    uint16_t Model[255];
+    uint8_t DeviceVersion_len;
+    uint16_t DeviceVersion[255];
+    uint8_t SerialNumber_len;
+    uint16_t SerialNumber[255];
+} __PACKED;
+
+struct mtp_object_props_support {
+    uint32_t ObjectPropCode_len;
+    uint16_t ObjectPropCode[255];
+} __PACKED;
+
+struct mtp_device_prop_desc {
+    uint16_t DevicePropertyCode;
+    uint16_t DataType;
+    uint8_t GetSet;
+    uint16_t DefaultValue[1];
+    uint16_t CurrentValue[1];
+    uint8_t FormFlag;
+} __PACKED;
+
+struct mtp_storage_id {
+    uint32_t StorageIDS_len;
+    uint32_t StorageIDS[255];
+} __PACKED;
+
+struct mtp_storage_info {
+    uint16_t StorageType;
+    uint16_t FilesystemType;
+    uint16_t AccessCapability;
+    uint64_t MaxCapability;
+    uint64_t FreeSpaceInBytes;
+    uint32_t FreeSpaceInObjects;
+    uint8_t StorageDescription_len;
+    uint8_t StorageDescription[255];
+    uint8_t VolumeIdentifier_len;
+    uint8_t VolumeIdentifier[255];
+} __PACKED;
+
+struct mtp_object_handles {
+    uint32_t ObjectHandle_len;
+    uint32_t ObjectHandle[255];
+} __PACKED;
+
+struct mtp_object_prop_desc {
+    uint16_t ObjectPropertyCode;
+    uint16_t DataType;
+    uint8_t GetSet;
+    uint8_t DefValue[16];
+    uint32_t GroupCode;
+    uint8_t FormFlag;
+} __PACKED;
+
+struct mtp_object_prop_element {
+    uint32_t ObjectHandle;
+    uint16_t PropertyCode;
+    uint16_t Datatype;
+    uint8_t value[8];
+} __PACKED;
+
+struct mtp_object_prop_list {
+    uint32_t element_len;
+    struct mtp_object_prop_element element[1];
+} __PACKED;
+
+struct mtp_object_info {
+    uint32_t StorageId;
+    uint16_t ObjectFormat;
+    uint16_t ProtectionStatus;
+    uint32_t ObjectCompressedSize;
+    uint16_t ThumbFormat;
+    uint32_t ThumbCompressedSize;
+    uint32_t ThumbPixWidth;
+    uint32_t ThumbPixHeight;
+    uint32_t ImagePixWidth;
+    uint32_t ImagePixHeight;
+    uint32_t ImageBitDepth;
+    uint32_t ParentObject;
+    uint16_t AssociationType;
+    uint32_t AssociationDesc;
+    uint32_t SequenceNumber;
+    uint8_t Filename_len;
+    uint16_t Filename[CONFIG_USBDEV_MTP_MAX_PATHNAME];
+    uint8_t CaptureDate[6];
+    uint8_t ModificationDate[6];
+} __PACKED;
+
+struct mtp_object {
+    uint32_t storage_id;
+    uint32_t handle;
+    uint32_t parent_handle;
+    uint16_t format;
+    bool is_dir;
+    bool is_readonly;
+    bool is_hidden;
+    uint32_t file_size;
+    uint32_t file_full_name_length;
+    char file_full_name[CONFIG_USBDEV_MTP_MAX_PATHNAME];
+    bool in_use;
+};
+
+/*Length of template descriptor: 23 bytes*/
+#define MTP_DESCRIPTOR_LEN (9 + 7 + 7 + 7)
+
+// clang-format off
+#define MTP_DESCRIPTOR_INIT(bFirstInterface, out_ep, in_ep, int_ep, wMaxPacketSize, str_idx) \
+    /* Interface */                                                      \
+    0x09,                          /* bLength */                         \
+    USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */                 \
+    bFirstInterface,               /* bInterfaceNumber */                \
+    0x00,                          /* bAlternateSetting */               \
+    0x03,                          /* bNumEndpoints */                   \
+    USB_DEVICE_CLASS_IMAGE,        /* bInterfaceClass */                 \
+    USB_MTP_SUB_CLASS,             /* bInterfaceSubClass */              \
+    USB_MTP_PROTOCOL,              /* bInterfaceProtocol */              \
+    str_idx,                       /* iInterface */                      \
+    0x07,                          /* bLength */                         \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,  /* bDescriptorType */                 \
+    out_ep,                        /* bEndpointAddress */                \
+    0x02,                          /* bmAttributes */                    \
+    WBVAL(wMaxPacketSize),         /* wMaxPacketSize */                  \
+    0x00,                          /* bInterval */                       \
+    0x07,                          /* bLength */                         \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,  /* bDescriptorType */                 \
+    in_ep,                         /* bEndpointAddress */                \
+    0x02,                          /* bmAttributes */                    \
+    WBVAL(wMaxPacketSize),         /* wMaxPacketSize */                  \
+    0x00,                          /* bInterval */                       \
+    0x07,                          /* bLength */                         \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,  /* bDescriptorType */                 \
+    int_ep,                        /* bEndpointAddress */                \
+    0x03,                          /* bmAttributes */                    \
+    0x1c,                          /* wMaxPacketSize */                  \
+    0x00,                          /* bInterval */                       \
+    0x06                           /* bLength */
+// clang-format on
+
+#endif

+ 62 - 0
class/mtp/usbd_mtp.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_MTP_H
+#define USBD_MTP_H
+
+#include "usb_mtp.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* gcc toolchain does not implement dirent.h, so we define our own MTP_DIR and mtp_dirent */
+
+typedef void MTP_DIR;
+
+struct mtp_statfs {
+    size_t f_bsize;  /* block size */
+    size_t f_blocks; /* total data blocks in file system */
+    size_t f_bfree;  /* free blocks in file system */
+};
+
+struct mtp_dirent {
+    uint8_t d_type;                              /* The type of the file */
+    uint8_t d_namlen;                            /* The length of the not including the terminating null file name */
+    uint16_t d_reclen;                           /* length of this record */
+    char d_name[CONFIG_USBDEV_MTP_MAX_PATHNAME]; /* The null-terminated file name */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct usbd_interface *usbd_mtp_init_intf(struct usbd_interface *intf,
+                                          const uint8_t out_ep,
+                                          const uint8_t in_ep,
+                                          const uint8_t int_ep);
+
+const char *usbd_mtp_fs_root_path(void);
+const char *usbd_mtp_fs_description(void);
+
+int usbd_mtp_mkdir(const char *path);
+int usbd_mtp_rmdir(const char *path);
+MTP_DIR *usbd_mtp_opendir(const char *name);
+int usbd_mtp_closedir(MTP_DIR *d);
+struct mtp_dirent *usbd_mtp_readdir(MTP_DIR *d);
+
+int usbd_mtp_statfs(const char *path, struct mtp_statfs *buf);
+int usbd_mtp_stat(const char *file, struct stat *buf);
+
+int usbd_mtp_open(const char *path, uint8_t mode);
+int usbd_mtp_close(int fd);
+int usbd_mtp_read(int fd, void *buf, size_t len);
+int usbd_mtp_write(int fd, const void *buf, size_t len);
+
+int usbd_mtp_unlink(const char *path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_MTP_H */

+ 312 - 0
class/mtp/usbd_mtp_support.h

@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2025, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_MTP_SUPPORT_H
+#define USBD_MTP_SUPPORT_H
+
+#define MTP_VERSION 100
+
+typedef struct _profile_property {
+    uint16_t prop_code;
+    uint16_t data_type;
+    uint8_t getset;
+    uint64_t default_value;
+    uint32_t group_code;
+    uint8_t form_flag;
+    uint16_t format_code;
+} profile_property;
+
+typedef struct _format_property {
+    uint16_t format_code;
+    uint16_t *properties;
+} formats_property;
+
+const char mtp_extension_string[] = "microsoft.com: 1.0; android.com: 1.0;";
+
+const uint16_t supported_op[] = {
+    MTP_OPERATION_GET_DEVICE_INFO,  //0x1001
+    MTP_OPERATION_OPEN_SESSION,     //0x1002
+    MTP_OPERATION_CLOSE_SESSION,    //0x1003
+    MTP_OPERATION_GET_STORAGE_IDS,  //0x1004
+    MTP_OPERATION_GET_STORAGE_INFO, //0x1005
+    //MTP_OPERATION_GET_NUM_OBJECTS                        ,//0x1006
+    MTP_OPERATION_GET_OBJECT_HANDLES, //0x1007
+    MTP_OPERATION_GET_OBJECT_INFO,    //0x1008
+    MTP_OPERATION_GET_OBJECT,         //0x1009
+    //MTP_OPERATION_GET_THUMB                              ,//0x100A
+    MTP_OPERATION_DELETE_OBJECT,        //0x100B
+    MTP_OPERATION_SEND_OBJECT_INFO,     //0x100C
+    MTP_OPERATION_SEND_OBJECT,          //0x100D
+    MTP_OPERATION_GET_DEVICE_PROP_DESC, //0x1014
+    // MTP_OPERATION_GET_DEVICE_PROP_VALUE                  ,//0x1015
+    // MTP_OPERATION_SET_DEVICE_PROP_VALUE                  ,//0x1016
+    //MTP_OPERATION_RESET_DEVICE_PROP_VALUE                ,//0x1017
+    // MTP_OPERATION_GET_PARTIAL_OBJECT                     ,//0x101B
+    MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED, //0x9801
+    // MTP_OPERATION_GET_OBJECT_PROP_DESC,       //0x9802
+    // MTP_OPERATION_GET_OBJECT_PROP_VALUE                  ,//0x9803
+    // MTP_OPERATION_SET_OBJECT_PROP_VALUE                  ,//0x9804
+    // MTP_OPERATION_GET_OBJECT_PROP_LIST                   ,//0x9805
+    //MTP_OPERATION_GET_OBJECT_REFERENCES                  ,//0x9810
+    //MTP_OPERATION_SET_OBJECT_REFERENCES                  ,//0x9811
+    // MTP_OPERATION_GET_PARTIAL_OBJECT_64                  ,//0x95C1
+    // MTP_OPERATION_SEND_PARTIAL_OBJECT                    ,//0x95C2
+    // MTP_OPERATION_TRUNCATE_OBJECT                        ,//0x95C3
+    // MTP_OPERATION_BEGIN_EDIT_OBJECT                      ,//0x95C4
+    // MTP_OPERATION_END_EDIT_OBJECT                         //0x95C5
+};
+
+int supported_op_size = sizeof(supported_op);
+
+const uint16_t supported_event[] = {
+    MTP_EVENT_OBJECT_ADDED,         // 0x4002
+    MTP_EVENT_OBJECT_REMOVED,       // 0x4003
+    MTP_EVENT_STORE_ADDED,          // 0x4004
+    MTP_EVENT_STORE_REMOVED,        // 0x4005
+    MTP_EVENT_STORAGE_INFO_CHANGED, // 0x400C
+    MTP_EVENT_OBJECT_INFO_CHANGED,  // 0x4007
+    MTP_EVENT_DEVICE_PROP_CHANGED,  // 0x4006
+    MTP_EVENT_OBJECT_PROP_CHANGED   // 0xC801
+};
+
+int supported_event_size = sizeof(supported_event);
+
+const formats_property support_format_properties[] = {
+    // format code                       prop code
+    { MTP_FORMAT_UNDEFINED, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+                                          MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+                                          MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+                                          0xFFFF } },
+    { MTP_FORMAT_ASSOCIATION, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+                                            MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+                                            MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+                                            0xFFFF } }
+#if 0
+	{ MTP_FORMAT_TEXT         , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_HTML         , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_MP4_CONTAINER, (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_3GP_CONTAINER, (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_WAV          , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,MTP_PROPERTY_ARTIST,MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER,
+												MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE, MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_PROPERTY_SAMPLE_RATE,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_MP3          , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,MTP_PROPERTY_ARTIST,MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER,
+												MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE, MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_PROPERTY_SAMPLE_RATE,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_MPEG         , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_EXIF_JPEG    , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH,
+												MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_BMP          , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH,
+												MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_GIF          , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH,
+												MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_JFIF         , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH,
+												MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_WMA          , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION,
+												MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE,
+												MTP_PROPERTY_NUMBER_OF_CHANNELS, MTP_PROPERTY_SAMPLE_RATE,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_OGG          , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION,
+												MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE,
+												MTP_PROPERTY_NUMBER_OF_CHANNELS, MTP_PROPERTY_SAMPLE_RATE,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_AAC          , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION,
+												MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE,
+												MTP_PROPERTY_NUMBER_OF_CHANNELS, MTP_PROPERTY_SAMPLE_RATE,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_ABSTRACT_AV_PLAYLIST, (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_WPL_PLAYLIST,  (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_M3U_PLAYLIST,  (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_PLS_PLAYLIST,  (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_XML_DOCUMENT,  (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_FLAC        ,  (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_AVI          , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_ASF          , (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
+												MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_MS_WORD_DOCUMENT, (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_MS_EXCEL_SPREADSHEET, (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	},
+	{ MTP_FORMAT_MS_POWERPOINT_PRESENTATION, (uint16_t[]){   MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
+												MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
+												MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
+												0xFFFF}
+	}
+#endif
+    ,
+
+    { 0xFFFF, (uint16_t[]){ 0xFFFF } }
+
+};
+
+const profile_property support_object_properties[] = {
+    // prop_code               data_type      getset    default_value group_code  form_flag format_code
+    { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000001, 0x00, 0xFFFF },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_UNDEFINED, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_ASSOCIATION, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_TEXT, 0x000000000, 0x00, MTP_FORMAT_TEXT },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_HTML, 0x000000000, 0x00, MTP_FORMAT_HTML },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_WAV, 0x000000000, 0x00, MTP_FORMAT_WAV },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MP3, 0x000000000, 0x00, MTP_FORMAT_MP3 },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MPEG, 0x000000000, 0x00, MTP_FORMAT_MPEG },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_EXIF_JPEG, 0x000000000, 0x00, MTP_FORMAT_EXIF_JPEG },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_BMP, 0x000000000, 0x00, MTP_FORMAT_BMP },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_AIFF, 0x000000000, 0x00, MTP_FORMAT_AIFF },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MPEG, 0x000000000, 0x00, MTP_FORMAT_MPEG },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_WMA, 0x000000000, 0x00, MTP_FORMAT_WMA },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_OGG, 0x000000000, 0x00, MTP_FORMAT_OGG },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_AAC, 0x000000000, 0x00, MTP_FORMAT_AAC },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MP4_CONTAINER, 0x000000000, 0x00, MTP_FORMAT_MP4_CONTAINER },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_3GP_CONTAINER, 0x000000000, 0x00, MTP_FORMAT_3GP_CONTAINER },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_ABSTRACT_AV_PLAYLIST, 0x000000000, 0x00, MTP_FORMAT_ABSTRACT_AV_PLAYLIST },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_WPL_PLAYLIST, 0x000000000, 0x00, MTP_FORMAT_WPL_PLAYLIST },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_M3U_PLAYLIST, 0x000000000, 0x00, MTP_FORMAT_M3U_PLAYLIST },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_PLS_PLAYLIST, 0x000000000, 0x00, MTP_FORMAT_PLS_PLAYLIST },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_XML_DOCUMENT, 0x000000000, 0x00, MTP_FORMAT_XML_DOCUMENT },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_FLAC, 0x000000000, 0x00, MTP_FORMAT_FLAC },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_AVI, 0x000000000, 0x00, MTP_FORMAT_AVI },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_ASF, 0x000000000, 0x00, MTP_FORMAT_ASF },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MS_WORD_DOCUMENT, 0x000000000, 0x00, MTP_FORMAT_MS_WORD_DOCUMENT },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MS_EXCEL_SPREADSHEET, 0x000000000, 0x00, MTP_FORMAT_MS_EXCEL_SPREADSHEET },
+    { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MS_POWERPOINT_PRESENTATION, 0x000000000, 0x00, MTP_FORMAT_MS_POWERPOINT_PRESENTATION },
+
+    { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, 0x00, 0x0000000000000000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16, 0x00, 0x0000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR, 0x00, 0x0000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, 0x01, 0x0000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_DATE_CREATED, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+    { MTP_PROPERTY_NAME, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
+
+    { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, 0x00, 0x0000000000000000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16, 0x00, 0x0000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR, 0x00, 0x0000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, 0x01, 0x0000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_DATE_CREATED, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+    { MTP_PROPERTY_NAME, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
+
+    //{MTP_PROPERTY_ASSOCIATION_TYPE,    MTP_TYPE_UINT16,    0x00,   0x0001             , 0x000000000 , 0x00 , 0xFFFF },
+    { MTP_PROPERTY_ASSOCIATION_DESC, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, 0xFFFF },
+    { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16, 0x00, 0x0000, 0x000000000, 0x00, 0xFFFF },
+    { MTP_PROPERTY_HIDDEN, MTP_TYPE_UINT16, 0x00, 0x0000, 0x000000000, 0x00, 0xFFFF },
+
+    { 0xFFFF, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00 }
+};
+
+const profile_property support_device_properties[] = {
+    // prop_code                                           data_type         getset    default_value          group_code     form_flag
+    //{MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER,          MTP_TYPE_UINT32,    0x00,   0x00000000           , 0x000000000 , 0x00 },
+    //{MTP_DEVICE_PROPERTY_IMAGE_SIZE,                       MTP_TYPE_UINT32,    0x00,   0x00000000           , 0x000000000 , 0x00 },
+    { MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT16, 0x00, 0x00000000, 0x000000000, 0x00 },
+    { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR, 0x00, 0x00000000, 0x000000000, 0x00 },
+
+    { 0xFFFF, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00 }
+};
+
+#endif

+ 250 - 0
demo/mtp_template.c

@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2025 sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+
+#include "usbd_core.h"
+#include "usbd_mtp.h"
+
+#if 1
+#error "commercial charge"
+#endif
+
+#ifndef CONFIG_USBDEV_MTP_THREAD
+#warning mtp depends on filesystem, suggest to enable CONFIG_USBDEV_MTP_THREAD
+#endif
+
+#define WCID_VENDOR_CODE 0x01
+
+__ALIGN_BEGIN const uint8_t WCID_StringDescriptor_MSOS[18] __ALIGN_END = {
+    ///////////////////////////////////////
+    /// MS OS string descriptor
+    ///////////////////////////////////////
+    0x12,                       /* bLength */
+    USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
+    /* MSFT100 */
+    'M', 0x00, 'S', 0x00, 'F', 0x00, 'T', 0x00, /* wcChar_7 */
+    '1', 0x00, '0', 0x00, '0', 0x00,            /* wcChar_7 */
+    WCID_VENDOR_CODE,                           /* bVendorCode */
+    0x00,                                       /* bReserved */
+};
+
+__ALIGN_BEGIN const uint8_t WINUSB_WCIDDescriptor[40] __ALIGN_END = {
+    ///////////////////////////////////////
+    /// WCID descriptor
+    ///////////////////////////////////////
+    0x28, 0x00, 0x00, 0x00,                   /* dwLength */
+    0x00, 0x01,                               /* bcdVersion */
+    0x04, 0x00,                               /* wIndex */
+    0x01,                                     /* bCount */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* bReserved_7 */
+
+    ///////////////////////////////////////
+    /// WCID function descriptor
+    ///////////////////////////////////////
+    0x00, /* bFirstInterfaceNumber */
+    0x01, /* bReserved */
+    /* MTP */
+    'M', 'T', 'P', 0x00, 0x00, 0x00, 0x00, 0x00, /* cCID_8 */
+    /*  */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cSubCID_8 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,             /* bReserved_6 */
+};
+
+__ALIGN_BEGIN const uint8_t WINUSB_IF0_WCIDProperties[142] __ALIGN_END = {
+    ///////////////////////////////////////
+    /// WCID property descriptor
+    ///////////////////////////////////////
+    0x8e, 0x00, 0x00, 0x00, /* dwLength */
+    0x00, 0x01,             /* bcdVersion */
+    0x05, 0x00,             /* wIndex */
+    0x01, 0x00,             /* wCount */
+
+    ///////////////////////////////////////
+    /// registry propter descriptor
+    ///////////////////////////////////////
+    0x84, 0x00, 0x00, 0x00, /* dwSize */
+    0x01, 0x00, 0x00, 0x00, /* dwPropertyDataType */
+    0x28, 0x00,             /* wPropertyNameLength */
+    /* DeviceInterfaceGUID */
+    'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00,  /* wcName_20 */
+    'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00,  /* wcName_20 */
+    't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00,  /* wcName_20 */
+    'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00,  /* wcName_20 */
+    'U', 0x00, 'I', 0x00, 'D', 0x00, 0x00, 0x00, /* wcName_20 */
+    0x4e, 0x00, 0x00, 0x00,                      /* dwPropertyDataLength */
+
+    /* {1D4B2365-4749-48EA-B38A-7C6FDDDD7E26} */
+    '{', 0x00, '1', 0x00, 'D', 0x00, '4', 0x00, /* wcData_39 */
+    'B', 0x00, '2', 0x00, '3', 0x00, '6', 0x00, /* wcData_39 */
+    '5', 0x00, '-', 0x00, '4', 0x00, '7', 0x00, /* wcData_39 */
+    '4', 0x00, '9', 0x00, '-', 0x00, '4', 0x00, /* wcData_39 */
+    '8', 0x00, 'E', 0x00, 'A', 0x00, '-', 0x00, /* wcData_39 */
+    'B', 0x00, '3', 0x00, '8', 0x00, 'A', 0x00, /* wcData_39 */
+    '-', 0x00, '7', 0x00, 'C', 0x00, '6', 0x00, /* wcData_39 */
+    'F', 0x00, 'D', 0x00, 'D', 0x00, 'D', 0x00, /* wcData_39 */
+    'D', 0x00, '7', 0x00, 'E', 0x00, '2', 0x00, /* wcData_39 */
+    '6', 0x00, '}', 0x00, 0x00, 0x00,           /* wcData_39 */
+
+};
+
+const uint8_t bos_descriptor[] = {
+    0x05, 0x0f, 0x16, 0x00, 0x02,
+    0x07, 0x10, 0x02, 0x06, 0x00, 0x00, 0x00,
+    0x0a, 0x10, 0x03, 0x00, 0x0f, 0x00, 0x01, 0x01, 0xf4, 0x01
+};
+
+/*!< endpoint address */
+#define MTP_IN_EP  0x81
+#define MTP_OUT_EP 0x02
+#define MTP_INT_EP 0x83
+
+/*!< config descriptor size */
+#define USB_CONFIG_SIZE (9 + MTP_DESCRIPTOR_LEN)
+
+static const uint8_t device_descriptor[] = {
+    USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0201, 0x01)
+};
+
+static const uint8_t config_descriptor_hs[] = {
+    USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+    MTP_DESCRIPTOR_INIT(0x00, MTP_OUT_EP, MTP_IN_EP, MTP_INT_EP, USB_BULK_EP_MPS_HS, 0x02),
+};
+
+static const uint8_t config_descriptor_fs[] = {
+    USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+    MTP_DESCRIPTOR_INIT(0x00, MTP_OUT_EP, MTP_IN_EP, MTP_INT_EP, USB_BULK_EP_MPS_FS, 0x02),
+};
+
+static const uint8_t device_quality_descriptor[] = {
+    USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+    USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+    MTP_DESCRIPTOR_INIT(0x00, MTP_OUT_EP, MTP_IN_EP, MTP_INT_EP, USB_BULK_EP_MPS_FS, 0x02),
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+    USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+    MTP_DESCRIPTOR_INIT(0x00, MTP_OUT_EP, MTP_IN_EP, MTP_INT_EP, USB_BULK_EP_MPS_HS, 0x02),
+};
+
+static const char *string_descriptors[] = {
+    (const char[]){ 0x09, 0x04 }, /* Langid */
+    "CherryUSB",                  /* Manufacturer */
+    "CherryUSB MTP DEMO",         /* Product */
+    "2025053000",                 /* Serial Number */
+};
+
+static const uint8_t *device_descriptor_callback(uint8_t speed)
+{
+    (void)speed;
+
+    return device_descriptor;
+}
+
+static const uint8_t *config_descriptor_callback(uint8_t speed)
+{
+    if (speed == USB_SPEED_HIGH) {
+        return config_descriptor_hs;
+    } else if (speed == USB_SPEED_FULL) {
+        return config_descriptor_fs;
+    } else {
+        return NULL;
+    }
+}
+
+static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
+{
+    (void)speed;
+
+    return device_quality_descriptor;
+}
+
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+    if (speed == USB_SPEED_HIGH) {
+        return other_speed_config_descriptor_hs;
+    } else if (speed == USB_SPEED_FULL) {
+        return other_speed_config_descriptor_fs;
+    } else {
+        return NULL;
+    }
+}
+
+static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
+{
+    (void)speed;
+
+    if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
+        return NULL;
+    }
+    return string_descriptors[index];
+}
+
+const uint8_t *WINUSB_IFx_WCIDProperties[] = {
+    WINUSB_IF0_WCIDProperties,
+};
+
+struct usb_msosv1_descriptor msosv1_desc = {
+    .string = WCID_StringDescriptor_MSOS,
+    .vendor_code = WCID_VENDOR_CODE,
+    .compat_id = WINUSB_WCIDDescriptor,
+    .comp_id_property = WINUSB_IFx_WCIDProperties,
+};
+
+const struct usb_bos_descriptor bos_desc = {
+    .string = bos_descriptor,
+    .string_len = 22
+};
+
+const struct usb_descriptor mtp_descriptor = {
+    .device_descriptor_callback = device_descriptor_callback,
+    .config_descriptor_callback = config_descriptor_callback,
+    .device_quality_descriptor_callback = device_quality_descriptor_callback,
+    .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
+    .string_descriptor_callback = string_descriptor_callback,
+    .bos_descriptor = &bos_desc,
+    .msosv1_descriptor = &msosv1_desc,
+};
+
+static void usbd_event_handler(uint8_t busid, uint8_t event)
+{
+    switch (event) {
+        case USBD_EVENT_RESET:
+            break;
+        case USBD_EVENT_CONNECTED:
+            break;
+        case USBD_EVENT_DISCONNECTED:
+            break;
+        case USBD_EVENT_RESUME:
+            break;
+        case USBD_EVENT_SUSPEND:
+            break;
+        case USBD_EVENT_CONFIGURED:
+            break;
+        case USBD_EVENT_SET_REMOTE_WAKEUP:
+            break;
+        case USBD_EVENT_CLR_REMOTE_WAKEUP:
+            break;
+
+        default:
+            break;
+    }
+}
+
+static struct usbd_interface intf0;
+
+extern void usbd_mtp_mount();
+
+void mtp_init(uint8_t busid, uint32_t reg_base)
+{
+    usbd_mtp_mount();
+
+    usbd_desc_register(busid, &mtp_descriptor);
+    usbd_add_interface(busid, usbd_mtp_init_intf(&intf0, MTP_OUT_EP, MTP_IN_EP, MTP_INT_EP));
+    usbd_initialize(busid, reg_base, usbd_event_handler);
+}

BIN
docs/source/support/img/mtpdev.png


+ 4 - 1
docs/source/support/index.rst

@@ -20,7 +20,10 @@
 
 
 - 主机 UVC & UAC 类 MUSB IP 中 ISO 驱动和 UAC/UVC 框架, MUSB 需要为 mentor 公司制定的标准 IP
 - 主机 UVC & UAC 类 MUSB IP 中 ISO 驱动和 UAC/UVC 框架, MUSB 需要为 mentor 公司制定的标准 IP
 
 
-- 主从机 MTP 类驱动
+- 从机 MTP 类驱动, 支持多文件和多文件夹
+
+.. figure:: img/mtpdev.png
+
 - USB 网卡类高性能版本优化,包含 CDC-NCM, CDC-RNDIS, 私有类驱动(支持多包发送和接收),下面举例 RNDIS
 - USB 网卡类高性能版本优化,包含 CDC-NCM, CDC-RNDIS, 私有类驱动(支持多包发送和接收),下面举例 RNDIS
 
 
 .. figure:: img/rndistx.png
 .. figure:: img/rndistx.png

+ 2 - 1
platform/README.md

@@ -5,7 +5,8 @@ This is a platform support for other opensource projects.
 
 
 ## Fatfs
 ## Fatfs
 
 
-Fatfs support with usb host msc.
+- Fatfs support with usb host msc.
+- Fatfs support with usb device mtp.
 
 
 ## lwip
 ## lwip
 
 

+ 337 - 0
platform/fatfs/usbd_fatfs_mtp.c

@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2025 sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+
+#include "ff.h"
+#include "diskio.h"
+#include "usbd_core.h"
+#include "usbd_mtp.h"
+
+FATFS s_sd_disk;
+FIL s_file;
+DIR s_dir;
+BYTE work[FF_MAX_SS];
+
+const TCHAR driver_num_buf[4] = { '0', ':', '/', '\0' };
+
+const char *show_error_string(FRESULT fresult);
+
+static FRESULT sd_mount_fs(void)
+{
+    FRESULT fresult = f_mount(&s_sd_disk, driver_num_buf, 1);
+    if (fresult == FR_OK) {
+        printf("SD card has been mounted successfully\n");
+    } else {
+        printf("Failed to mount SD card, cause: %s\n", show_error_string(fresult));
+    }
+
+    return fresult;
+}
+
+#if 0
+static FRESULT sd_mkfs(void)
+{
+    printf("Formatting the SD card, depending on the SD card capacity, the formatting process may take a long time\n");
+    FRESULT fresult = f_mkfs(driver_num_buf, NULL, work, sizeof(work));
+    if (fresult != FR_OK) {
+        printf("Making File system failed, cause: %s\n", show_error_string(fresult));
+    } else {
+        printf("Making file system is successful\n");
+    }
+
+    return fresult;
+}
+#endif
+
+static FRESULT sd_write_file(void)
+{
+    FRESULT fresult = f_open(&s_file, "0:/readme.txt", FA_WRITE | FA_CREATE_ALWAYS);
+    if (fresult != FR_OK) {
+        printf("Create new file failed, cause: %d\n", show_error_string(fresult));
+    } else {
+        printf("Create new file successfully, status=%d\n", fresult);
+    }
+    char hello_str[] = "Hello, this is SD card FATFS demo\n";
+    UINT byte_written;
+    fresult = f_write(&s_file, hello_str, sizeof(hello_str), &byte_written);
+    if (fresult != FR_OK) {
+        printf("Write file failed, cause: %s\n", show_error_string(fresult));
+    } else {
+        printf("Write file operation is successfully\n");
+    }
+
+    f_close(&s_file);
+
+    return fresult;
+}
+
+const char *show_error_string(FRESULT fresult)
+{
+    const char *result_str;
+
+    switch (fresult) {
+        case FR_OK:
+            result_str = "succeeded";
+            break;
+        case FR_DISK_ERR:
+            result_str = "A hard error occurred in the low level disk I/O level";
+            break;
+        case FR_INT_ERR:
+            result_str = "Assertion failed";
+            break;
+        case FR_NOT_READY:
+            result_str = "The physical drive cannot work";
+            break;
+        case FR_NO_FILE:
+            result_str = "Could not find the file";
+            break;
+        case FR_NO_PATH:
+            result_str = "Could not find the path";
+            break;
+        case FR_INVALID_NAME:
+            result_str = "Tha path name format is invalid";
+            break;
+        case FR_DENIED:
+            result_str = "Access denied due to prohibited access or directory full";
+            break;
+        case FR_EXIST:
+            result_str = "Access denied due to prohibited access";
+            break;
+        case FR_INVALID_OBJECT:
+            result_str = "The file/directory object is invalid";
+            break;
+        case FR_WRITE_PROTECTED:
+            result_str = "The physical drive is write protected";
+            break;
+        case FR_INVALID_DRIVE:
+            result_str = "The logical driver number is invalid";
+            break;
+        case FR_NOT_ENABLED:
+            result_str = "The volume has no work area";
+            break;
+        case FR_NO_FILESYSTEM:
+            result_str = "There is no valid FAT volume";
+            break;
+        case FR_MKFS_ABORTED:
+            result_str = "THe f_mkfs() aborted due to any problem";
+            break;
+        case FR_TIMEOUT:
+            result_str = "Could not get a grant to access the volume within defined period";
+            break;
+        case FR_LOCKED:
+            result_str = "The operation is rejected according to the file sharing policy";
+            break;
+        case FR_NOT_ENOUGH_CORE:
+            result_str = "LFN working buffer could not be allocated";
+            break;
+        case FR_TOO_MANY_OPEN_FILES:
+            result_str = "Number of open files > FF_FS_LOCK";
+            break;
+        case FR_INVALID_PARAMETER:
+            result_str = "Given parameter is invalid";
+            break;
+        default:
+            result_str = "Unknown error";
+            break;
+    }
+    return result_str;
+}
+
+const char *usbd_mtp_fs_root_path(void)
+{
+    return driver_num_buf;
+}
+
+const char *usbd_mtp_fs_description(void)
+{
+    return "CherryUSB MTP";
+}
+
+int usbd_mtp_mkdir(const char *path)
+{
+    FRESULT result = f_mkdir(path);
+    if (result != FR_OK) {
+        printf("f_mkdir failed, cause: %s\n", show_error_string(result));
+        return -1;
+    }
+    return 0; // Directory created successfully
+}
+
+int usbd_mtp_rmdir(const char *path)
+{
+    FRESULT result = f_rmdir(path);
+    if (result != FR_OK) {
+        printf("f_mkdir failed, cause: %s\n", show_error_string(result));
+        return -1;
+    }
+    return 0; // Directory created successfully
+}
+
+MTP_DIR *usbd_mtp_opendir(const char *name)
+{
+    f_opendir(&s_dir, name);
+    return (MTP_DIR *)&s_dir;
+}
+
+int usbd_mtp_closedir(MTP_DIR *dir)
+{
+    return f_closedir((DIR *)dir);
+}
+
+struct mtp_dirent *usbd_mtp_readdir(MTP_DIR *dir)
+{
+    FILINFO fno;
+    FRESULT result;
+
+    result = f_readdir((DIR *)dir, &fno);
+    if (result != FR_OK || fno.fname[0] == 0)
+        return NULL;
+
+    static struct mtp_dirent dirent;
+    memset(&dirent, 0, sizeof(struct mtp_dirent));
+    strncpy(dirent.d_name, fno.fname, sizeof(dirent.d_name) - 1);
+    dirent.d_name[sizeof(dirent.d_name) - 1] = '\0';
+    dirent.d_namlen = strlen(dirent.d_name);
+
+    return &dirent;
+}
+
+#undef SS
+#if FF_MAX_SS == FF_MIN_SS
+#define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */
+#else
+#define SS(fs) ((fs)->ssize) /* Variable sector size */
+#endif
+
+int usbd_mtp_stat(const char *path, struct stat *buf)
+{
+    FILINFO file_info;
+    FRESULT result;
+    FATFS *f;
+    f = &s_sd_disk;
+
+    result = f_stat(path, &file_info);
+    if (result != FR_OK) {
+        printf("f_stat failed, cause: %s\n", show_error_string(result));
+        return -1;
+    }
+    buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
+                   S_IWUSR | S_IWGRP | S_IWOTH;
+    if (file_info.fattrib & AM_DIR) {
+        buf->st_mode &= ~S_IFREG;
+        buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+    }
+    if (file_info.fattrib & AM_RDO)
+        buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+
+    buf->st_size = file_info.fsize;
+    buf->st_blksize = f->csize * SS(f);
+    if (file_info.fattrib & AM_ARC) {
+        buf->st_blocks = file_info.fsize ? ((file_info.fsize - 1) / SS(f) / f->csize + 1) : 0;
+        buf->st_blocks *= (buf->st_blksize / 512); // man say st_blocks is number of 512B blocks allocated
+    } else {
+        buf->st_blocks = f->csize;
+    }
+    return 0;
+}
+
+int usbd_mtp_statfs(const char *path, struct mtp_statfs *buf)
+{
+    FATFS *f;
+    FRESULT res;
+    DWORD fre_clust, fre_sect, tot_sect;
+
+    f = &s_sd_disk;
+
+    res = f_getfree(path, &fre_clust, &f);
+    if (res != FR_OK) {
+        printf("f_getfree failed, cause: %s\n", show_error_string(res));
+        return -1;
+    }
+    tot_sect = (f->n_fatent - 2) * f->csize;
+    fre_sect = fre_clust * f->csize;
+
+    buf->f_blocks = tot_sect;
+    buf->f_bfree = fre_sect;
+#if FF_MAX_SS != FF_MIN_SS
+    buf->f_bsize = f->ssize;
+#else
+    buf->f_bsize = FF_MIN_SS;
+#endif
+    return 0;
+}
+
+int usbd_mtp_open(const char *path, uint8_t mode)
+{
+    BYTE flags;
+
+    if (mode == O_RDONLY) {
+        flags = FA_READ | FA_OPEN_EXISTING;
+    } else if (mode == O_WRONLY) {
+        flags = FA_WRITE | FA_OPEN_ALWAYS;
+    } else if (mode == O_RDWR) {
+        flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
+    } else {
+        return -1; // Invalid mode
+    }
+
+    FRESULT result = f_open(&s_file, path, flags);
+    if (result != FR_OK) {
+        printf("f_open failed, cause: %s\n", show_error_string(result));
+        return -1;
+    }
+    return 0;
+}
+
+int usbd_mtp_close(int fd)
+{
+    FRESULT result = f_close(&s_file);
+    if (result != FR_OK) {
+        printf("f_close failed, cause: %s\n", show_error_string(result));
+        return -1;
+    }
+    return 0;
+}
+
+int usbd_mtp_read(int fd, void *buf, size_t len)
+{
+    UINT bytes_read;
+    FRESULT result = f_read(&s_file, buf, len, &bytes_read);
+    if (result != FR_OK) {
+        printf("f_read failed, cause: %s\n", show_error_string(result));
+        return -1;
+    }
+    return bytes_read; // Return number of bytes read
+}
+
+int usbd_mtp_write(int fd, const void *buf, size_t len)
+{
+    UINT bytes_written;
+    FRESULT result = f_write(&s_file, buf, len, &bytes_written);
+    if (result != FR_OK) {
+        printf("f_write failed, cause: %s\n", show_error_string(result));
+        return -1;
+    }
+    return bytes_written; // Return number of bytes written
+}
+
+int usbd_mtp_unlink(const char *path)
+{
+    FRESULT result = f_unlink(path);
+    if (result != FR_OK) {
+        printf("f_unlink failed, cause: %s\n", show_error_string(result));
+        return -1;
+    }
+    return 0; // File deleted successfully
+}
+
+void usbd_mtp_mount()
+{
+    sd_mount_fs();
+
+    // write a file to test the SD card
+    sd_write_file();
+}