Files
luban-lite-t3e-pro/packages/third-party/cherryusb/class/mtp/usbd_mtp.c
刘可亮 0a13af6a1d V1.0.5
2024-06-04 19:00:30 +08:00

1371 lines
49 KiB
C

/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_mtp.h"
#include "usbd_mtp_config.h"
#include "usb_osal.h"
#if defined(KERNEL_RTTHREAD)
#include <rtthread.h>
#include <rthw.h>
#include <rtthread.h>
#include <rtservice.h>
#include <rtdevice.h>
#endif
/* Max USB packet size */
#ifndef CONFIG_USB_HS
#define MTP_BULK_EP_MPS 64
#else
#define MTP_BULK_EP_MPS 512
#endif
#define DATA_BUFFER_SIZE CONFIG_USBDEV_MTP_MAX_BUFSIZE
#define MAX_WITTE_FILE_SIZE CONFIG_USBDEV_MTP_MAX_BUFSIZE
#define MTP_OUT_EP_IDX 0
#define MTP_IN_EP_IDX 1
#define MTP_INT_EP_IDX 2
/* MTP Stage */
enum Stage {
MTP_READ_COMMAND = 0,
MTP_DATA_OUT = 1,
MTP_DATA_IN = 2,
MTP_SEND_RESPONSE = 3,
MTP_WAIT_RESPONSE = 4,
};
USB_NOCACHE_RAM_SECTION struct usbd_mtp_priv {
USB_MEM_ALIGNX struct mtp_container_command con_command;
USB_MEM_ALIGNX struct mtp_container_data con_data;
USB_MEM_ALIGNX struct mtp_container_response con_response;
enum Stage stage;
uint8_t session_state;
uint32_t response_code;
/*-----priv-----*/
char path[512];
uint32_t handle_counter;
struct mtp_object *mtp_objects;
USB_MEM_ALIGNX uint8_t usbd_mtp_data_in[CONFIG_USBDEV_MTP_MAX_BUFSIZE];
USB_MEM_ALIGNX uint8_t usbd_mtp_data_out[CONFIG_USBDEV_MTP_MAX_BUFSIZE];
uint32_t usbd_mtp_rcnt; //total data
uint32_t usbd_mtp_wcnt;
struct mtp_file mtp_file_in; // file data
struct mtp_file mtp_file_out;
#if defined(CONFIG_USBDEV_MTP_THREAD)
usb_osal_mq_t usbd_mtp_mq;
usb_osal_thread_t usbd_mtp_thread;
uint32_t nbytes;
#endif
} g_usbd_mtp;
/* Describe EndPoints configuration */
static struct usbd_endpoint mtp_ep_data[3];
struct mtp_object mtp_objects[MTP_OBJECT_HANDLES_MAX_NUM];
static int mtp_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
USB_LOG_DBG("MTP Class request: "
"bRequest 0x%02x\r\n",
setup->bRequest);
switch (setup->bRequest) {
case MTP_REQUEST_CANCEL:
break;
case MTP_REQUEST_GET_EXT_EVENT_DATA:
break;
case MTP_REQUEST_RESET:
break;
case MTP_REQUEST_GET_DEVICE_STATUS:
*(uint16_t *)(*data) = 0x08; //len
*(uint16_t *)(*data + 2) = MTP_RESPONSE_OK; // resepone
*len = 8;
break;
default:
USB_LOG_WRN("Unhandled MTP Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
return 0;
}
static int usbd_mtp_get_object_by_handle(struct mtp_object **object, uint32_t handle)
{
if (handle < 0 || handle > MTP_OBJECT_HANDLES_MAX_NUM) {
USB_LOG_ERR("Failed to get object:%ld(%d)\n", handle, MTP_OBJECT_HANDLES_MAX_NUM);
return -1;
}
*object = &mtp_objects[handle];
return 0;
}
static int usbd_mtp_creat_object(struct mtp_object **object, uint32_t *index)
{
uint32_t handle_index;
if (g_usbd_mtp.handle_counter >= MTP_OBJECT_HANDLES_MAX_NUM) {
USB_LOG_ERR("The maximum number of files has been reached !\r\n");
return -1;
}
for (handle_index = 1U; handle_index < MTP_OBJECT_HANDLES_MAX_NUM; handle_index++) {
if (mtp_objects[handle_index].handle == 0U) {
*object = &mtp_objects[handle_index];
*index = handle_index;
g_usbd_mtp.handle_counter++;
break;
}
}
return 0;
}
static int usbd_mtp_unlink_object(struct mtp_object *object)
{
int ret;
uint32_t child;
if (object->property.format != MTP_OBJ_FORMAT_ASSOCIATION) {
ret = usbd_mtp_unlink_file((char *)object->property.file_full_name);
if (ret < 0)
return -1;
} else {
for (child = 1; child < MTP_OBJECT_HANDLES_MAX_NUM; child++) {
if (mtp_objects[child].property.parent_object == object->handle)
usbd_mtp_unlink_object(&mtp_objects[child]);
}
usbd_mtp_remove_dir((char *)object->property.file_full_name);
}
memset(object, 0U, sizeof(struct mtp_object));
g_usbd_mtp.handle_counter--;
return 0;
}
static void usbd_mtp_send_response_param(uint32_t code, uint32_t param1,
uint32_t param2, uint32_t param3,
uint32_t param4, uint32_t param5)
{
USB_LOG_DBG("Send response\r\n");
g_usbd_mtp.stage = MTP_WAIT_RESPONSE;
g_usbd_mtp.con_response.conlen = 32;
g_usbd_mtp.con_response.contype = MTP_CONTAINER_TYPE_RESPONSE;
g_usbd_mtp.con_response.code = code;
g_usbd_mtp.con_response.trans_id = g_usbd_mtp.con_command.trans_id;
g_usbd_mtp.con_response.param1 = (uint32_t)param1;
g_usbd_mtp.con_response.param2 = (uint32_t)param2;
g_usbd_mtp.con_response.param3 = (uint32_t)param3;
g_usbd_mtp.con_response.param4 = (uint32_t)param4;
g_usbd_mtp.con_response.param5 = (uint32_t)param5;
usbd_ep_start_write(mtp_ep_data[MTP_IN_EP_IDX].ep_addr, (uint8_t *)&g_usbd_mtp.con_response, 32);
}
static void usbd_mtp_send_response(uint32_t code)
{
USB_LOG_DBG("Send response\r\n");
g_usbd_mtp.stage = MTP_WAIT_RESPONSE;
g_usbd_mtp.con_response.conlen = CONFIG_MTP_COMMAND_LEN;
g_usbd_mtp.con_response.contype = MTP_CONTAINER_TYPE_RESPONSE;
g_usbd_mtp.con_response.code = code;
g_usbd_mtp.con_response.trans_id = g_usbd_mtp.con_command.trans_id;
usbd_ep_start_write(mtp_ep_data[MTP_IN_EP_IDX].ep_addr,
(uint8_t *)&g_usbd_mtp.con_response,
CONFIG_MTP_COMMAND_LEN);
}
static void usbd_mtp_send_info(uint8_t *data, uint32_t len)
{
USB_LOG_DBG("Send info\r\n");
g_usbd_mtp.stage = MTP_SEND_RESPONSE;
g_usbd_mtp.con_data.conlen = CONFIG_MTP_COMMAND_LEN + len;
g_usbd_mtp.con_data.contype = MTP_CONTAINER_TYPE_DATA;
g_usbd_mtp.con_data.code = MTP_RESPONSE_OK;
g_usbd_mtp.con_data.trans_id = g_usbd_mtp.con_command.trans_id;
memcpy(g_usbd_mtp.con_data.data, data, len);
usbd_ep_start_write(mtp_ep_data[MTP_IN_EP_IDX].ep_addr,
(uint8_t *)&g_usbd_mtp.con_data,
CONFIG_MTP_COMMAND_LEN + len);
}
static void usbd_mtp_get_device_info(void)
{
struct mtp_device_info device_info;
uint16_t i;
device_info.StandardVersion = 100;
device_info.VendorExtensionID = 0x06;
device_info.VendorExtensionVersion = 100;
device_info.VendorExtensionDesc_len = (uint8_t)CONFIG_MTP_VEND_EXT_DESC_LEN;
for (i = 0; i < CONFIG_MTP_VEND_EXT_DESC_LEN; i++) {
device_info.VendorExtensionDesc[i] = VendExtDesc[i];
}
/* device supports one mode , standard mode */
device_info.FunctionalMode = 0x0000;
/* All supported operation */
device_info.OperationsSupported_len = CONFIG_MTP_SUPP_OP_LEN;
for (i = 0U; i < CONFIG_MTP_SUPP_OP_LEN; i++) {
device_info.OperationsSupported[i] = SuppOP[i];
}
/* event that are currently generated by the device*/
device_info.EventsSupported_len = CONFIG_MTP_SUPP_EVENTS_LEN;
for (i = 0U; i < CONFIG_MTP_SUPP_EVENTS_LEN; i++) {
device_info.EventsSupported[i] = SuppEvents[i];
}
device_info.DevicePropertiesSupported_len = CONFIG_MTP_SUPP_DEVICE_PROP_LEN;
for (i = 0U; i < CONFIG_MTP_SUPP_DEVICE_PROP_LEN; i++) {
device_info.DevicePropertiesSupported[i] = DevicePropSupp[i];
}
device_info.CaptureFormats_len = CONFIG_MTP_SUPP_CAPT_FORMAT_LEN;
for (i = 0U; i < CONFIG_MTP_SUPP_CAPT_FORMAT_LEN; i++) {
device_info.CaptureFormats[i] = SuppCaptFormat[i];
}
/* number of image formats that are supported by the device*/
device_info.ImageFormats_len = CONFIG_MTP_SUPP_IMG_FORMAT_LEN;
for (i = 0U; i < CONFIG_MTP_SUPP_IMG_FORMAT_LEN; i++) {
device_info.ImageFormats[i] = SuppImgFormat[i];
}
device_info.Manufacturer_len = (uint8_t)CONFIG_MTP_MANUF_LEN;
for (i = 0U; i < CONFIG_MTP_MANUF_LEN; i++) {
device_info.Manufacturer[i] = Manuf[i];
}
device_info.Model_len = (uint8_t)CONFIG_MTP_MODEL_LEN;
for (i = 0U; i < CONFIG_MTP_MODEL_LEN; i++) {
device_info.Model[i] = Model[i];
}
device_info.DeviceVersion_len = (uint8_t)CONFIG_MTP_DEVICE_VERSION_LEN;
for (i = 0U; i < CONFIG_MTP_DEVICE_VERSION_LEN; i++) {
device_info.DeviceVersion[i] = DeviceVers[i];
}
device_info.SerialNumber_len = (uint8_t)CONFIG_MTP_SERIAL_NBR_LEN;
for (i = 0U; i < CONFIG_MTP_SERIAL_NBR_LEN; i++) {
device_info.SerialNumber[i] = SerialNbr[i];
}
usbd_mtp_send_info((uint8_t *)&device_info, sizeof(struct mtp_device_info));
}
static void usbd_mtp_open_session(void)
{
usbd_mtp_send_response(MTP_RESPONSE_OK);
}
static void usbd_mtp_get_storage_ids(void)
{
struct mtp_storage_id storage_id;
storage_id.StorageIDS_len = CONFIG_MTP_STORAGE_ID_LEN;
storage_id.StorageIDS[0] = MTP_STORAGE_ID;
usbd_mtp_send_info((uint8_t *)&storage_id, sizeof(struct mtp_storage_id));
}
static void usbd_mtp_get_storage_info(void)
{
struct mtp_storage_info storage_info;
uint64_t MaxCapability, FreeSpaceInBytes;
storage_info.StorageType = MTP_STORAGE_REMOVABLE_RAM;
storage_info.FilesystemType = MTP_FILESYSTEM_GENERIC_FLAT;
storage_info.AccessCapability = MTP_ACCESS_CAP_RW;
if (usbd_mtp_get_cap(&MaxCapability, &FreeSpaceInBytes))
USB_LOG_ERR("Failed to get storage info \r\n");
storage_info.MaxCapability = MaxCapability;
storage_info.FreeSpaceInBytes = FreeSpaceInBytes;
storage_info.FreeSpaceInObjects = 0xFFFFFFFFU;
storage_info.StorageDescription = 0U;
storage_info.VolumeLabel = 0U;
usbd_mtp_send_info((uint8_t *)&storage_info, sizeof(struct mtp_storage_info));
}
uint16_t _get_format_by_name(char *file_name)
{
uint32_t objformat;
char file_ext[5];
memset(file_ext, 0, sizeof(file_ext));
char* ext = strrchr(file_name, '.');
/* Get file type */
if (ext != 0U && (strlen(ext + 1) <= 5)) {
strcpy(file_ext, (ext + 1));
} else {
objformat = MTP_OBJ_FORMAT_ASSOCIATION;
return objformat;
}
if ((strcmp(file_ext, "TXT") == 0) || (strcmp(file_ext, "txt") == 0)) {
objformat = MTP_OBJ_FORMAT_TEXT;
} else if ((strcmp(file_ext, "JPG") == 0) || (strcmp(file_ext, "jpg") == 0)) {
objformat = MTP_OBJ_FORMAT_EXIF_JPEG;
} else if ((strcmp(file_ext, "BMP") == 0) || (strcmp(file_ext, "bmp") == 0)) {
objformat = MTP_OBJ_FORMAT_BMP;
} else if ((strcmp(file_ext, "PNG") == 0) || (strcmp(file_ext, "png") == 0)) {
objformat = MTP_OBJ_FORMAT_PNG;
} else if ((strcmp(file_ext, "MP4") == 0) || (strcmp(file_ext, "mp4") == 0)) {
objformat = MTP_OBJ_FORMAT_MP4_CONTAINER;
} else if ((strcmp(file_ext, "WAV") == 0) || (strcmp(file_ext, "wav") == 0)) {
objformat = MTP_OBJ_FORMAT_WAV;
} else if ((strcmp(file_ext, "PDF") == 0) || (strcmp(file_ext, "pdf") == 0)) {
objformat = 0x3000U;
} else {
objformat = 0x3000U;
}
/* Return object format */
return objformat;
}
void _string_to_unicode(void *dest, void *src, int len)
{
uint16_t *dest_str = (uint16_t *)dest;
uint8_t *src_str = (uint8_t *)src;
for (int i = 0; i < len; i++) {
*dest_str = (uint16_t)*src_str;
dest_str++;
src_str++;
}
}
void _unicode_to_string(void *dest, void *src, int len)
{
uint8_t *dest_str = (uint8_t *)dest;
uint16_t *src_str = (uint16_t *)src;
for (int i = 0; i < len; i++) {
*dest_str = (uint8_t)*src_str;
dest_str++;
src_str++;
}
}
static int mtp_object_handles_list(struct mtp_object_handle *object_handle,
uint32_t parent_handle, const char *pathname)
{
uint32_t i = 0, index = 0, size = 0, protection_status;
char *path = (char*)pathname;
char file_name[255], fullpath[255];
void *dirent = NULL;
uint8_t file_name_len;
struct mtp_object *object = NULL;
dirent = usbd_mtp_open_dir(pathname);
if (dirent == NULL) {
USB_LOG_DBG("Failed to open %s\r\n", pathname);
return -1;
}
while(usbd_mtp_get_file_info(dirent, file_name,
&file_name_len, &protection_status)) {
/* Get file information */
usbd_mtp_get_fullpath(fullpath, path, file_name);
if (fullpath == NULL)
return -1;
USB_LOG_DBG("fullpath:%s\r\n", fullpath);
size = usbd_mtp_get_file_size(fullpath);
if (size < 0)
break;
/* Creat mtp object */
if (usbd_mtp_creat_object(&object, &index) < 0)
goto __finsh;
object->handle = (uint32_t)(index);
/* property */
object->property.storage_id = MTP_STORAGE_ID;
object->property.format = (uint16_t)_get_format_by_name(file_name);
object->property.protection_status = protection_status;
object->property.size = size;
object->property.file_name_length = file_name_len;
strcpy((char *)object->property.file_name, (char *)file_name);
object->property.file_full_name_length = strlen((char *)fullpath);
strcpy((char *)object->property.file_full_name, (char *)fullpath);
object->property.parent_object = parent_handle;
object->property.identifier[0] = 0U;
/* Add to ObjectHandleList */
object_handle->ObjectHandle[i] = (uint32_t)(index);
USB_LOG_DBG("file:%s(%ld-%ld-%ld-%ld)\r\n", object->property.file_full_name,
object->handle, object_handle->ObjectHandle[i], g_usbd_mtp.handle_counter, i);
memset(file_name, 0, sizeof(file_name));
memset(fullpath, 0, sizeof(fullpath));
if (i >= CONFIG_USBDEV_MTP_GET_MAX_HANDLES)
goto __finsh;
i++;
}
__finsh:
object_handle->ObjectHandle_len = i;
usbd_mtp_close_dir(dirent);
return 0;
}
static void usbd_mtp_get_object_handles(void)
{
struct mtp_object_handle object_handle;
struct mtp_object *object = NULL;
int ret;
memset(&object_handle, 0U, sizeof(struct mtp_object_handle));
if (g_usbd_mtp.con_command.param1 != MTP_STORAGE_ID &&
g_usbd_mtp.con_command.param1 != 0xffffffff) {
usbd_mtp_send_response(MTP_RESPONSE_STORE_NOT_AVAILABLE);
return;
}
if (g_usbd_mtp.con_command.param2 != 0x00000000) {
usbd_mtp_send_response(MTP_RESPONSE_SPECIFICATION_BY_FORMAT_NOT_SUPPORTED);
return;
}
if (g_usbd_mtp.con_command.param3 == 0x00000000 ||
g_usbd_mtp.con_command.param3 == 0xffffffff) {
ret = mtp_object_handles_list(&object_handle, 0U, ROOT_PATH);
if (ret < 0) {
usbd_mtp_send_response(MTP_RESPONSE_INVALID_OBJECT_HANDLE);
return;
}
} else {
usbd_mtp_get_object_by_handle(&object, g_usbd_mtp.con_command.param3);
ret = mtp_object_handles_list(&object_handle, g_usbd_mtp.con_command.param3,
(char *)object->property.file_full_name);
if (ret < 0) {
usbd_mtp_send_response(MTP_RESPONSE_INVALID_OBJECT_HANDLE);
return;
}
}
usbd_mtp_send_info((uint8_t *)&object_handle, sizeof(uint32_t) * (object_handle.ObjectHandle_len + 1U));
}
struct mtp_object_info object_info;
static void usbd_mtp_get_object_info(void)
{
struct mtp_object *object = NULL;
usbd_mtp_get_object_by_handle(&object, (uint32_t)g_usbd_mtp.con_command.param1);
if (object == NULL) {
USB_LOG_ERR("Invalid Object!\r\n");
usbd_mtp_send_response(MTP_RESPONSE_INVALID_OBJECT_HANDLE);
return;
}
memset(&object_info, 0, sizeof(struct mtp_object_info));
object_info.Storage_id = MTP_STORAGE_ID;
object_info.ObjectFormat = object->property.format;
object_info.ProtectionStatus = 0U;
object_info.ObjectCompressedSize = object->property.size;
object_info.ThumbFormat = MTP_OBJ_FORMAT_UNDEFINED;
object_info.ParentObject = object->property.parent_object;
if (object->property.format == MTP_OBJ_FORMAT_ASSOCIATION)
object_info.AssociationType = 0x0001; /* generic folder */
else
object_info.AssociationType = 0U;
object_info.Filename_len = object->property.file_name_length;
_string_to_unicode(object_info.Filename,
object->property.file_name,
object->property.file_name_length);
usbd_mtp_send_info((uint8_t *)&object_info, sizeof(struct mtp_object_info));
}
static void usbd_mtp_get_object(void)
{
int fd;
int32_t ret;
struct mtp_object *object = NULL;
ret = usbd_mtp_get_object_by_handle(&object, g_usbd_mtp.con_command.param1);
if (ret < 0) {
USB_LOG_ERR("Faile to get flie(%s)\r\n", (char *)object->property.file_full_name);
usbd_mtp_send_response(MTP_RESPONSE_INVALID_OBJECT_HANDLE);
return;
}
if (object->property.format == MTP_OBJ_FORMAT_ASSOCIATION) {
USB_LOG_ERR("The object is a folder\r\n");
usbd_mtp_send_response(MTP_RESPONSE_INVALID_OBJECT_HANDLE);
return;
}
/* Read */
fd = usbd_mtp_open_file_rdonly((char *)object->property.file_full_name);
if (fd < 0) {
USB_LOG_ERR("Faile to open file(%s)\r\n", object->property.file_full_name);
usbd_mtp_send_response(MTP_RESPONSE_INCOMPLETE_TRANSFER);
return;
}
int32_t data_length = object->property.size;
/* first packet */
ret = usbd_mtp_read_file(fd, g_usbd_mtp.con_data.data,
MIN(data_length, CONFIG_USBDEV_MTP_MAX_BUFSIZE - CONFIG_MTP_COMMAND_LEN));
g_usbd_mtp.con_data.conlen = CONFIG_MTP_COMMAND_LEN + data_length;
g_usbd_mtp.con_data.contype = MTP_CONTAINER_TYPE_DATA;
g_usbd_mtp.con_data.code = MTP_RESPONSE_OK;
g_usbd_mtp.con_data.trans_id = g_usbd_mtp.con_command.trans_id;
data_length = ((data_length - ret) < 0) ? data_length : (data_length - ret);
if (data_length == 0) {
g_usbd_mtp.stage = MTP_SEND_RESPONSE;
if (usbd_mtp_close_file(fd) < 0) {
USB_LOG_ERR("Falie to close file(%s)\r\n", object->property.file_full_name);
usbd_mtp_send_response(MTP_RESPONSE_INCOMPLETE_TRANSFER);
return;
}
} else {
g_usbd_mtp.stage = MTP_DATA_IN;
g_usbd_mtp.mtp_file_in.handle = g_usbd_mtp.con_command.param1;
g_usbd_mtp.mtp_file_in.fd = fd;
g_usbd_mtp.mtp_file_in.data_length = data_length;
}
usbd_ep_start_write(mtp_ep_data[MTP_IN_EP_IDX].ep_addr,
(uint8_t *)&g_usbd_mtp.con_data,
MIN(g_usbd_mtp.con_data.conlen, CONFIG_USBDEV_MTP_MAX_BUFSIZE));
return;
}
void usbd_mtp_data_in(void)
{
int32_t ret;
int32_t data_length = g_usbd_mtp.mtp_file_in.data_length;
if (data_length <= 0)
return;
ret = usbd_mtp_read_file(g_usbd_mtp.mtp_file_in.fd,
g_usbd_mtp.usbd_mtp_data_in,
MIN(data_length, CONFIG_USBDEV_MTP_MAX_BUFSIZE));
if (ret < 0) {
USB_LOG_ERR("Failed to read file\r\n");
if (usbd_mtp_close_file(g_usbd_mtp.mtp_file_in.fd) < 0) {
USB_LOG_ERR("Falie to close file\r\n");
}
usbd_mtp_send_response(MTP_RESPONSE_INCOMPLETE_TRANSFER);
return;
}
data_length = ((data_length - ret) < 0) ? data_length : (data_length - ret);
g_usbd_mtp.mtp_file_in.data_length = data_length;
if (g_usbd_mtp.mtp_file_in.data_length == 0) {
if (usbd_mtp_close_file(g_usbd_mtp.mtp_file_in.fd) < 0) {
USB_LOG_ERR("Falie to close file\r\n");
return;
}
g_usbd_mtp.stage = MTP_SEND_RESPONSE;
}
usbd_ep_start_write(mtp_ep_data[MTP_IN_EP_IDX].ep_addr,
g_usbd_mtp.usbd_mtp_data_in, ret);
return;
}
static void usbd_mtp_get_object_prop_desc(void)
{
struct mtp_object_prop_desc object_prop_desc;
struct mtp_string mtp_filename;
uint16_t undef_format = MTP_OBJ_FORMAT_UNDEFINED;
uint32_t storageid = MTP_STORAGE_ID;
USB_LOG_DBG("param:%#lx(1)-%#lx(2)\r\n", g_usbd_mtp.con_command.param1, g_usbd_mtp.con_command.param2);
if (g_usbd_mtp.con_command.param2 == MTP_OBJ_FORMAT_UNDEFINED &&
g_usbd_mtp.con_command.param2 == MTP_OBJ_FORMAT_ASSOCIATION) {
usbd_mtp_send_response(MTP_RESPONSE_INVALID_OBJECT_FORMAT_CODE);
return;
}
switch (g_usbd_mtp.con_command.param1) /* switch obj prop code */
{
case MTP_OB_PROP_STORAGE_ID:
object_prop_desc.ObjectPropertyCode = (uint16_t)(g_usbd_mtp.con_command.param1);
object_prop_desc.DataType = MTP_DATATYPE_UINT32;
object_prop_desc.GetSet = MTP_PROP_GET;
object_prop_desc.DefValue = (uint8_t *)&storageid;
object_prop_desc.GroupCode = 0U;
object_prop_desc.FormFlag = 0U;
break;
case MTP_OB_PROP_OBJECT_FORMAT:
object_prop_desc.ObjectPropertyCode = (uint16_t)(g_usbd_mtp.con_command.param1);
object_prop_desc.DataType = MTP_DATATYPE_UINT16;
object_prop_desc.GetSet = MTP_PROP_GET;
object_prop_desc.DefValue = (uint8_t *)&undef_format;
object_prop_desc.GroupCode = 0U;
object_prop_desc.FormFlag = 0U;
break;
case MTP_OB_PROP_PROTECTION_STATUS:
object_prop_desc.ObjectPropertyCode = (uint16_t)(g_usbd_mtp.con_command.param1);
object_prop_desc.DataType = MTP_DATATYPE_UINT16;
object_prop_desc.GetSet = MTP_PROP_GET_SET;
object_prop_desc.DefValue = 0U;
object_prop_desc.GroupCode = 0U;
object_prop_desc.FormFlag = 0U;
break;
case MTP_OB_PROP_OBJ_FILE_NAME:
object_prop_desc.ObjectPropertyCode = (uint16_t)(g_usbd_mtp.con_command.param1);
object_prop_desc.DataType = MTP_DATATYPE_STR;
object_prop_desc.GetSet = MTP_PROP_GET_SET;
mtp_filename.len = (uint8_t)(sizeof(DefaultFileName));
_string_to_unicode(mtp_filename.string,
(char *)DefaultFileName,
mtp_filename.len);
object_prop_desc.DefValue = (uint8_t *)&mtp_filename;
object_prop_desc.GroupCode = 0U;
object_prop_desc.FormFlag = 0U;
break;
case MTP_OB_PROP_PARENT_OBJECT:
object_prop_desc.ObjectPropertyCode = (uint16_t)(g_usbd_mtp.con_command.param1);
object_prop_desc.DataType = MTP_DATATYPE_UINT32;
object_prop_desc.GetSet = MTP_PROP_GET;
object_prop_desc.DefValue = 0U;
object_prop_desc.GroupCode = 0U;
object_prop_desc.FormFlag = 0U;
break;
case MTP_OB_PROP_OBJECT_SIZE:
object_prop_desc.ObjectPropertyCode = (uint16_t)(g_usbd_mtp.con_command.param1);
object_prop_desc.DataType = MTP_DATATYPE_UINT64;
object_prop_desc.GetSet = MTP_PROP_GET;
object_prop_desc.DefValue = 0U;
object_prop_desc.GroupCode = 0U;
object_prop_desc.FormFlag = 0U;
break;
case MTP_OB_PROP_NAME:
object_prop_desc.ObjectPropertyCode = (uint16_t)(g_usbd_mtp.con_command.param1);
object_prop_desc.DataType = MTP_DATATYPE_STR;
object_prop_desc.GetSet = MTP_PROP_GET_SET;
mtp_filename.len = (uint8_t)(sizeof(DefaultFileName));
memcpy((void *)(mtp_filename.string),
(void *)DefaultFileName, sizeof(DefaultFileName));
object_prop_desc.DefValue = (uint8_t *)&mtp_filename;
object_prop_desc.GroupCode = 0U;
object_prop_desc.FormFlag = 0U;
break;
case MTP_OB_PROP_PERS_UNIQ_OBJ_IDEN:
object_prop_desc.ObjectPropertyCode = (uint16_t)(g_usbd_mtp.con_command.param1);
object_prop_desc.DataType = MTP_DATATYPE_UINT128;
object_prop_desc.GetSet = MTP_PROP_GET;
object_prop_desc.DefValue = 0U;
object_prop_desc.GroupCode = 0U;
object_prop_desc.FormFlag = 0U;
break;
default:
break;
}
usbd_mtp_send_info((uint8_t *)&object_prop_desc, sizeof(struct mtp_object_prop_desc));
}
static void usbd_mtp_get_object_props_supported(void)
{
struct mtp_object_props_support object_props_support;
uint32_t i;
object_props_support.ObjectPropCode_len = CONFIG_MTP_SUPP_OBJ_PROP_LEN;
for (i = 0U; i < CONFIG_MTP_SUPP_OBJ_PROP_LEN; i++) {
object_props_support.ObjectPropCode[i] = ObjectPropCode[i];
}
usbd_mtp_send_info((uint8_t *)&object_props_support, sizeof(struct mtp_object_props_support));
}
#if 0
static void usbd_mtp_get_object_prop_value(void)
{
uint8_t *value = NULL;
uint32_t length = 0U;
struct mtp_string file_name;
struct mtp_object *object = NULL;
uint32_t object_handle = g_usbd_mtp.con_command.param1;
uint32_t object_prop_code = g_usbd_mtp.con_command.param2;
usbd_mtp_get_object_by_handle(&object, object_handle);
switch(object_prop_code) {
case MTP_OB_PROP_STORAGE_ID:
length = sizeof(uint32_t);
value = (uint8_t *)&object->property.storage_id;
break;
case MTP_OB_PROP_OBJECT_FORMAT:
length = sizeof(uint16_t);
value = (uint8_t *)&object->property.format;
break;
case MTP_OB_PROP_PROTECTION_STATUS:
length = sizeof(uint16_t);
value = (uint8_t *)&object->property.protection_status;
break;
case MTP_OB_PROP_OBJ_FILE_NAME:
file_name.len = object->property.file_name_length;
_string_to_unicode(file_name.string,
object->property.file_name,
object->property.file_name_length);
length = file_name.len + 1;
value = (uint8_t *)&file_name;
break;
case MTP_OB_PROP_PARENT_OBJECT:
length = sizeof(uint16_t);
value = (uint8_t *)&object->property.parent_object;
break;
case MTP_OB_PROP_OBJECT_SIZE:
length = sizeof(uint16_t);
value = (uint8_t *)&object->property.size;
break;
case MTP_OB_PROP_PERS_UNIQ_OBJ_IDEN:
break;
default:
usbd_mtp_send_response(MTP_RESPONSE_ACCESS_DENIED);
return;
break;
}
memcpy(g_usbd_mtp.usbd_mtp_data_out, (uint8_t *)value, length);
usbd_mtp_send_info((uint8_t *)g_usbd_mtp.usbd_mtp_data_out, length);
}
static void usbd_mtp_set_object_prop_value(void)
{
static uint32_t last_trans_id = 0x0, object_handle, object_prop_code;
uint32_t length = 0U;
struct mtp_object *object = NULL;
if (g_usbd_mtp.con_command.trans_id != last_trans_id) {
last_trans_id = g_usbd_mtp.con_command.trans_id;
object_handle = g_usbd_mtp.con_command.param1;
object_prop_code = g_usbd_mtp.con_command.param2;
usbd_ep_start_read(mtp_ep_data[MTP_OUT_EP_IDX].ep_addr, (uint8_t *)&g_usbd_mtp.con_data, CONFIG_USBDEV_MTP_MAX_BUFSIZE);
return;
}
usbd_mtp_get_object_by_handle(&object, object_handle);
/* Object Prop Code */
switch(object_prop_code) {
case MTP_OB_PROP_STORAGE_ID:
length = sizeof(uint32_t);
memcpy(&object->property.storage_id,
g_usbd_mtp.con_data.data,
length);
break;
case MTP_OB_PROP_OBJECT_FORMAT:
length = sizeof(uint16_t);
memcpy(&object->property.format,
g_usbd_mtp.con_data.data,
length);
break;
case MTP_OB_PROP_PROTECTION_STATUS:
length = sizeof(uint16_t);
memcpy(&object->property.protection_status,
g_usbd_mtp.con_data.data,
length);
break;
case MTP_OB_PROP_OBJ_FILE_NAME:
length = g_usbd_mtp.con_data.data[0];
object->property.file_full_name_length = length;
_unicode_to_string(object->property.file_name,
(char *)&g_usbd_mtp.con_data.data[1],
length);
break;
case MTP_OB_PROP_PARENT_OBJECT:
length = sizeof(uint16_t);
memcpy(&object->property.parent_object,
g_usbd_mtp.con_data.data,
length);
break;
case MTP_OB_PROP_OBJECT_SIZE:
length = sizeof(uint16_t);
memcpy(&object->property.size,
g_usbd_mtp.con_data.data,
length);
break;
case MTP_OB_PROP_NAME:
length = object->property.file_name_length;
memcpy(object->property.file_name,
g_usbd_mtp.con_data.data,
length);
break;
case MTP_OB_PROP_PERS_UNIQ_OBJ_IDEN:
break;
default:
usbd_mtp_send_response(MTP_RESPONSE_OK);
break;
}
usbd_mtp_send_response(MTP_RESPONSE_OK);
}
#endif
#if 0
//todo
uint8_t usbd_mtp_dataset[RINGBUFFER_FIFO];
void usbd_mtp_get_object_prop_list(void)
{
struct mtp_object_prop_list object_prop_list;
uint32_t storageid = MTP_STORAGE_ID;
uint32_t default_val = 0U;
uint16_t format = MTP_OBJ_FORMAT_TEXT;
uint64_t objsize = 3;
uint32_t parent_proval = 4;
uint32_t dataLength = sizeof(uint32_t);
uint32_t element_len =0;
object_prop_list.Properties_len = CONFIG_MTP_SUPP_OBJ_PROP_LEN;
rt_memcpy(usbd_mtp_dataset, (uint8_t *)&object_prop_list.Properties_len, sizeof(uint32_t));
USB_LOG_INFO("usbd_mtp_get_object_prop_list\n param:%#lx(1)-%#lx(2)", g_usbd_mtp.con_command.param1, g_usbd_mtp.con_command.param2);
for (uint8_t i = 0U; i < CONFIG_MTP_SUPP_OBJ_PROP_LEN; i++) {
object_prop_list.Properties[i].ObjectHandle = g_usbd_mtp.con_command.param1;
switch (ObjectPropCode[i]) {
case MTP_OB_PROP_STORAGE_ID:
object_prop_list.Properties[i].PropertyCode = MTP_OB_PROP_STORAGE_ID;
object_prop_list.Properties[i].Datatype = MTP_DATATYPE_UINT32;
object_prop_list.Properties[i].propval.u32 = (uint32_t)storageid;
/* Copy object property code to the payload data */
element_len = sizeof(object_prop_list.Properties[i]) - 8U + sizeof(uint32_t);
rt_memcpy(usbd_mtp_dataset + dataLength, &object_prop_list.Properties[i],
element_len);
break;
case MTP_OB_PROP_OBJECT_FORMAT:
object_prop_list.Properties[i].PropertyCode = MTP_OB_PROP_OBJECT_FORMAT;
object_prop_list.Properties[i].Datatype = MTP_DATATYPE_UINT16;
object_prop_list.Properties[i].propval.u16 = (uint16_t)format;
/* Copy object property code to the payload data */
element_len = sizeof(object_prop_list.Properties[i]) - 8U + sizeof(uint16_t);
rt_memcpy(usbd_mtp_dataset + dataLength, &object_prop_list.Properties[i],
element_len);
break;
case MTP_OB_PROP_OBJECT_SIZE:
object_prop_list.Properties[i].PropertyCode = MTP_OB_PROP_OBJECT_SIZE;
object_prop_list.Properties[i].Datatype = MTP_DATATYPE_UINT64;
object_prop_list.Properties[i].propval.u64 = (uint64_t)objsize;
element_len = sizeof(object_prop_list.Properties[i]) - 8U + sizeof(uint16_t);
rt_memcpy(usbd_mtp_dataset + dataLength, &object_prop_list.Properties[i],
element_len);
break;
case MTP_OB_PROP_OBJ_FILE_NAME:
object_prop_list.Properties[i].PropertyCode = MTP_OB_PROP_OBJ_FILE_NAME;
object_prop_list.Properties[i].Datatype = MTP_DATATYPE_STR;
mtp_filename.len = CONFIG_MTP_FILE_NAME_LEN;
memcpy(mtp_filename.string, DefaultFileName, sizeof(DefaultFileName));
object_prop_list.Properties[i].propval.str = (uint8_t *)&mtp_filename;
element_len = sizeof(object_prop_list.Properties[i]) - 8U;
rt_memcpy(usbd_mtp_dataset + dataLength, &object_prop_list.Properties[i],
element_len);
dataLength += element_len;
element_len = mtp_filename.len * 2U + 1U;
rt_memcpy(usbd_mtp_dataset + dataLength, object_prop_list.Properties[i].propval.str,
element_len);
break;
case MTP_OB_PROP_PARENT_OBJECT:
object_prop_list.Properties[i].PropertyCode = MTP_OB_PROP_PARENT_OBJECT;
object_prop_list.Properties[i].Datatype = MTP_DATATYPE_UINT32;
object_prop_list.Properties[i].propval.u32 = (uint32_t)parent_proval;
element_len = sizeof(object_prop_list.Properties[i]) - 8U + sizeof(uint32_t);
rt_memcpy(usbd_mtp_dataset + dataLength, &object_prop_list.Properties[i],
element_len);
break;
case MTP_OB_PROP_NAME:
object_prop_list.Properties[i].PropertyCode = MTP_OB_PROP_NAME;
object_prop_list.Properties[i].Datatype = MTP_DATATYPE_STR;
mtp_filename.len = CONFIG_MTP_FILE_NAME_LEN;
rt_memcpy((void *)(mtp_filename.string), (void *)DefaultFileName,
sizeof(DefaultFileName));
object_prop_list.Properties[i].propval.str = (uint8_t *)&mtp_filename;
element_len = sizeof(object_prop_list.Properties[i]) - 8U;
rt_memcpy(usbd_mtp_dataset + dataLength, &object_prop_list.Properties[i],
element_len);
dataLength += element_len;
element_len = mtp_filename.len * 2U + 1U;
rt_memcpy(usbd_mtp_dataset + dataLength, object_prop_list.Properties[i].propval.str,
element_len);
break;
case MTP_OB_PROP_PERS_UNIQ_OBJ_IDEN:
object_prop_list.Properties[i].PropertyCode = MTP_OB_PROP_PERS_UNIQ_OBJ_IDEN;
object_prop_list.Properties[i].Datatype = MTP_DATATYPE_UINT8;
object_prop_list.Properties[i].propval.u8 = (uint8_t)g_usbd_mtp.con_command.param1;
element_len = sizeof(object_prop_list.Properties[i]) - 8U + sizeof(uint8_t);
rt_memcpy(usbd_mtp_dataset + dataLength, &object_prop_list.Properties[i],
element_len);
break;
case MTP_OB_PROP_PROTECTION_STATUS:
object_prop_list.Properties[i].PropertyCode = MTP_OB_PROP_PROTECTION_STATUS;
object_prop_list.Properties[i].Datatype = MTP_DATATYPE_UINT16;
object_prop_list.Properties[i].propval.u16 = (uint16_t)default_val;
element_len = sizeof(object_prop_list.Properties[i]) - 8U + sizeof(uint16_t);
rt_memcpy(usbd_mtp_dataset + dataLength, &object_prop_list.Properties[i],
element_len);
break;
default:
break;
}
dataLength += element_len;
}
usbd_mtp_send_info((uint8_t *)usbd_mtp_dataset, dataLength + sizeof(uint32_t));
}
# endif
void usbd_mtp_send_object_info(void)
{
static uint32_t last_trans_id = 0x0;
uint32_t index, parent_handle = g_usbd_mtp.con_command.param2;
uint64_t MaxCapability, FreeSpaceInBytes;
int fd = 0;
char filename_tmp[255];
struct mtp_object_info *object_info;
struct mtp_object *object = NULL;
if (g_usbd_mtp.con_command.trans_id != last_trans_id) {
last_trans_id = g_usbd_mtp.con_command.trans_id;
memset(g_usbd_mtp.path, 0, sizeof(g_usbd_mtp.path));
if (parent_handle == 0xffffffff) {
/* place object in root */
strcat(g_usbd_mtp.path, ROOT_PATH);
} else {
usbd_mtp_get_object_by_handle(&object, parent_handle);
strcpy(g_usbd_mtp.path, (char *)object->property.file_full_name);
}
/* No response */
usbd_ep_start_read(mtp_ep_data[MTP_OUT_EP_IDX].ep_addr, (uint8_t *)&g_usbd_mtp.con_data,
CONFIG_USBDEV_MSC_MAX_BUFSIZE);
return;
}
/* Make sure we can accommodate a new object here */
if ((g_usbd_mtp.handle_counter + 1U) < MTP_OBJECT_HANDLES_MAX_NUM) {
/* Get ObjecyInfo Dataset*/
object_info = (struct mtp_object_info *)&g_usbd_mtp.con_data.data;
_unicode_to_string(filename_tmp,
object_info->Filename,
object_info->Filename_len);
strcat(g_usbd_mtp.path, "/");
strcat(g_usbd_mtp.path, filename_tmp);
/* Create file or directory */
USB_LOG_DBG("%s\n", g_usbd_mtp.path);
if (object_info->ObjectFormat != MTP_OBJ_FORMAT_ASSOCIATION)
fd = usbd_mtp_creat_file(g_usbd_mtp.path);
else
usbd_mtp_make_dir(g_usbd_mtp.path);
if (fd >= 0) {
usbd_mtp_creat_object(&object, &index);
object->handle = index;
object->property.storage_id = MTP_STORAGE_ID;
object->property.format = object_info->ObjectFormat;
object->property.protection_status = object_info->ProtectionStatus;
object->property.size = object_info->ObjectCompressedSize;
if (usbd_mtp_get_cap(&MaxCapability, &FreeSpaceInBytes))
USB_LOG_ERR("Failed to get storage info \r\n");
if (object->property.size > FreeSpaceInBytes) {
USB_LOG_ERR("Store full! object size:%ld freespace:%lld\r\n",
object->property.size, FreeSpaceInBytes);
goto __store_full;
}
object->property.parent_object = parent_handle;
object->property.file_name_length = object_info->Filename_len;
_unicode_to_string(object->property.file_name,
object_info->Filename,
object->property.file_name_length);
object->property.file_full_name_length = strlen(g_usbd_mtp.path);
strcpy((char *)object->property.file_full_name, g_usbd_mtp.path);
/* Close file */
if (object_info->ObjectFormat != MTP_OBJ_FORMAT_ASSOCIATION)
usbd_mtp_close_file(fd);
g_usbd_mtp.mtp_file_out.handle = object->handle;
} else {
/* Identify the problem type of file creation */
switch(fd) {
// case :
// break;
default :
goto __store_full;
break;
}
/* Failed to creat file */
memset(object_info, 0, sizeof(struct mtp_object_info));
return;
}
} else {
USB_LOG_ERR("Store full! handle_counter%ld\r\n", g_usbd_mtp.handle_counter + 1U);
goto __store_full;
}
usbd_mtp_send_response_param(MTP_RESPONSE_OK, object->property.storage_id,
object->property.parent_object,
object->handle, 0, 0);
return;
__store_full:
USB_LOG_ERR("Store full! Failed to create file!%d\r\n", fd);
usbd_mtp_send_response(MTP_RESPONSE_STORE_FULL);
}
void usbd_mtp_data_out(void)
{
int32_t ret;
int32_t data_length = g_usbd_mtp.usbd_mtp_wcnt;
if (data_length <= 0) {
usbd_mtp_send_response(MTP_RESPONSE_OK);
return;
}
ret = usbd_mtp_write_file(g_usbd_mtp.mtp_file_out.fd,
g_usbd_mtp.usbd_mtp_data_out,
g_usbd_mtp.mtp_file_out.data_length);
if (ret <= 0) {
usbd_mtp_send_response(MTP_RESPONSE_INCOMPLETE_TRANSFER);
if (usbd_mtp_close_file(g_usbd_mtp.mtp_file_out.fd) < 0) {
USB_LOG_ERR("Falie to close file\r\n");
}
return;
}
data_length = ((data_length - ret) < 0) ? data_length : (data_length - ret);
g_usbd_mtp.mtp_file_out.data_length = MIN(data_length, CONFIG_USBDEV_MTP_MAX_BUFSIZE);
g_usbd_mtp.usbd_mtp_wcnt = data_length;
if (g_usbd_mtp.usbd_mtp_wcnt == 0) {
if (usbd_mtp_close_file(g_usbd_mtp.mtp_file_out.fd) < 0) {
USB_LOG_ERR("Falie to close file\r\n");
return;
}
usbd_mtp_send_response(MTP_RESPONSE_OK);
return;
}
usbd_ep_start_read(mtp_ep_data[MTP_OUT_EP_IDX].ep_addr,
g_usbd_mtp.usbd_mtp_data_out, CONFIG_USBDEV_MTP_MAX_BUFSIZE);
}
void usbd_mtp_send_object(void)
{
static uint32_t last_trans_id = 0x0;
int fd;
int32_t ret;
struct mtp_object *object = NULL;
if (g_usbd_mtp.con_command.trans_id != last_trans_id) {
last_trans_id = g_usbd_mtp.con_command.trans_id;
usbd_ep_start_read(mtp_ep_data[MTP_OUT_EP_IDX].ep_addr, (uint8_t *)&g_usbd_mtp.con_data, CONFIG_USBDEV_MTP_MAX_BUFSIZE);
return;
}
ret = usbd_mtp_get_object_by_handle(&object, g_usbd_mtp.mtp_file_out.handle);
if (ret < 0) {
USB_LOG_ERR("Faile to get flie(%s)\r\n", (char *)object->property.file_full_name);
usbd_mtp_send_response(MTP_RESPONSE_INVALID_OBJECT_HANDLE);
return;
}
/* Write */
fd = usbd_mtp_open_file_wronly((char *)object->property.file_full_name);
if (fd < 0) {
USB_LOG_ERR("Faile to open file(%s)\r\n", (char *)object->property.file_full_name);
usbd_mtp_send_response(MTP_RESPONSE_INCOMPLETE_TRANSFER);
return;
}
uint32_t data_length = g_usbd_mtp.con_data.conlen - CONFIG_MTP_COMMAND_LEN;
if (data_length > CONFIG_USBDEV_MTP_MAX_BUFSIZE - CONFIG_MTP_COMMAND_LEN)
g_usbd_mtp.stage = MTP_DATA_OUT;
g_usbd_mtp.usbd_mtp_wcnt = data_length;
g_usbd_mtp.mtp_file_out.fd = fd;
g_usbd_mtp.mtp_file_out.data_length = MIN(data_length,
CONFIG_USBDEV_MTP_MAX_BUFSIZE - CONFIG_MTP_COMMAND_LEN);
memcpy(g_usbd_mtp.usbd_mtp_data_out, g_usbd_mtp.con_data.data,
MIN(data_length, CONFIG_USBDEV_MTP_MAX_BUFSIZE - CONFIG_MTP_COMMAND_LEN));
usbd_mtp_data_out();
return;
}
void usbd_mtp_delete_object(void)
{
int ret = 0;
struct mtp_object *object = NULL;
/* Delete all objects */
if (g_usbd_mtp.con_command.param1 == 0xffffffff) {
USB_LOG_ERR("Delete all objects!\r\n");
}
usbd_mtp_get_object_by_handle(&object, g_usbd_mtp.con_command.param1);
usbd_mtp_unlink_object(object);
if (ret < 0) {
USB_LOG_ERR("Failed to detele flle(%s)\r\n", (char *)object->property.file_name);
usbd_mtp_send_response(MTP_RESPONSE_INVALID_OBJECT_HANDLE);
return;
}
usbd_mtp_send_response(MTP_RESPONSE_OK);
}
static void usbd_mtp_get_device_prop_desc(void)
{
struct mtp_device_prop_desc device_prop_desc;
uint32_t i;
device_prop_desc.DevicePropertyCode = MTP_DEV_PROP_DEVICE_FRIENDLY_NAME;
device_prop_desc.DataType = MTP_DATATYPE_STR;
device_prop_desc.GetSet = MTP_PROP_GET_SET;
device_prop_desc.DefaultValue_len = CONFIG_MTP_DEVICE_PROP_DESC_DEF_LEN;
for (i = 0U; i < (sizeof(DevicePropDefVal) / 2U); i++) {
device_prop_desc.DefaultValue[i] = DevicePropDefVal[i];
}
device_prop_desc.CurrentValue_len = CONFIG_MTP_DEVICE_PROP_DESC_CUR_LEN;
for (i = 0U; i < (sizeof(DevicePropCurDefVal) / 2U); i++) {
device_prop_desc.CurrentValue[i] = DevicePropCurDefVal[i];
}
device_prop_desc.FormFlag = 0U;
usbd_mtp_send_info((uint8_t *)&device_prop_desc, sizeof(struct mtp_device_prop_desc));
}
static int usbd_mtp_decode(struct mtp_container *container)
{
switch (container->code) {
case MTP_OP_GET_DEVICE_INFO:
usbd_mtp_get_device_info();
break;
case MTP_OP_OPEN_SESSION:
usbd_mtp_open_session();
break;
case MTP_OP_CLOSE_SESSION:
break;
case MTP_OP_GET_STORAGE_IDS:
usbd_mtp_get_storage_ids();
break;
case MTP_OP_GET_STORAGE_INFO:
usbd_mtp_get_storage_info();
break;
case MTP_OP_GET_OBJECT_HANDLES:
usbd_mtp_get_object_handles();
break;
case MTP_OP_GET_OBJECT_INFO:
usbd_mtp_get_object_info();
break;
case MTP_OP_GET_OBJECT_PROP_REFERENCES:
break;
case MTP_OP_GET_OBJECT_PROPS_SUPPORTED:
usbd_mtp_get_object_props_supported();
break;
case MTP_OP_GET_OBJECT_PROP_DESC:
usbd_mtp_get_object_prop_desc();
break;
case MTP_OP_GET_OBJECT_PROPLIST:
break;
case MTP_OP_SET_OBJECT_PROP_VALUE:
// usbd_mtp_set_object_prop_value();
break;
case MTP_OP_GET_OBJECT_PROP_VALUE:
// usbd_mtp_get_object_prop_value();
break;
case MTP_OP_GET_DEVICE_PROP_DESC:
usbd_mtp_get_device_prop_desc();
break;
case MTP_OP_GET_OBJECT:
usbd_mtp_get_object();
break;
case MTP_OP_SEND_OBJECT_INFO:
usbd_mtp_send_object_info();
break;
case MTP_OP_SEND_OBJECT:
usbd_mtp_send_object();
break;
case MTP_OP_DELETE_OBJECT:
usbd_mtp_delete_object();
break;
default:
USB_LOG_WRN("code:%04x\r\n", container->code);
break;
}
return 0;
}
static void usbd_mtp_bulk_out(uint8_t ep, uint32_t nbytes)
{
switch (g_usbd_mtp.stage) {
case MTP_READ_COMMAND:
#ifdef CONFIG_USBDEV_MTP_THREAD
usb_osal_mq_send(g_usbd_mtp.usbd_mtp_mq, MTP_READ_COMMAND);
#else
usbd_mtp_decode((struct mtp_container *)&g_usbd_mtp.con_command);
#endif
break;
case MTP_DATA_OUT:
#ifdef CONFIG_USBDEV_MTP_THREAD
usb_osal_mq_send(g_usbd_mtp.usbd_mtp_mq, MTP_DATA_OUT);
#else
usbd_mtp_data_out();
#endif
break;
default:
break;
}
}
static void usbd_mtp_bulk_in(uint8_t ep, uint32_t nbytes)
{
switch (g_usbd_mtp.stage) {
case MTP_DATA_IN:
#ifdef CONFIG_USBDEV_MTP_THREAD
usb_osal_mq_send(g_usbd_mtp.usbd_mtp_mq, MTP_DATA_IN);
#else
usbd_mtp_data_in();
#endif
break;
case MTP_SEND_RESPONSE:
usbd_mtp_send_response(MTP_RESPONSE_OK);
break;
case MTP_WAIT_RESPONSE:
g_usbd_mtp.stage = MTP_READ_COMMAND;
usbd_ep_start_read(mtp_ep_data[MTP_OUT_EP_IDX].ep_addr, (uint8_t *)&g_usbd_mtp.con_command, CONFIG_USBDEV_MTP_MAX_BUFSIZE);
break;
default:
break;
}
}
static void mtp_notify_handler(uint8_t event, void *arg)
{
switch (event) {
case USBD_EVENT_RESET:
break;
case USBD_EVENT_CONFIGURED:
USB_LOG_DBG("Start reading command\r\n");
g_usbd_mtp.stage = MTP_READ_COMMAND;
usbd_ep_start_read(mtp_ep_data[MTP_OUT_EP_IDX].ep_addr, (uint8_t *)&g_usbd_mtp.con_command, CONFIG_USBDEV_MTP_MAX_BUFSIZE);
break;
default:
break;
}
}
#ifdef CONFIG_USBDEV_MTP_THREAD
static void usbdev_mtp_thread(void *argument)
{
uintptr_t event;
int ret;
while (1) {
ret = usb_osal_mq_recv(g_usbd_mtp.usbd_mtp_mq, (uintptr_t *)&event, USB_OSAL_WAITING_FOREVER);
if (ret < 0) {
continue;
}
USB_LOG_DBG("%d\r\n", event);
if (event == MTP_DATA_OUT) {
usbd_mtp_data_out();
} else if (event == MTP_DATA_IN) {
usbd_mtp_data_in();
} else if (event == MTP_READ_COMMAND) {
usbd_mtp_decode((struct mtp_container *)&g_usbd_mtp.con_command);
} else {
}
}
}
#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)
{
g_usbd_mtp.handle_counter = 0U;
g_usbd_mtp.mtp_objects = mtp_objects;
intf->class_interface_handler = mtp_class_interface_request_handler;
intf->class_endpoint_handler = NULL;
intf->vendor_handler = NULL;
intf->notify_handler = mtp_notify_handler;
mtp_ep_data[MTP_OUT_EP_IDX].ep_addr = out_ep;
mtp_ep_data[MTP_OUT_EP_IDX].ep_cb = usbd_mtp_bulk_out;
mtp_ep_data[MTP_IN_EP_IDX].ep_addr = in_ep;
mtp_ep_data[MTP_IN_EP_IDX].ep_cb = usbd_mtp_bulk_in;
mtp_ep_data[MTP_INT_EP_IDX].ep_addr = int_ep;
mtp_ep_data[MTP_INT_EP_IDX].ep_cb = NULL;
usbd_add_endpoint(&mtp_ep_data[MTP_OUT_EP_IDX]);
usbd_add_endpoint(&mtp_ep_data[MTP_IN_EP_IDX]);
usbd_add_endpoint(&mtp_ep_data[MTP_INT_EP_IDX]); //event
#ifdef CONFIG_USBDEV_MTP_THREAD
g_usbd_mtp.usbd_mtp_mq = usb_osal_mq_create(DATA_BUFFER_SIZE / MAX_WITTE_FILE_SIZE);
if (g_usbd_mtp.usbd_mtp_mq == NULL) {
return NULL;
}
g_usbd_mtp.usbd_mtp_thread = usb_osal_thread_create("usbd_mtp", 1024 * 6, CONFIG_USBDEV_MSC_PRIO, usbdev_mtp_thread, NULL);
if (g_usbd_mtp.usbd_mtp_thread == NULL) {
return NULL;
}
#endif
return intf;
}