MCUXpresso_MIMXRT1021xxxxx/boards/evkmimxrt1020/usb_examples/usb_device_mtp_lite/bm/mtp_operation.c
2022-08-23 23:00:33 +08:00

2895 lines
101 KiB
C

/*
* Copyright 2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "usb_device_config.h"
#include "usb.h"
#include "usb_device.h"
#include "usb_device_mtp.h"
#include "usb_device_ch9.h"
#include "usb_device_descriptor.h"
#include "mtp_file_system_adapter.h"
#include "mtp_object_handle.h"
#include "mtp_operation.h"
#include "mtp.h"
#include "fsl_debug_console.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define MTP_DATE_TIME_LEN (8U * 2U) /* The length of datetime */
#define MTP_BLOCK_SIZE (512U)
/*******************************************************************************
* Prototypes
******************************************************************************/
#if USB_DEVICE_CONFIG_USE_TASK
extern void USB_DeviceTaskFn(void *deviceHandle);
#endif
/*******************************************************************************
* Variables
******************************************************************************/
extern usb_mtp_struct_t g_mtp;
extern uint32_t g_mtpTransferBuffer[USB_DEVICE_MTP_TRANSFER_BUFF_SIZE >> 2];
/*******************************************************************************
* Code
******************************************************************************/
uint32_t USB_DeviceMemCopyArray(void *desBuf, const void *srcBuf, uint32_t size, uint32_t elementSize, uint32_t index)
{
uint8_t *buffer = (uint8_t *)desBuf;
uint32_t elementCnt = size / elementSize;
buffer += index;
*buffer++ = (uint8_t)elementCnt;
*buffer++ = (uint8_t)(elementCnt >> 8U);
*buffer++ = (uint8_t)(elementCnt >> 16U);
*buffer++ = (uint8_t)(elementCnt >> 24U);
index += 4U;
(void)memcpy((void *)buffer, (void *)srcBuf, size);
return (index + size);
}
/* ascll to unicode */
uint32_t USB_DeviceMemCopyString(void *desBuf, const char *srcBuf, uint32_t index)
{
uint8_t *buffer = (uint8_t *)desBuf;
uint32_t i;
if (srcBuf == NULL)
{
buffer += index;
buffer[0] = 0x00U;
return (index + 1U);
}
else
{
i = 0;
index += 1U;
buffer += index;
while (srcBuf[i] != 0x00U)
{
buffer[(i << 1U)] = srcBuf[i];
buffer[(i << 1U) + 1U] = 0x00U;
i++;
}
buffer[(i << 1U)] = 0x00U;
buffer[(i << 1U) + 1U] = 0x00U; /* terminate with 0x00, 0x00 */
i += 1;
*(buffer - 1U) = i; /* the number of char */
return (index + (i << 1U));
}
}
uint32_t USB_DeviceMemCopyByte(void *desBuf, uint8_t byte, uint32_t index)
{
uint8_t *buffer = (uint8_t *)desBuf;
buffer += index;
buffer[0] = byte;
return (index + 1U);
}
uint32_t USB_DeviceMemCopyWord(void *desBuf, uint16_t word, uint32_t index)
{
uint8_t *buffer = (uint8_t *)desBuf;
buffer += index;
buffer[0] = (uint8_t)word;
buffer[1] = (uint8_t)(word >> 8U);
return (index + 2U);
}
uint32_t USB_DeviceMemCopyDword(void *desBuf, uint32_t dword, uint32_t index)
{
uint8_t *buffer = (uint8_t *)desBuf;
buffer += index;
buffer[0] = (uint8_t)dword;
buffer[1] = (uint8_t)(dword >> 8U);
buffer[2] = (uint8_t)(dword >> 16U);
buffer[3] = (uint8_t)(dword >> 24U);
return (index + 4U);
}
uint32_t USB_DeviceMemCopyQword(void *desBuf, uint64_t dword, uint32_t index)
{
uint8_t *buffer = (uint8_t *)desBuf;
buffer += index;
(void)memcpy((void *)buffer, (void *)&dword, 8U);
return (index + 8U);
}
uint32_t USB_DeviceMemCopyUnicodeString(void *desBuf, const uint16_t *srcBuf, uint32_t index)
{
uint8_t *buffer = (uint8_t *)desBuf;
const uint8_t *src = (const uint8_t *)srcBuf;
uint32_t count;
if (srcBuf == NULL)
{
if (index != 0U)
{
buffer += index;
buffer[0] = 0x00U;
return (index + 1U);
}
return 0;
}
else
{
count = 0U;
if (index != 0U)
{
index += 1U;
}
buffer += index;
while ((src[count] != 0U) || (src[count + 1U] != 0U) || ((count % 2U) != 0U))
{
buffer[count] = src[count];
count++;
}
buffer[count] = 0U;
buffer[count + 1U] = 0U; /* terminate with 0x00, 0x00 */
count += 2;
if (index != 0U)
{
*(buffer - 1U) = count >> 1U; /* the number of char */
}
return (count + index);
}
}
uint32_t USB_DeviceUnicodeStringLength(const uint16_t *srcBuf)
{
const uint8_t *src = (const uint8_t *)srcBuf;
uint32_t count = 0;
if (srcBuf == NULL)
{
return 0;
}
while ((src[count] != 0U) || (src[count + 1U] != 0U) || ((count % 2U) != 0U))
{
count++;
}
return count;
}
static uint32_t USB_DeviceParseDataType(uint16_t dataType, void *buffer, void *val, uint32_t offset)
{
uint32_t index;
switch (dataType)
{
case MTP_TYPE_STR:
offset = USB_DeviceMemCopyString(buffer, val, offset);
break;
case MTP_TYPE_INT8:
case MTP_TYPE_UINT8:
offset = USB_DeviceMemCopyByte(buffer, *(uint8_t *)val, offset);
break;
case MTP_TYPE_INT16:
case MTP_TYPE_UINT16:
offset = USB_DeviceMemCopyWord(buffer, *(uint16_t *)val, offset);
break;
case MTP_TYPE_INT32:
case MTP_TYPE_UINT32:
offset = USB_DeviceMemCopyDword(buffer, *(uint32_t *)val, offset);
break;
case MTP_TYPE_INT64:
case MTP_TYPE_UINT64:
offset = USB_DeviceMemCopyQword(buffer, *(uint64_t *)val, offset);
break;
case MTP_TYPE_INT128:
case MTP_TYPE_UINT128:
/* Only property of Persistent UID is UINT128 type.
The default value is 0x0...0, so there is a special process*/
if (val == NULL)
{
offset = USB_DeviceMemCopyQword(buffer, 0x00U, offset);
offset = USB_DeviceMemCopyQword(buffer, 0x00U, offset);
}
else
{
offset = USB_DeviceMemCopyQword(buffer, *(uint64_t *)val, offset);
offset = USB_DeviceMemCopyQword(buffer, *((uint64_t *)val + 1U), offset);
}
break;
case MTP_TYPE_AINT8:
case MTP_TYPE_AUINT8:
/* For array, the default value in the property description is only 0x00U. */
offset = USB_DeviceMemCopyDword(buffer, *(uint32_t *)val, offset);
for (index = 0; index < *(uint32_t *)val; index++)
{
offset = USB_DeviceMemCopyByte(buffer, ((uint8_t *)val)[index + 4U], offset);
}
break;
case MTP_TYPE_AINT16:
case MTP_TYPE_AUINT16:
/* For array, the default value in the property description is only 0x00U. */
offset = USB_DeviceMemCopyDword(buffer, *(uint32_t *)val, offset);
for (index = 0; index < *(uint32_t *)val; index++)
{
offset = USB_DeviceMemCopyWord(buffer, ((uint16_t *)val)[index + 2U], offset);
}
break;
default:
/* no action */
break;
}
return offset;
}
static void USB_DeviceParseDateTime(const uint16_t *dateTime, usb_device_mtp_file_time_stamp_t *timeStamp)
{
const uint8_t *src = (const uint8_t *)dateTime;
memset((void *)timeStamp, 0U, sizeof(usb_device_mtp_file_time_stamp_t));
/* dateTime is unicode string. */
timeStamp->year += (*src - '0') * 1000U;
src += 2U;
timeStamp->year += (*src - '0') * 100U;
src += 2U;
timeStamp->year += (*src - '0') * 10U;
src += 2U;
timeStamp->year += (*src - '0');
src += 2U;
timeStamp->month += (*src - '0') * 10U;
src += 2U;
timeStamp->month += (*src - '0');
src += 2U;
timeStamp->day += (*src - '0') * 10U;
src += 2U;
timeStamp->day += (*src - '0');
src += 2U;
src += 2U; /* skip delimiter 'T' */
timeStamp->hour += (*src - '0') * 10U;
src += 2U;
timeStamp->hour += (*src - '0');
src += 2U;
timeStamp->minute += (*src - '0') * 10U;
src += 2U;
timeStamp->minute += (*src - '0');
src += 2U;
timeStamp->second += (*src - '0') * 10U;
src += 2U;
timeStamp->second += (*src - '0');
}
/* return number of bytes. */
static uint32_t USB_DeviceGetRootPath(usb_mtp_struct_t *mtp, uint32_t storageID, uint8_t *path)
{
uint8_t i;
for (i = 0; i < mtp->storageList->storageCount; i++)
{
if (storageID == mtp->storageList->storageInfo[i].storageID)
{
return USB_DeviceMemCopyUnicodeString(path, (const uint16_t *)mtp->storageList->storageInfo[i].rootPath, 0);
}
}
return 0;
}
static usb_status_t USB_DeviceBuildPath(usb_mtp_struct_t *mtp, uint32_t storageID, uint32_t objHandle, uint8_t *path)
{
usb_status_t result;
usb_mtp_obj_handle_t objHandleStruct;
uint8_t nameLen;
uint32_t backwardOffset;
uint32_t forwardOffset;
uint32_t i;
backwardOffset = USB_DeviceGetRootPath(mtp, storageID, path);
backwardOffset -= 2U; /* remove null-terminated */
forwardOffset = MTP_PATH_MAX_LEN;
objHandleStruct.idUnion.parentID = objHandle;
while (objHandleStruct.idUnion.parentID != 0U)
{
result = USB_DeviceMtpObjHandleRead(objHandleStruct.idUnion.parentID, &objHandleStruct);
if ((result != kStatus_USB_Success) || ((objHandleStruct.flag & MTP_OBJECT_DELETE) != 0U))
{
usb_echo("USB build path failed\r\n");
return kStatus_USB_Error;
}
nameLen = USB_DeviceUnicodeStringLength(objHandleStruct.name);
forwardOffset -= nameLen;
forwardOffset -= 2U;
if ((forwardOffset < backwardOffset) || (forwardOffset > MTP_PATH_MAX_LEN))
{
/* please increase the length of path. */
usb_echo("Please increase the length of path\r\n");
return kStatus_USB_Error;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
/* now i indicates the offset */
i = USB_DeviceMemCopyUnicodeString(&path[forwardOffset], objHandleStruct.name, 0);
#else
(void)USB_DeviceMemCopyUnicodeString(&path[forwardOffset], objHandleStruct.name, 0);
#endif
path[forwardOffset + nameLen] = '/';
path[forwardOffset + nameLen + 1U] = '\0';
}
if (forwardOffset < MTP_PATH_MAX_LEN)
{
path[MTP_PATH_MAX_LEN - 1U] = '\0';
path[MTP_PATH_MAX_LEN - 2U] = '\0';
path[backwardOffset - 2U] = '/';
path[backwardOffset - 1U] = '\0';
if (forwardOffset > backwardOffset)
{
for (i = 0; i < (MTP_PATH_MAX_LEN - forwardOffset); i++)
{
path[i + backwardOffset] = path[i + forwardOffset];
}
}
else
{
/* no action, the path has been built, forwardOffset == backwardOffset */
}
}
else
{
/* no action, root path, forwardOffset == MTP_PATH_MAX_LEN */
}
return kStatus_USB_Success;
}
usb_status_t USB_DeviceGetObjHandleInfo(usb_mtp_struct_t *mtp,
uint32_t objHandle,
usb_mtp_obj_handle_t *objHandleStruct)
{
usb_status_t result;
result = USB_DeviceMtpObjHandleRead(objHandle, objHandleStruct);
if ((result != kStatus_USB_Success) || ((objHandleStruct->flag & MTP_OBJECT_DELETE) != 0U) ||
(objHandleStruct->handleID != objHandle))
{
/* Invalid object handle */
return kStatus_USB_Error;
}
return kStatus_USB_Success;
}
static uint16_t USB_DeviceIdentifyFileType(usb_mtp_obj_handle_t *objHandleStruct)
{
/* TODO: identify more object properties. */
if ((objHandleStruct->flag & MTP_OBJECT_DIR) != 0U)
{
return MTP_FORMAT_ASSOCIATION;
}
else
{
return MTP_FORMAT_UNDEFINED;
}
}
uint32_t USB_DeviceCheckDirDepth(const uint16_t *path)
{
const uint8_t *src = (const uint8_t *)path;
uint32_t count = 0;
uint32_t depthCount = 0;
if (path == NULL)
{
return 0;
}
while ((src[count] != 0U) || (src[count + 1U] != 0U) || ((count % 2U) != 0U))
{
if ((src[count] == '/') && (src[count + 1U] == '\0') && ((count % 2U) == 0U))
{
depthCount++;
}
count++;
}
return depthCount;
}
usb_status_t USB_DeviceDeleteDir(uint8_t *path)
{
static usb_device_mtp_file_info_t fno;
static uint32_t nestedDepth = 0U;
static uint32_t length2;
usb_status_t result;
usb_device_mtp_dir_handle_t dir;
uint32_t length;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
uint32_t offset = 0U;
#endif
if (nestedDepth >= USB_DEVICE_MTP_DIR_INSTANCE)
{
usb_echo("The nested directory is too deep, please increase the dir instance\r\n");
return kStatus_USB_Error;
}
nestedDepth++;
result = USB_DeviceMtpOpenDir(&dir, (const uint16_t *)path);
if (result == kStatus_USB_Success)
{
length = USB_DeviceUnicodeStringLength((const uint16_t *)&path[0]);
path[length++] = '/';
path[length++] = '\0';
for (;;)
{
result = USB_DeviceMtpReadDir(dir, &fno);
if (result != kStatus_USB_Success)
{
break; /* Break on error or end of dir */
}
#if USB_DEVICE_CONFIG_USE_TASK
USB_DeviceTaskFn(g_mtp.deviceHandle);
#endif
/* check buffer length */
length2 = length + USB_DeviceUnicodeStringLength((const uint16_t *)(&fno.name[0]));
length2 += 2U;
if (length2 > MTP_PATH_MAX_LEN)
{
/* please increase the length of path. */
usb_echo("Please increase the length of path\r\n");
result = kStatus_USB_Error;
break;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
offset = USB_DeviceMemCopyUnicodeString(&path[length], (const uint16_t *)&fno.name[0], 0);
#else
(void)USB_DeviceMemCopyUnicodeString(&path[length], (const uint16_t *)&fno.name[0], 0);
#endif
if ((fno.attrib & USB_DEVICE_MTP_DIR) != 0U)
{
result = USB_DeviceDeleteDir(path); /* recursively delete directory */
if (result != kStatus_USB_Success)
{
break;
}
}
else
{
result = USB_DeviceMtpUnlink((const uint16_t *)path); /* delete file */
if (result != kStatus_USB_Success)
{
break;
}
}
}
path[--length] = '\0';
path[--length] = '\0';
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success != USB_DeviceMtpCloseDir(dir))
{
return kStatus_USB_Error;
}
#else
(void)USB_DeviceMtpCloseDir(dir);
#endif
/* kStatus_USB_InvalidRequest means end of dir, so delete the current directory. */
if (result == kStatus_USB_InvalidRequest)
{
result = USB_DeviceMtpUnlink((const uint16_t *)path); /* delete self */
}
nestedDepth--;
return result;
}
usb_status_t USB_DeviceAppendNameToPath(uint16_t *path, const uint16_t *name)
{
uint32_t length;
uint32_t length2;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
uint32_t offset = 0U;
#endif
if ((path == NULL) && (name == NULL))
{
return kStatus_USB_Error;
}
length = USB_DeviceUnicodeStringLength((const uint16_t *)path);
/* check path validity */
if (length < 2U)
{
return kStatus_USB_Error;
}
/* if there is not '/' at the end of path, append '/'. */
if (path[(length - 2U) >> 1U] != '/')
{
path[length >> 1U] = '/';
length += 2U;
}
/* check buffer length */
length2 = length + USB_DeviceUnicodeStringLength((const uint16_t *)name);
length2 += 2U;
if (length2 > MTP_PATH_MAX_LEN)
{
/* please increase the length of path. */
usb_echo("Please increase the length of path\r\n");
return kStatus_USB_Error;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
offset = USB_DeviceMemCopyUnicodeString(&path[length >> 1U], (const uint16_t *)name, 0);
#else
(void)USB_DeviceMemCopyUnicodeString(&path[length >> 1U], (const uint16_t *)name, 0);
#endif
return kStatus_USB_Success;
}
usb_status_t USB_DeviceCopyFile(uint8_t *destPath, uint8_t *srcPath)
{
usb_device_mtp_file_handle_t fileSrc;
usb_device_mtp_file_handle_t fileDest;
uint32_t readSize;
uint32_t writeSize;
usb_status_t result;
result = USB_DeviceMtpOpen(&fileSrc, (const uint16_t *)srcPath, USB_DEVICE_MTP_READ);
if (result != kStatus_USB_Success)
{
return kStatus_USB_Error;
}
#if USB_DEVICE_CONFIG_USE_TASK
USB_DeviceTaskFn(g_mtp.deviceHandle);
#endif
result = USB_DeviceMtpOpen(&fileDest, (const uint16_t *)destPath,
USB_DEVICE_MTP_CREATE_ALWAYS | USB_DEVICE_MTP_READ | USB_DEVICE_MTP_WRITE);
if (result != kStatus_USB_Success)
{
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
result = USB_DeviceMtpClose(fileSrc);
#else
(void)USB_DeviceMtpClose(fileSrc);
#endif
return kStatus_USB_Error;
}
for (;;)
{
#if USB_DEVICE_CONFIG_USE_TASK
USB_DeviceTaskFn(g_mtp.deviceHandle);
#endif
result = USB_DeviceMtpRead(fileSrc, &g_mtpTransferBuffer[0], USB_DEVICE_MTP_TRANSFER_BUFF_SIZE, &readSize);
if ((result != kStatus_USB_Success) || (readSize == 0U))
{
break;
}
result = USB_DeviceMtpWrite(fileDest, &g_mtpTransferBuffer[0], readSize, &writeSize);
if ((result != kStatus_USB_Success) || (readSize < writeSize))
{
break;
}
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if ((kStatus_USB_Success != USB_DeviceMtpClose(fileSrc)) || (kStatus_USB_Success != USB_DeviceMtpClose(fileDest)))
{
return kStatus_USB_Error;
}
#else
(void)USB_DeviceMtpClose(fileSrc);
(void)USB_DeviceMtpClose(fileDest);
#endif
return kStatus_USB_Success;
}
usb_status_t USB_DeviceCopyDir(uint8_t *destPath, uint8_t *srcPath)
{
static usb_device_mtp_file_info_t fno;
static uint32_t length;
static uint32_t length2;
usb_device_mtp_dir_handle_t dirSrc;
uint32_t lengthSrc;
uint32_t lengthDest;
usb_status_t result;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
uint32_t offset = 0U;
#endif
lengthSrc = USB_DeviceUnicodeStringLength((const uint16_t *)srcPath);
lengthDest = USB_DeviceUnicodeStringLength((const uint16_t *)destPath);
if ((lengthSrc == 0U) || (lengthDest == 0U))
{
return kStatus_USB_Error; /* invalid source or destination path */
}
lengthSrc--;
while ((lengthSrc > 0U) && ((srcPath[lengthSrc] != '\0') || (srcPath[lengthSrc - 1U] != '/')))
{
lengthSrc--;
}
if (lengthSrc == 0U)
{
return kStatus_USB_Error; /* cannot find the directory name. */
}
lengthSrc++;
destPath[lengthDest++] = '/';
destPath[lengthDest++] = '\0';
/* Build destination path */
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
offset = USB_DeviceMemCopyUnicodeString(&destPath[lengthDest], (const uint16_t *)&srcPath[lengthSrc], 0U);
#else
(void)USB_DeviceMemCopyUnicodeString(&destPath[lengthDest], (const uint16_t *)&srcPath[lengthSrc], 0U);
#endif
length2 = USB_DeviceCheckDirDepth((const uint16_t *)&destPath[0]);
if (length2 > USB_DEVICE_MTP_DIR_INSTANCE)
{
usb_echo("The created directory is too deep, please increase the dir instance\r\n");
result = kStatus_USB_Error;
}
else
{
result = USB_DeviceMtpMakeDir((const uint16_t *)destPath); /* Create directory */
}
if (result == kStatus_USB_Success)
{
/* Open directory */
result = USB_DeviceMtpOpenDir(&dirSrc, (const uint16_t *)srcPath);
}
if (result == kStatus_USB_Success)
{
lengthSrc = USB_DeviceUnicodeStringLength((const uint16_t *)srcPath);
srcPath[lengthSrc++] = '/';
srcPath[lengthSrc++] = '\0';
for (;;)
{
result = USB_DeviceMtpReadDir(dirSrc, &fno);
if ((result == kStatus_USB_InvalidRequest) || (result != kStatus_USB_Success))
{
if (result == kStatus_USB_InvalidRequest)
{
result = kStatus_USB_Success; /* return success when reaching end of dir */
}
break; /* Break on error or end of dir */
}
#if USB_DEVICE_CONFIG_USE_TASK
USB_DeviceTaskFn(g_mtp.deviceHandle);
#endif
/* check buffer length */
length2 = lengthSrc + USB_DeviceUnicodeStringLength((const uint16_t *)(&fno.name[0]));
length2 += 2U;
if (length2 > MTP_PATH_MAX_LEN)
{
/* please increase the length of path. */
usb_echo("Please increase the length of path\r\n");
result = kStatus_USB_Error;
break;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
offset = USB_DeviceMemCopyUnicodeString(&srcPath[lengthSrc], (const uint16_t *)&fno.name[0], 0);
#else
(void)USB_DeviceMemCopyUnicodeString(&srcPath[lengthSrc], (const uint16_t *)&fno.name[0], 0);
#endif
if ((fno.attrib & USB_DEVICE_MTP_DIR) != 0U)
{
result = USB_DeviceCopyDir(destPath, srcPath); /* recursively copy directory */
if (result != kStatus_USB_Success)
{
break;
}
}
else
{
length = USB_DeviceUnicodeStringLength((const uint16_t *)destPath);
destPath[length++] = '/';
destPath[length++] = '\0';
/* check buffer length */
length2 = length + USB_DeviceUnicodeStringLength((const uint16_t *)(&fno.name[0]));
length2 += 2U;
if (length2 > MTP_PATH_MAX_LEN)
{
/* please increase the length of path. */
usb_echo("Please increase the length of path\r\n");
result = kStatus_USB_Error;
break;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
offset = USB_DeviceMemCopyUnicodeString(&destPath[length], (const uint16_t *)&fno.name[0], 0);
#else
(void)USB_DeviceMemCopyUnicodeString(&destPath[length], (const uint16_t *)&fno.name[0], 0);
#endif
result = USB_DeviceCopyFile(destPath, srcPath); /* copy file */
if (result != kStatus_USB_Success)
{
break;
}
destPath[--length] = '\0';
destPath[--length] = '\0';
}
}
srcPath[--lengthSrc] = '\0';
srcPath[--lengthSrc] = '\0';
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
result = USB_DeviceMtpCloseDir(dirSrc);
#else
(void)USB_DeviceMtpCloseDir(dirSrc);
#endif
}
destPath[--lengthDest] = '\0';
destPath[--lengthDest] = '\0';
return result;
}
static uint32_t USB_DeviceAssignDevPropVal(
uint16_t devPropCode, uint16_t dataType, void *buffer, void *val, uint32_t offset)
{
switch (devPropCode)
{
case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
offset = USB_DeviceMemCopyUnicodeString(buffer, (const uint16_t *)g_mtp.devFriendlyName, offset);
break;
default:
/* TODO: identify more device property code. */
offset = USB_DeviceParseDataType(dataType, buffer, val, offset);
break;
}
return offset;
}
static uint32_t USB_DeviceAssignObjPropVal(
uint16_t objPropCode, uint16_t dataType, void *buffer, usb_mtp_obj_handle_t *objHandleStruct, uint32_t offset)
{
uint32_t temp;
uint32_t uid[4];
char dateTimeBuffer[MTP_DATE_TIME_LEN];
switch (objPropCode)
{
case MTP_OBJECT_PROPERTY_STORAGE_ID:
offset = USB_DeviceParseDataType(dataType, buffer, &objHandleStruct->storageID, offset);
break;
case MTP_OBJECT_PROPERTY_OBJECT_FORMAT:
temp = USB_DeviceIdentifyFileType(objHandleStruct);
offset = USB_DeviceParseDataType(dataType, buffer, &temp, offset);
break;
case MTP_OBJECT_PROPERTY_PROTECTION_STATUS:
temp = 0;
offset = USB_DeviceParseDataType(dataType, buffer, &temp, offset);
break;
case MTP_OBJECT_PROPERTY_OBJECT_SIZE:
offset = USB_DeviceParseDataType(dataType, buffer, &objHandleStruct->size, offset);
break;
case MTP_OBJECT_PROPERTY_OBJECT_FILE_NAME:
offset = USB_DeviceMemCopyUnicodeString(buffer, &objHandleStruct->name[0], offset);
break;
case MTP_OBJECT_PROPERTY_DATE_MODIFIED:
snprintf(&dateTimeBuffer[0], sizeof(dateTimeBuffer), "%.4d%.2d%.2dT%.2d%.2d%.2d",
objHandleStruct->dateUnion.dateBitField.year, objHandleStruct->dateUnion.dateBitField.month,
objHandleStruct->dateUnion.dateBitField.day, objHandleStruct->timeUnion.timeBitField.hour,
objHandleStruct->timeUnion.timeBitField.minute, objHandleStruct->timeUnion.timeBitField.second);
offset = USB_DeviceParseDataType(dataType, buffer, &dateTimeBuffer[0], offset);
break;
case MTP_OBJECT_PROPERTY_PERSISTENT_UID:
uid[0] = objHandleStruct->handleID;
uid[1] = objHandleStruct->storageID;
uid[2] = 0;
uid[3] = 0;
offset = USB_DeviceParseDataType(dataType, buffer, &uid[0], offset);
break;
case MTP_OBJECT_PROPERTY_PARENT_OBJECT:
offset = USB_DeviceParseDataType(dataType, buffer, &objHandleStruct->idUnion.parentID, offset);
break;
case MTP_OBJECT_PROPERTY_NAME:
offset = USB_DeviceMemCopyUnicodeString(buffer, &objHandleStruct->name[0], offset);
break;
case MTP_OBJECT_PROPERTY_DISPLAY_NAME:
offset = USB_DeviceMemCopyUnicodeString(buffer, &objHandleStruct->name[0], offset);
break;
case MTP_OBJECT_PROPERTY_DATE_ADDED:
snprintf(&dateTimeBuffer[0], sizeof(dateTimeBuffer), "%.4d%.2d%.2dT%.2d%.2d%.2d",
objHandleStruct->dateUnion.dateBitField.year, objHandleStruct->dateUnion.dateBitField.month,
objHandleStruct->dateUnion.dateBitField.day, objHandleStruct->timeUnion.timeBitField.hour,
objHandleStruct->timeUnion.timeBitField.minute, objHandleStruct->timeUnion.timeBitField.second);
offset = USB_DeviceParseDataType(dataType, buffer, &dateTimeBuffer[0], offset);
break;
default:
/* no action */
break;
}
return offset;
}
void USB_DeviceCmdOpenSession(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
usb_status_t result;
uint8_t i;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
g_mtp.nextHandleID = 0x01U;
g_mtp.validObjInfo = 0x00U;
for (i = 0; i < g_mtp.storageList->storageCount; i++)
{
g_mtp.storageList->storageInfo[i].flag &= ~MTP_OBJECT_ALREADY_GET;
}
result = USB_DeviceMtpObjHandleInit();
if (result != kStatus_USB_Success)
{
dataInfo->code = MTP_RESPONSE_DEVICE_BUSY;
}
else
{
dataInfo->code = MTP_RESPONSE_OK;
}
}
}
void USB_DeviceCmdCloseSession(void *param)
{
uint8_t i;
g_mtp.nextHandleID = 0x01U;
g_mtp.validObjInfo = 0x00U;
for (i = 0; i < g_mtp.storageList->storageCount; i++)
{
g_mtp.storageList->storageInfo[i].flag &= ~MTP_OBJECT_ALREADY_GET;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success != USB_DeviceMtpObjHandleDeinit())
{
#if (defined(DEVICE_ECHO) && (DEVICE_ECHO > 0U))
usb_echo("mtp handle de-init error\r\n");
#endif
}
#else
(void)USB_DeviceMtpObjHandleDeinit();
#endif
if (param != NULL)
{
((usb_device_mtp_cmd_data_struct_t *)param)->code = MTP_RESPONSE_OK;
}
}
void USB_DeviceCmdGetDeviceInfo(void *param, usb_device_mtp_device_info_t *deviceInfo)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
/* Build DeviceInfo dataset here. For more information about DeviceInfo dataset,
please refer to chapter 5.1.1 in the MTP spec Rev1.1. */
offset = USB_DeviceMemCopyWord(readBuf, MTP_STANDARD_VERSION, offset); /* standard version */
offset = USB_DeviceMemCopyDword(readBuf, MTP_VENDOR_EXTENSION_ID, offset); /* MTP vendor extension ID */
offset = USB_DeviceMemCopyWord(readBuf, MTP_VERSION, offset); /* MTP version */
offset = USB_DeviceMemCopyString(readBuf, deviceInfo->mtpExtendsions, offset); /* MTP extensions */
offset = USB_DeviceMemCopyWord(readBuf, deviceInfo->functionalMode, offset); /* functional Mode */
offset = USB_DeviceMemCopyArray(readBuf, deviceInfo->opSupported, deviceInfo->opSupportedLength, 2U, offset);
offset = USB_DeviceMemCopyArray(readBuf, deviceInfo->eventSupported, deviceInfo->eventSupportedLength, 2U,
offset); /* event supported */
offset = USB_DeviceMemCopyArray(readBuf, deviceInfo->devPropSupported, deviceInfo->devPropSupportedLength, 2U,
offset); /* device properties supported */
offset = USB_DeviceMemCopyArray(readBuf, deviceInfo->captureFormat, deviceInfo->captureFormatLength, 2U,
offset); /* capture formats */
offset = USB_DeviceMemCopyArray(readBuf, deviceInfo->playbackFormat, deviceInfo->playbackFormatLength, 2U,
offset); /* playback formats */
offset = USB_DeviceMemCopyString(readBuf, deviceInfo->manufacturer, offset); /* manufacturer */
offset = USB_DeviceMemCopyString(readBuf, deviceInfo->model, offset); /* model */
offset = USB_DeviceMemCopyString(readBuf, deviceInfo->deviceVersion, offset); /* device version */
offset = USB_DeviceMemCopyString(readBuf, deviceInfo->serialNumber, offset); /* serial number */
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
void USB_DeviceCmdGetDevicePropDesc(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint16_t devPropCode = dataInfo->param[0];
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
uint32_t i;
uint32_t j;
usb_device_mtp_dev_prop_desc_t *devPropDesc;
uint32_t count;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
devPropDesc = g_mtp.devPropDescList->devPropDesc;
count = g_mtp.devPropDescList->devPropDescCount;
for (i = 0; i < count; i++)
{
if (devPropDesc[i].devPropCode == devPropCode)
{
/* Build device property describing dataset here. For more information about device property describing
dataset, please refer to chapter 5.1.2 in the MTP spec Rev1.1. */
offset = USB_DeviceMemCopyWord(readBuf, devPropDesc[i].devPropCode, offset);
offset = USB_DeviceMemCopyWord(readBuf, devPropDesc[i].dataType, offset);
offset = USB_DeviceMemCopyByte(readBuf, devPropDesc[i].getSet, offset);
offset = USB_DeviceParseDataType(devPropDesc[i].dataType, readBuf, &devPropDesc[i].defaultVal, offset);
offset = USB_DeviceAssignDevPropVal(devPropDesc[i].devPropCode, devPropDesc[i].dataType, readBuf,
&devPropDesc[i].currentVal, offset);
offset = USB_DeviceMemCopyByte(readBuf, devPropDesc[i].formFlag, offset);
switch (devPropDesc[i].formFlag)
{
case MTP_FORM_FLAG_RANGE:
{
offset = USB_DeviceParseDataType(devPropDesc[i].dataType, readBuf,
&devPropDesc[i].form.rangeForm.minVal, offset);
offset = USB_DeviceParseDataType(devPropDesc[i].dataType, readBuf,
&devPropDesc[i].form.rangeForm.maxVal, offset);
offset = USB_DeviceParseDataType(devPropDesc[i].dataType, readBuf,
&devPropDesc[i].form.rangeForm.stepSize, offset);
break;
}
case MTP_FORM_FLAG_ENUMERATION:
{
offset = USB_DeviceMemCopyWord(readBuf, devPropDesc[i].form.enumForm.num, offset);
for (j = 0; j < devPropDesc[i].form.enumForm.num; j++)
{
offset = USB_DeviceParseDataType(devPropDesc[i].dataType, readBuf,
&devPropDesc[i].form.enumForm.val[j], offset);
}
break;
}
default:
/* no action */
break;
}
break; /* exit from loop. */
}
}
if (i == count)
{
/* not support device property */
dataInfo->code = MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
}
else
{
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
}
void USB_DeviceCmdGetObjPropsSupported(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint16_t objPropCode = dataInfo->param[0];
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
uint32_t i;
uint32_t j;
usb_device_mtp_obj_prop_t *objPropDescList;
uint32_t count;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
objPropDescList = g_mtp.objPropList->objProp;
count = g_mtp.objPropList->objPropCount;
for (i = 0; i < count; i++)
{
if (objPropDescList[i].objFormat == objPropCode)
{
offset = USB_DeviceMemCopyDword(readBuf, (uint32_t)objPropDescList[i].objPropDescCount, offset);
for (j = 0; j < objPropDescList[i].objPropDescCount; j++)
{
offset = USB_DeviceMemCopyWord(readBuf, objPropDescList[i].objPropDesc[j].objPropCode, offset);
}
break;
}
}
if (i == count)
{
/* not support device property */
dataInfo->code = MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
}
else
{
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
}
void USB_DeviceCmdGetStorageIDs(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
uint8_t i;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
offset = USB_DeviceMemCopyDword(readBuf, g_mtp.storageList->storageCount, offset);
for (i = 0; i < g_mtp.storageList->storageCount; i++)
{
offset = USB_DeviceMemCopyDword(readBuf, g_mtp.storageList->storageInfo[i].storageID, offset);
}
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
void USB_DeviceCmdGetStorageInfo(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t storageID = dataInfo->param[0];
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
uint8_t i;
const uint8_t *rootPath;
uint64_t freeBytes;
uint64_t totalBytes;
usb_device_mtp_storage_info_t *storageInfo;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
rootPath = NULL;
storageInfo = g_mtp.storageList->storageInfo;
for (i = 0; i < g_mtp.storageList->storageCount; i++)
{
if (storageInfo[i].storageID == storageID)
{
rootPath = storageInfo[i].rootPath;
break;
}
}
if (rootPath == NULL)
{
/* invalid storage ID */
dataInfo->code = MTP_RESPONSE_INVALID_STORAGE_ID;
}
else
{
/* Build StorageInfo dataset here. For more information about StorageInfo dataset,
please refer to chapter 5.2.2 in the MTP spec Rev1.1. */
USB_DeviceMtpGetDiskTotalBytes((const uint16_t *)rootPath, &totalBytes);
USB_DeviceMtpGetDiskFreeBytes((const uint16_t *)rootPath, &freeBytes);
offset = USB_DeviceMemCopyWord(readBuf, storageInfo[i].storageType, offset);
offset = USB_DeviceMemCopyWord(readBuf, storageInfo[i].fileSystemType, offset);
offset = USB_DeviceMemCopyWord(readBuf, storageInfo[i].accessCapability, offset);
offset = USB_DeviceMemCopyQword(readBuf, totalBytes, offset);
offset = USB_DeviceMemCopyQword(readBuf, freeBytes, offset);
offset = USB_DeviceMemCopyDword(readBuf, USB_DEVICE_MTP_MAX_UINT32_VAL, offset);
offset = USB_DeviceMemCopyString(readBuf, storageInfo[i].storageDesc, offset);
offset = USB_DeviceMemCopyString(readBuf, storageInfo[i].volumeID, offset);
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
}
void USB_DeviceCmdGetObjHandles(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset;
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
uint32_t storageID = dataInfo->param[0];
uint16_t objFormatCode = dataInfo->param[1];
uint32_t objHandle = dataInfo->param[2];
usb_status_t result;
usb_device_mtp_dir_handle_t dir;
usb_device_mtp_file_info_t fno;
usb_mtp_obj_handle_t objHandleStruct;
uint32_t objHandleCount;
uint32_t j;
uint8_t i;
uint8_t storageCount = g_mtp.storageList->storageCount;
usb_device_mtp_storage_info_t *storageInfo = g_mtp.storageList->storageInfo;
/* Check storage ID */
if (storageID != USB_DEVICE_MTP_MAX_UINT32_VAL)
{
for (i = 0; i < storageCount; i++)
{
if (storageInfo[i].storageID == storageID)
{
break;
}
}
if (i == storageCount)
{
/* invalid storage ID */
dataInfo->code = MTP_RESPONSE_INVALID_STORAGE_ID;
return;
}
storageInfo = &storageInfo[i];
storageCount = 1;
}
else
{
storageID = storageInfo[0].storageID;
}
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
/* Check format code */
if (objFormatCode != 0U)
{
/* unspported format code */
dataInfo->code = MTP_RESPONSE_SPECIFICATION_BY_FORMAT_UNSUPPORTED;
return;
}
objHandleCount = 0U;
offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH + 4U;
for (i = 0; i < storageCount; i++)
{
if (storageCount > 1)
{
storageID = storageInfo[i].storageID;
}
if (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL)
{
/* root path */
objHandle = 0;
if ((storageInfo[i].flag & MTP_OBJECT_ALREADY_GET) == 0U)
{
USB_DeviceGetRootPath(&g_mtp, storageID, g_mtp.path);
}
}
else
{
/* build path here. */
if ((objHandle >= g_mtp.nextHandleID) || (objHandle == 0U) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success) ||
(USB_DeviceBuildPath(&g_mtp, storageID, objHandle, g_mtp.path) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandleStruct.flag & MTP_OBJECT_DIR) == 0U)
{
/* invalid parent object */
dataInfo->code = MTP_RESPONSE_INVALID_PARENT_OBJECT;
return;
}
}
if (((objHandle != 0U) && ((objHandleStruct.flag & MTP_OBJECT_ALREADY_GET) != 0U)) ||
((objHandle == 0U) && ((storageInfo[i].flag & MTP_OBJECT_ALREADY_GET) != 0U)))
{
/* traverse object lists to find its child */
for (j = 1U; j < g_mtp.nextHandleID; j++)
{
result = USB_DeviceMtpObjHandleRead(j, &objHandleStruct);
if (result != kStatus_USB_Success)
{
break; /* reach the end */
}
if ((objHandleStruct.idUnion.parentID == objHandle) &&
((objHandleStruct.flag & MTP_OBJECT_DELETE) == 0U))
{
objHandleCount++;
if (offset < USB_DEVICE_MTP_TRANSFER_BUFF_SIZE) /* Buffer is full, need to chunk? */
{
offset = USB_DeviceMemCopyDword(readBuf, objHandleStruct.handleID, offset);
}
}
}
}
else
{
/* traverse directory to find its child */
result = USB_DeviceMtpOpenDir(&dir, (const uint16_t *)&g_mtp.path[0]);
for (;;)
{
result = USB_DeviceMtpReadDir(dir, &fno);
if (result != kStatus_USB_Success)
{
break; /* Break on error or end of dir */
}
if (offset < USB_DEVICE_MTP_TRANSFER_BUFF_SIZE) /* Buffer is full, need to chunk? */
{
objHandleStruct.handleID = g_mtp.nextHandleID;
g_mtp.nextHandleID++;
objHandleStruct.idUnion.parentID = objHandle;
objHandleStruct.storageID = storageID;
objHandleStruct.size = fno.size;
objHandleStruct.dateUnion.date = fno.dateUnion.date;
objHandleStruct.timeUnion.time = fno.timeUnion.time;
objHandleStruct.flag = 0U;
if ((fno.attrib & USB_DEVICE_MTP_DIR) != 0U)
{
objHandleStruct.flag |= MTP_OBJECT_DIR;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
/* now j indicates the offset */
j = USB_DeviceMemCopyUnicodeString(&objHandleStruct.name[0], (const uint16_t *)&fno.name[0],
0U);
#else
(void)USB_DeviceMemCopyUnicodeString(&objHandleStruct.name[0], (const uint16_t *)&fno.name[0],
0U);
#endif
result = USB_DeviceMtpObjHandleWrite(objHandleStruct.handleID, &objHandleStruct);
offset = USB_DeviceMemCopyDword(readBuf, objHandleStruct.handleID, offset);
}
objHandleCount++;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
result = USB_DeviceMtpCloseDir(dir);
#else
(void)USB_DeviceMtpCloseDir(dir);
#endif
}
}
/* number of object Handle */
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
j = USB_DeviceMemCopyDword(readBuf, objHandleCount, USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH);
#else
(void)USB_DeviceMemCopyDword(readBuf, objHandleCount, USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH);
#endif
g_mtp.transferTotalSize = objHandleCount * 4U + USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH + 4U;
dataInfo->totalSize = g_mtp.transferTotalSize;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
else if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_DATA)
{
/* Buffer is full, need to chunk. */
if (dataInfo->curPos < g_mtp.transferTotalSize)
{
offset = 0U;
/* the number of object handle has been sent. */
objHandleCount = (dataInfo->curPos - USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH - 4U) / 4U;
for (i = 0; i < storageCount; i++)
{
if (storageCount > 1)
{
storageID = storageInfo[i].storageID;
}
if (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL)
{
/* root path */
objHandle = 0;
if ((storageInfo[i].flag & MTP_OBJECT_ALREADY_GET) == 0U)
{
USB_DeviceGetRootPath(&g_mtp, storageID, g_mtp.path);
}
}
else
{
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if ((kStatus_USB_Success != USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct)) ||
USB_DeviceBuildPath(&g_mtp, storageID, objHandle, g_mtp.path))
{
return;
}
#else
(void)USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct);
(void)USB_DeviceBuildPath(&g_mtp, storageID, objHandle, g_mtp.path);
#endif
}
if (((objHandle != 0U) && ((objHandleStruct.flag & MTP_OBJECT_ALREADY_GET) != 0U)) ||
((objHandle == 0U) && ((storageInfo[i].flag & MTP_OBJECT_ALREADY_GET) != 0U)))
{
/* traverse object lists to find its child. */
for (j = 1U; j < g_mtp.nextHandleID; j++)
{
result = USB_DeviceMtpObjHandleRead(j, &objHandleStruct);
if (result != kStatus_USB_Success)
{
break; /* reach the end */
}
if ((objHandleStruct.idUnion.parentID == objHandle) &&
((objHandleStruct.flag & MTP_OBJECT_DELETE) == 0U))
{
if (objHandleCount == 0U)
{
if (offset < USB_DEVICE_MTP_TRANSFER_BUFF_SIZE) /* Buffer is full, need to chunk? */
{
offset = USB_DeviceMemCopyDword(readBuf, objHandleStruct.handleID, offset);
}
}
else
{
objHandleCount--;
}
}
}
}
else
{
/* traverse directory to find its child */
result = USB_DeviceMtpOpenDir(&dir, (const uint16_t *)&g_mtp.path[0]);
for (;;)
{
result = USB_DeviceMtpReadDir(dir, &fno);
if (result != kStatus_USB_Success)
{
break; /* Break on error or end of dir */
}
if (objHandleCount == 0U)
{
if (offset < USB_DEVICE_MTP_TRANSFER_BUFF_SIZE) /* Buffer is full, need to chunk? */
{
objHandleStruct.handleID = g_mtp.nextHandleID;
g_mtp.nextHandleID++;
objHandleStruct.idUnion.parentID = objHandle;
objHandleStruct.storageID = storageID;
objHandleStruct.size = fno.size;
objHandleStruct.dateUnion.date = fno.dateUnion.date;
objHandleStruct.timeUnion.time = fno.timeUnion.time;
objHandleStruct.flag = 0U;
if ((fno.attrib & USB_DEVICE_MTP_DIR) != 0U)
{
objHandleStruct.flag |= MTP_OBJECT_DIR;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
/* now j indicates the offset */
j = USB_DeviceMemCopyUnicodeString(&objHandleStruct.name[0],
(const uint16_t *)&fno.name[0], 0U);
#else
(void)USB_DeviceMemCopyUnicodeString(&objHandleStruct.name[0],
(const uint16_t *)&fno.name[0], 0U);
#endif
result = USB_DeviceMtpObjHandleWrite(objHandleStruct.handleID, &objHandleStruct);
offset = USB_DeviceMemCopyDword(readBuf, objHandleStruct.handleID, offset);
}
}
else
{
objHandleCount--;
}
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
result = USB_DeviceMtpCloseDir(dir);
#else
(void)USB_DeviceMtpCloseDir(dir);
#endif
}
}
dataInfo->totalSize = g_mtp.transferTotalSize;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
else if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_RESPONSE)
{
/* record the directory has been accessed. */
for (i = 0; i < storageCount; i++)
{
if (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL)
{
/* root path */
storageInfo[i].flag |= MTP_OBJECT_ALREADY_GET;
}
else
{
result = USB_DeviceMtpObjHandleRead(objHandle, &objHandleStruct);
objHandleStruct.flag |= MTP_OBJECT_ALREADY_GET;
result = USB_DeviceMtpObjHandleWrite(objHandle, &objHandleStruct);
}
}
}
else
{
/* no action */
}
}
void USB_DeviceCmdGetObjPropDesc(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
uint16_t objPropCode = dataInfo->param[0];
uint16_t objFormatCode = dataInfo->param[1];
uint32_t i;
uint32_t j;
uint16_t n;
usb_device_mtp_obj_prop_desc_t *propDesc;
usb_device_mtp_obj_prop_t *prop;
uint32_t propCount;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
prop = g_mtp.objPropList->objProp;
propCount = g_mtp.objPropList->objPropCount;
for (i = 0U; i < propCount; i++)
{
if (prop[i].objFormat == objFormatCode)
{
break;
}
}
if (i == propCount)
{
/* invalid object format code */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_FORMAT_CODE;
return;
}
for (j = 0U; j < prop[i].objPropDescCount; j++)
{
if (prop[i].objPropDesc[j].objPropCode == objPropCode)
{
break;
}
}
if (j == prop[i].objPropDescCount)
{
/* invalid object property code */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
return;
}
propDesc = &prop[i].objPropDesc[j];
/* Build object property describing dataset here. For more information about object property describing dataset,
please refer to chapter 5.3.2.3 in the MTP spec Rev1.1. */
offset = USB_DeviceMemCopyWord(readBuf, propDesc->objPropCode, offset);
offset = USB_DeviceMemCopyWord(readBuf, propDesc->dataType, offset);
offset = USB_DeviceMemCopyByte(readBuf, propDesc->getSet, offset);
offset = USB_DeviceParseDataType(propDesc->dataType, readBuf, &propDesc->defaultVal, offset);
offset = USB_DeviceMemCopyDword(readBuf, propDesc->groupCode, offset); /* group code */
offset = USB_DeviceMemCopyByte(readBuf, propDesc->formFlag, offset); /* form flag */
switch (propDesc->formFlag)
{
case MTP_FORM_FLAG_RANGE:
{
offset = USB_DeviceParseDataType(propDesc->dataType, readBuf, &propDesc->form.rangeForm.minVal, offset);
offset = USB_DeviceParseDataType(propDesc->dataType, readBuf, &propDesc->form.rangeForm.maxVal, offset);
offset =
USB_DeviceParseDataType(propDesc->dataType, readBuf, &propDesc->form.rangeForm.stepSize, offset);
break;
}
case MTP_FORM_FLAG_ENUMERATION:
{
offset = USB_DeviceMemCopyWord(readBuf, propDesc->form.enumForm.num, offset);
for (n = 0; n < propDesc->form.enumForm.num; n++)
{
offset =
USB_DeviceParseDataType(propDesc->dataType, readBuf, &propDesc->form.enumForm.val[n], offset);
}
break;
}
case MTP_FORM_FLAG_FIXED_LENGTH_ARRAY:
case MTP_FORM_FLAG_BYTE_ARRAY:
case MTP_FORM_FLAG_LONG_STRING:
offset = USB_DeviceMemCopyDword(readBuf, propDesc->form.fixedLengthArray, offset);
break;
case MTP_FORM_FLAG_REGULAR_EXPRESSION:
offset = USB_DeviceMemCopyString(readBuf, propDesc->form.regularExpression, offset);
break;
case MTP_FORM_FLAG_DATA_TIME:
default:
/* no action */
break;
}
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
void USB_DeviceCmdGetObjPropList(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
uint32_t objHandle = dataInfo->param[0];
uint32_t objFormatCode = dataInfo->param[1];
uint32_t objPropCode = dataInfo->param[2];
uint32_t objPropGroupCode = dataInfo->param[3];
uint32_t depth = dataInfo->param[4];
uint32_t i;
uint32_t j;
usb_mtp_obj_handle_t objHandleStruct;
uint16_t dataType;
usb_device_mtp_obj_prop_t *objProp;
uint32_t objPropCount;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
if (objFormatCode != 0U)
{
/* unsupported format */
dataInfo->code = MTP_RESPONSE_SPECIFICATION_BY_FORMAT_UNSUPPORTED;
return;
}
if (objPropCode == 0U)
{
/* unsupported group code */
dataInfo->code = MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED;
return;
}
if (depth != 0U)
{
/* unsupported depth */
dataInfo->code = MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED;
return;
}
if ((objHandle == 0U) || (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL))
{
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandle >= g_mtp.nextHandleID) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
/* identify file type */
objFormatCode = USB_DeviceIdentifyFileType(&objHandleStruct);
objProp = g_mtp.objPropList->objProp;
objPropCount = g_mtp.objPropList->objPropCount;
if (objPropCode != USB_DEVICE_MTP_MAX_UINT32_VAL)
{
j = 0U;
for (i = 0U; i < objPropCount; i++)
{
if (objProp[i].objFormat == objFormatCode)
{
for (; j < objProp[i].objPropDescCount; j++)
{
if (objProp[i].objPropDesc[j].objPropCode == (uint16_t)objPropCode)
{
break;
}
}
break;
}
}
if ((i == objPropCount) || (j == objProp[i].objPropDescCount))
{
/* unsupported property code */
dataInfo->code = MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
return;
}
dataType = objProp[i].objPropDesc[j].dataType;
/* Build object property list dataset here. For more information about object property list dataset,
please refer to Appendix E.2.1.1 in the MTP spec Rev1.1. */
offset = USB_DeviceMemCopyDword(readBuf, 1U, offset); /* number of elements */
offset = USB_DeviceMemCopyDword(readBuf, objHandle, offset); /* object handle */
offset = USB_DeviceMemCopyWord(readBuf, objPropCode, offset); /* object property */
offset = USB_DeviceMemCopyWord(readBuf, dataType, offset); /* data type */
offset =
USB_DeviceAssignObjPropVal(objPropCode, dataType, readBuf, &objHandleStruct, offset); /* object value */
}
else
{
for (i = 0U; i < objPropCount; i++)
{
if (objProp[i].objFormat == objFormatCode)
{
objProp = &objProp[i];
break;
}
}
offset = USB_DeviceMemCopyDword(readBuf, objProp->objPropDescCount, offset); /* number of elements */
for (j = 0; j < objProp->objPropDescCount; j++)
{
dataType = objProp->objPropDesc[j].dataType;
objPropCode = objProp->objPropDesc[j].objPropCode;
offset = USB_DeviceMemCopyDword(readBuf, objHandle, offset); /* object handle */
offset = USB_DeviceMemCopyWord(readBuf, objPropCode, offset); /* object property */
offset = USB_DeviceMemCopyWord(readBuf, dataType, offset); /* data type */
offset = USB_DeviceAssignObjPropVal(objPropCode, dataType, readBuf, &objHandleStruct,
offset); /* object value */
}
}
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
(void)objPropGroupCode; /* avoid compiler warning */
}
}
void USB_DeviceCmdGetObjInfo(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint32_t objHandle = dataInfo->param[0];
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
usb_mtp_obj_handle_t objHandleStruct;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
if ((objHandle == 0U) || (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL))
{
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandle >= g_mtp.nextHandleID) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
/* Build ObjectInfo dataset here. For more information about ObjectInfo dataset,
please refer to chapter 5.3.1 in the MTP spec Rev1.1. */
offset = USB_DeviceMemCopyDword(readBuf, objHandleStruct.storageID, offset); /* storage ID */
offset =
USB_DeviceMemCopyWord(readBuf, USB_DeviceIdentifyFileType(&objHandleStruct), offset); /* object format */
offset = USB_DeviceMemCopyWord(readBuf, 0, offset); /* protection status */
offset = USB_DeviceMemCopyDword(readBuf, objHandleStruct.size, offset); /* object compressed size */
offset = USB_DeviceMemCopyWord(readBuf, 0, offset); /* thumb format */
offset = USB_DeviceMemCopyDword(readBuf, 0, offset); /* thumb compressed size */
offset = USB_DeviceMemCopyDword(readBuf, 0, offset); /* thumb pix width */
offset = USB_DeviceMemCopyDword(readBuf, 0, offset); /* thumb pix height */
offset = USB_DeviceMemCopyDword(readBuf, 0, offset); /* image pix width */
offset = USB_DeviceMemCopyDword(readBuf, 0, offset); /* image pix height */
offset = USB_DeviceMemCopyDword(readBuf, 0, offset); /* image bit depth */
offset = USB_DeviceMemCopyDword(readBuf, objHandleStruct.idUnion.parentID, offset); /* parent object */
offset = USB_DeviceMemCopyWord(readBuf, 0, offset); /* association type */
offset = USB_DeviceMemCopyDword(readBuf, 0, offset); /* association description */
offset = USB_DeviceMemCopyDword(readBuf, 0, offset); /* sequence number */
offset = USB_DeviceMemCopyUnicodeString(readBuf, objHandleStruct.name, offset); /* file name */
offset = USB_DeviceAssignObjPropVal(MTP_OBJECT_PROPERTY_DATE_ADDED, MTP_TYPE_STR, readBuf, &objHandleStruct,
offset); /* date created */
offset = USB_DeviceAssignObjPropVal(MTP_OBJECT_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, readBuf, &objHandleStruct,
offset); /* date modified */
offset = USB_DeviceMemCopyUnicodeString(readBuf, NULL, offset); /* keywords */
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
void USB_DeviceCmdGetObj(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset;
uint32_t objHandle = dataInfo->param[0];
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
usb_mtp_obj_handle_t objHandleStruct;
uint32_t sizeRead;
usb_status_t result;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
if ((objHandle == 0U) || (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL))
{
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandle >= g_mtp.nextHandleID) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success) ||
((objHandleStruct.flag & MTP_OBJECT_DIR) != 0U) ||
(USB_DeviceBuildPath(&g_mtp, objHandleStruct.storageID, objHandle, g_mtp.path) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
offset =
(objHandleStruct.size > (USB_DEVICE_MTP_TRANSFER_BUFF_SIZE - USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH)) ?
(USB_DEVICE_MTP_TRANSFER_BUFF_SIZE - USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH) :
objHandleStruct.size;
result = USB_DeviceMtpOpen(&g_mtp.file, (const uint16_t *)&g_mtp.path[0], USB_DEVICE_MTP_READ);
result = USB_DeviceMtpRead(g_mtp.file, readBuf + USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH, offset, &sizeRead);
if ((result != kStatus_USB_Success) || (sizeRead < offset))
{
dataInfo->code = MTP_RESPONSE_ACCESS_DENIED;
}
else
{
g_mtp.transferTotalSize = objHandleStruct.size + USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
dataInfo->totalSize = g_mtp.transferTotalSize;
dataInfo->curSize = offset + USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
dataInfo->buffer = readBuf;
}
}
else if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_DATA)
{
offset = ((g_mtp.transferTotalSize - dataInfo->curPos) > USB_DEVICE_MTP_TRANSFER_BUFF_SIZE) ?
USB_DEVICE_MTP_TRANSFER_BUFF_SIZE :
(g_mtp.transferTotalSize - dataInfo->curPos);
result = USB_DeviceMtpLseek(g_mtp.file, dataInfo->curPos - USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH);
result = USB_DeviceMtpRead(g_mtp.file, readBuf, offset, &sizeRead);
if ((result != kStatus_USB_Success) || (sizeRead < offset))
{
dataInfo->code = MTP_RESPONSE_ACCESS_DENIED;
}
else
{
dataInfo->totalSize = g_mtp.transferTotalSize;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
else if ((dataInfo->curPhase == USB_DEVICE_MTP_PHASE_RESPONSE) ||
(dataInfo->curPhase == USB_DEVICE_MTP_PHASE_CANCELLATION))
{
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
result = USB_DeviceMtpClose(g_mtp.file);
#else
(void)USB_DeviceMtpClose(g_mtp.file);
#endif
}
else
{
/* no action */
}
}
void USB_DeviceCmdSendObjInfo(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t storageID = dataInfo->param[0];
uint32_t objHandle = dataInfo->param[1];
uint8_t *writeBuf;
usb_mtp_obj_handle_t objHandleStruct;
uint32_t objFormat;
uint32_t objSize;
uint64_t freeBytes;
usb_device_mtp_file_handle_t file;
usb_device_mtp_file_info_t fno;
uint32_t length;
uint32_t length2;
uint16_t stringLength;
usb_status_t result;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
uint32_t offset = 0U;
#endif
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
if (USB_DeviceGetRootPath(&g_mtp, storageID, g_mtp.path) == 0U)
{
/* invalid storage ID */
dataInfo->code = MTP_RESPONSE_INVALID_STORAGE_ID;
return;
}
if (objHandle != USB_DEVICE_MTP_MAX_UINT32_VAL)
{
if ((objHandle >= g_mtp.nextHandleID) || (objHandle == 0U) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandleStruct.flag & MTP_OBJECT_DIR) == 0U)
{
/* invalid parent object */
dataInfo->code = MTP_RESPONSE_INVALID_PARENT_OBJECT;
return;
}
/* build path here. */
if (USB_DeviceBuildPath(&g_mtp, objHandleStruct.storageID, objHandle, g_mtp.path) != kStatus_USB_Success)
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
}
else
{
/* root path */
}
dataInfo->curSize = USB_DEVICE_MTP_TRANSFER_BUFF_SIZE;
dataInfo->buffer = (uint8_t *)&g_mtpTransferBuffer[0];
}
else if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_RESPONSE)
{
writeBuf = (uint8_t *)&g_mtpTransferBuffer[0] + USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
objFormat = *(uint16_t *)(writeBuf + 4U); /* object format */
objSize = *(uint32_t *)(writeBuf + 8U); /* object compressed size */
stringLength = *(uint8_t *)(writeBuf + 52U); /* the length of file name */
if (stringLength == 0U)
{
dataInfo->code = MTP_RESPONSE_INVALID_DATASET;
return;
}
if (USB_DeviceUnicodeStringLength((const uint16_t *)(writeBuf + 53U)) != ((stringLength - 1U) << 1U))
{
dataInfo->code = MTP_RESPONSE_INVALID_DATASET;
return;
}
USB_DeviceMtpGetDiskFreeBytes((const uint16_t *)&g_mtp.path[0], &freeBytes);
if (freeBytes < objSize)
{
dataInfo->code = MTP_RESPONSE_OBJECT_TOO_LARGE;
return;
}
if (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL)
{
objHandle = 0;
}
/* build path here(append file name to the path) */
if (USB_DeviceAppendNameToPath((uint16_t *)g_mtp.path, (const uint16_t *)(writeBuf + 53U)) !=
kStatus_USB_Success)
{
dataInfo->code = MTP_RESPONSE_ACCESS_DENIED;
return;
}
if (objFormat == MTP_FORMAT_ASSOCIATION)
{
length2 = USB_DeviceCheckDirDepth((const uint16_t *)&g_mtp.path[0]);
if (length2 > USB_DEVICE_MTP_DIR_INSTANCE)
{
usb_echo("The created directory is too deep, please increase the dir instance\r\n");
result = kStatus_USB_Error;
}
else
{
result = USB_DeviceMtpMakeDir((const uint16_t *)&g_mtp.path[0]); /* Create directory */
}
if (result != kStatus_USB_Success)
{
dataInfo->code = MTP_RESPONSE_ACCESS_DENIED;
return;
}
}
else
{
result = USB_DeviceMtpOpen(
&file, (const uint16_t *)&g_mtp.path[0],
USB_DEVICE_MTP_READ | USB_DEVICE_MTP_WRITE | USB_DEVICE_MTP_CREATE_ALWAYS); /* Create file */
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success != USB_DeviceMtpClose(file))
{
return;
}
#else
(void)USB_DeviceMtpClose(file);
#endif
if (result != kStatus_USB_Success)
{
dataInfo->code = MTP_RESPONSE_ACCESS_DENIED;
return;
}
}
length = (stringLength << 1U) + 53U; /* Date Created Offset */
stringLength = *(uint8_t *)(writeBuf + length); /* Date Created length */
length = (stringLength << 1U) + length + 1U; /* Date Modify Offset */
if (*(uint8_t *)(writeBuf + length) != 0U)
{
USB_DeviceParseDateTime((const uint16_t *)(writeBuf + length + 1U), &g_mtp.timeStamp);
}
else
{
/* Get date and time. */
USB_DeviceMtpFstat((const uint16_t *)&g_mtp.path[0], &fno);
*(uint32_t *)(&g_mtp.timeStamp) = fno.dateUnion.date;
*((uint32_t *)(&g_mtp.timeStamp) + 1U) = fno.timeUnion.time;
}
/* assign object handle */
objHandleStruct.handleID = g_mtp.nextHandleID;
g_mtp.nextHandleID++;
objHandleStruct.idUnion.parentID = objHandle;
objHandleStruct.storageID = storageID;
objHandleStruct.size = objSize;
objHandleStruct.dateUnion.date = *(uint32_t *)(&g_mtp.timeStamp);
objHandleStruct.timeUnion.time = *((uint32_t *)(&g_mtp.timeStamp) + 1U);
objHandleStruct.flag = 0U;
if (objFormat == MTP_FORMAT_ASSOCIATION)
{
objHandleStruct.flag |= MTP_OBJECT_DIR;
/* modify time stamp */
USB_DeviceMtpUtime((const uint16_t *)&g_mtp.path[0], &g_mtp.timeStamp);
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
offset = USB_DeviceMemCopyUnicodeString(&objHandleStruct.name[0], (const uint16_t *)(writeBuf + 53U), 0U);
#else
(void)USB_DeviceMemCopyUnicodeString(&objHandleStruct.name[0], (const uint16_t *)(writeBuf + 53U), 0U);
#endif
result = USB_DeviceMtpObjHandleWrite(objHandleStruct.handleID, &objHandleStruct);
dataInfo->code = MTP_RESPONSE_OK;
dataInfo->curSize = 3U;
dataInfo->param[0] = storageID;
dataInfo->param[1] = objHandle;
dataInfo->param[2] = objHandleStruct.handleID;
g_mtp.validObjInfo = 1;
g_mtp.transferTotalSize = objSize + USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
}
else
{
/* no action */
}
}
void USB_DeviceCmdSendObj(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint8_t *writeBuf;
uint32_t size;
uint32_t sizeWritten;
uint64_t freeBytes;
usb_status_t result;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
if (g_mtp.validObjInfo == 0U)
{
dataInfo->code = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
return;
}
dataInfo->curSize = USB_DEVICE_MTP_TRANSFER_BUFF_SIZE;
dataInfo->buffer = (uint8_t *)&g_mtpTransferBuffer[0];
g_mtp.transferDoneSize = 0;
result = USB_DeviceMtpOpen(&g_mtp.file, (const uint16_t *)&g_mtp.path[0],
USB_DEVICE_MTP_READ | USB_DEVICE_MTP_WRITE);
}
else if ((dataInfo->curPhase == USB_DEVICE_MTP_PHASE_DATA) || (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_RESPONSE))
{
/* Special process for receiving >4GB object. */
if (dataInfo->totalSize == USB_DEVICE_MTP_MAX_UINT64_VAL)
{
g_mtp.transferTotalSize = USB_DEVICE_MTP_MAX_UINT64_VAL;
USB_DeviceMtpGetDiskFreeBytes((const uint16_t *)&g_mtp.path[0], &freeBytes);
/* ensure at least 4GB space for this object. */
if (freeBytes < USB_DEVICE_MTP_MAX_UINT32_VAL)
{
dataInfo->code = MTP_RESPONSE_OBJECT_TOO_LARGE;
return;
}
}
if (g_mtp.transferTotalSize < dataInfo->curPos)
{
dataInfo->code = MTP_RESPONSE_STORAGE_FULL;
return;
}
/* here 512 byte aligned processing is to improve performance. */
if (g_mtp.transferDoneSize == 0U)
{
if (dataInfo->curPhase != USB_DEVICE_MTP_PHASE_RESPONSE)
{
/* first packet in the data phase */
size = dataInfo->curPos - MTP_BLOCK_SIZE;
}
else
{
/* both first and last packet */
size = dataInfo->curPos - USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
}
}
else
{
if (dataInfo->curPhase != USB_DEVICE_MTP_PHASE_RESPONSE)
{
/* intermediate packet */
size = dataInfo->curPos - g_mtp.transferDoneSize;
}
else
{
/* last packet */
size = dataInfo->curPos - g_mtp.transferDoneSize + MTP_BLOCK_SIZE -
USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
}
/* g_mtp.transferDoneSize = g_mtp.transferDoneSize - MTP_BLOCK_SIZE; */
}
writeBuf = (uint8_t *)&g_mtpTransferBuffer[0] + USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
/* result = USB_DeviceMtpLseek(g_mtp.file, g_mtp.transferDoneSize); */
result = USB_DeviceMtpWrite(g_mtp.file, writeBuf, size, &sizeWritten);
if (dataInfo->curPhase != USB_DEVICE_MTP_PHASE_RESPONSE)
{
(void)memcpy(writeBuf, writeBuf + size, MTP_BLOCK_SIZE - USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH);
}
if ((result != kStatus_USB_Success) || (sizeWritten < size))
{
dataInfo->code = MTP_RESPONSE_INCOMPLETE_TRANSFER;
return;
}
else
{
dataInfo->curSize = USB_DEVICE_MTP_TRANSFER_BUFF_SIZE - MTP_BLOCK_SIZE;
dataInfo->buffer = (uint8_t *)&g_mtpTransferBuffer[0] + MTP_BLOCK_SIZE;
}
g_mtp.transferDoneSize = dataInfo->curPos;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_RESPONSE)
{
g_mtp.validObjInfo = 0;
dataInfo->code = MTP_RESPONSE_OK;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
result = USB_DeviceMtpClose(g_mtp.file);
#else
(void)USB_DeviceMtpClose(g_mtp.file);
#endif
/* modify time stamp */
USB_DeviceMtpUtime((const uint16_t *)&g_mtp.path[0], &g_mtp.timeStamp);
}
}
else if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_CANCELLATION)
{
g_mtp.validObjInfo = 0;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
result = USB_DeviceMtpClose(g_mtp.file);
#else
(void)USB_DeviceMtpClose(g_mtp.file);
#endif
result = USB_DeviceMtpUnlink((const uint16_t *)&g_mtp.path[0]);
}
else
{
/* no action */
}
}
void USB_DeviceCmdDeleteObj(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t objHandle = dataInfo->param[0];
usb_mtp_obj_handle_t objHandleStruct;
usb_status_t result;
uint32_t i;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_CANCELLATION)
{
return;
}
dataInfo->curSize = 0; /* the number of the response parameter */
if (objHandle != USB_DEVICE_MTP_MAX_UINT32_VAL)
{
/* build path here */
if ((objHandle >= g_mtp.nextHandleID) || (objHandle == 0U) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success) ||
(USB_DeviceBuildPath(&g_mtp, objHandleStruct.storageID, objHandle, g_mtp.path) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandleStruct.flag & MTP_OBJECT_DIR) != 0U)
{
result = USB_DeviceDeleteDir(&g_mtp.path[0]);
}
else
{
result = USB_DeviceMtpUnlink((const uint16_t *)&g_mtp.path[0]);
}
if (result == kStatus_USB_Success)
{
objHandleStruct.flag |= MTP_OBJECT_DELETE;
result = USB_DeviceMtpObjHandleWrite(objHandle, &objHandleStruct);
dataInfo->code = MTP_RESPONSE_OK;
}
else
{
dataInfo->code = MTP_RESPONSE_ACCESS_DENIED;
}
}
else
{
result = kStatus_USB_Error;
/* root path */
for (i = 0; i < g_mtp.storageList->storageCount; i++)
{
result = USB_DeviceDeleteDir(g_mtp.storageList->storageInfo[i].rootPath);
if (result != kStatus_USB_Success)
{
break;
}
}
if (result == kStatus_USB_Success)
{
dataInfo->code = MTP_RESPONSE_OK;
}
else
{
dataInfo->code = MTP_RESPONSE_ACCESS_DENIED;
}
}
}
void USB_DeviceCmdGetDevicePropVal(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint16_t devPropCode = dataInfo->param[0];
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
uint32_t i;
usb_device_mtp_dev_prop_desc_t *devPropDesc;
uint32_t count;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
devPropDesc = g_mtp.devPropDescList->devPropDesc;
count = g_mtp.devPropDescList->devPropDescCount;
for (i = 0; i < count; i++)
{
if (devPropDesc[i].devPropCode == devPropCode)
{
offset = USB_DeviceAssignDevPropVal(devPropDesc[i].devPropCode, devPropDesc[i].dataType, readBuf,
&devPropDesc[i].currentVal, offset);
break;
}
}
if (i == count)
{
/* not support device property */
dataInfo->code = MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
}
else
{
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
}
void USB_DeviceCmdSetDevicePropVal(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint16_t devPropCode = dataInfo->param[0];
uint8_t *writeBuf;
uint32_t i;
uint8_t size;
usb_device_mtp_dev_prop_desc_t *devPropDesc;
uint32_t count;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
devPropDesc = g_mtp.devPropDescList->devPropDesc;
count = g_mtp.devPropDescList->devPropDescCount;
for (i = 0; i < count; i++)
{
if (devPropDesc[i].devPropCode == devPropCode)
{
break;
}
}
if (i == count)
{
/* not support device property */
dataInfo->code = MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
return;
}
if (devPropDesc[i].getSet == 0U)
{
/* only get, cannot set, return access denied */
dataInfo->code = MTP_RESPONSE_ACCESS_DENIED;
return;
}
dataInfo->curSize = USB_DEVICE_MTP_TRANSFER_BUFF_SIZE;
dataInfo->buffer = (uint8_t *)&g_mtpTransferBuffer[0];
}
else if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_RESPONSE)
{
writeBuf = (uint8_t *)&g_mtpTransferBuffer[0] + USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
switch (devPropCode)
{
case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
{
size = USB_DeviceUnicodeStringLength((const uint16_t *)(writeBuf + 1U));
size += 2U;
if ((size >> 1U) != *(uint8_t *)writeBuf)
{
dataInfo->code = MTP_RESPONSE_INVALID_DEVICE_PROP_VALUE;
return;
}
if (size > MTP_DEVICE_FRIENDLY_NAME_LEN)
{
size = MTP_DEVICE_FRIENDLY_NAME_LEN;
}
(void)memcpy(g_mtp.devFriendlyName, (const uint16_t *)(writeBuf + 1U), size);
g_mtp.devFriendlyName[MTP_DEVICE_FRIENDLY_NAME_LEN - 1U] = '\0';
g_mtp.devFriendlyName[MTP_DEVICE_FRIENDLY_NAME_LEN - 2U] = '\0';
break;
}
default:
/* TODO: identify more device property code. */
break;
}
dataInfo->code = MTP_RESPONSE_OK;
}
else
{
/* no action */
}
}
void USB_DeviceCmdGetObjPropVal(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint32_t objHandle = dataInfo->param[0];
uint16_t objPropCode = dataInfo->param[1];
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
uint32_t i;
uint32_t j;
usb_mtp_obj_handle_t objHandleStruct;
usb_device_mtp_obj_prop_t *prop;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
if ((objHandle == 0U) || (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL))
{
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandle >= g_mtp.nextHandleID) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
prop = g_mtp.objPropList->objProp;
j = 0U;
for (i = 0U; i < g_mtp.objPropList->objPropCount; i++)
{
if (prop[i].objFormat == USB_DeviceIdentifyFileType(&objHandleStruct))
{
for (; j < prop[i].objPropDescCount; j++)
{
if (prop[i].objPropDesc[j].objPropCode == objPropCode)
{
break;
}
}
break;
}
}
if ((i == g_mtp.objPropList->objPropCount) || (j == prop[i].objPropDescCount))
{
/* invalid object property code */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
return;
}
offset = USB_DeviceAssignObjPropVal(objPropCode, prop[i].objPropDesc[j].dataType, readBuf, &objHandleStruct,
offset); /* object value */
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
void USB_DeviceCmdSetObjPropVal(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t objHandle = dataInfo->param[0];
uint16_t objPropCode = dataInfo->param[1];
uint8_t *writeBuf;
uint32_t i;
uint32_t j;
uint32_t size;
usb_mtp_obj_handle_t objHandleStruct;
uint16_t renameBuffer[MTP_PATH_MAX_LEN >> 1U];
usb_status_t result;
usb_device_mtp_obj_prop_t *prop;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
if ((objHandle == 0U) || (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL))
{
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandle >= g_mtp.nextHandleID) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success) ||
(USB_DeviceBuildPath(&g_mtp, objHandleStruct.storageID, objHandle, g_mtp.path) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
prop = g_mtp.objPropList->objProp;
j = 0U;
for (i = 0U; i < g_mtp.objPropList->objPropCount; i++)
{
if (prop[i].objFormat == USB_DeviceIdentifyFileType(&objHandleStruct))
{
for (; j < prop[i].objPropDescCount; j++)
{
if (prop[i].objPropDesc[j].objPropCode == objPropCode)
{
break;
}
}
break;
}
}
if ((i == g_mtp.objPropList->objPropCount) || (j == prop[i].objPropDescCount))
{
/* invalid object property code */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
return;
}
if (prop[i].objPropDesc[j].getSet == 0U)
{
/* only get, cannot set, return access denied */
dataInfo->code = MTP_RESPONSE_ACCESS_DENIED;
return;
}
dataInfo->curSize = USB_DEVICE_MTP_TRANSFER_BUFF_SIZE;
dataInfo->buffer = (uint8_t *)&g_mtpTransferBuffer[0];
}
else if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_RESPONSE)
{
writeBuf = (uint8_t *)&g_mtpTransferBuffer[0] + USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
switch (objPropCode)
{
case MTP_OBJECT_PROPERTY_OBJECT_FILE_NAME:
{
size = USB_DeviceUnicodeStringLength((const uint16_t *)(writeBuf + 1U));
size = (size + 2U) >> 1U;
if (size != *(uint8_t *)writeBuf)
{
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_PROP_VALUE;
return;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success != USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct))
{
return;
}
#else
(void)USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct);
#endif
/* build rename buffer */
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
/* j indicates the offset */
j = USB_DeviceMemCopyUnicodeString(&renameBuffer[0], (const uint16_t *)&g_mtp.path[0], 0);
#else
(void)USB_DeviceMemCopyUnicodeString(&renameBuffer[0], (const uint16_t *)&g_mtp.path[0], 0);
#endif
size = USB_DeviceUnicodeStringLength((const uint16_t *)&g_mtp.path[0]);
size >>= 1U;
while (renameBuffer[size] != '/')
{
size--;
};
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
/* j indicates the offset */
j = USB_DeviceMemCopyUnicodeString(&renameBuffer[size + 1U], (const uint16_t *)(writeBuf + 1U), 0);
#else
(void)USB_DeviceMemCopyUnicodeString(&renameBuffer[size + 1U], (const uint16_t *)(writeBuf + 1U), 0);
#endif
result = USB_DeviceMtpRename((const uint16_t *)&g_mtp.path[0], (const uint16_t *)&renameBuffer[0]);
if (result != kStatus_USB_Success)
{
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_PROP_VALUE;
return;
}
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
/* j indicates the offset */
j = USB_DeviceMemCopyUnicodeString(&objHandleStruct.name[0], (const uint16_t *)(writeBuf + 1U), 0);
#else
(void)USB_DeviceMemCopyUnicodeString(&objHandleStruct.name[0], (const uint16_t *)(writeBuf + 1U), 0);
#endif
result = USB_DeviceMtpObjHandleWrite(objHandle, &objHandleStruct);
(void)result;
break;
}
default:
/* TODO: identify more object property code. */
break;
}
}
else
{
/* no action */
}
}
void USB_DeviceCmdGetObjReferences(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t offset = USB_DEVICE_MTP_MINIMUM_CONTAINER_LENGTH;
uint32_t objHandle = dataInfo->param[0];
uint8_t *readBuf = (uint8_t *)&g_mtpTransferBuffer[0];
usb_mtp_obj_handle_t objHandleStruct;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_COMMAND)
{
if ((objHandle == 0U) || (objHandle == USB_DEVICE_MTP_MAX_UINT32_VAL))
{
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandle >= g_mtp.nextHandleID) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
offset = USB_DeviceMemCopyDword(readBuf, 0, offset);
dataInfo->totalSize = offset;
dataInfo->curSize = offset;
dataInfo->buffer = readBuf;
}
}
void USB_DeviceCmdMoveObj(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t objHandle = dataInfo->param[0];
uint32_t storageID = dataInfo->param[1];
uint32_t newParentObj = dataInfo->param[2];
usb_mtp_obj_handle_t objHandleStruct;
uint16_t destPath[MTP_PATH_MAX_LEN >> 1U];
usb_status_t result;
uint8_t i;
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_CANCELLATION)
{
return;
}
for (i = 0; i < g_mtp.storageList->storageCount; i++)
{
if (g_mtp.storageList->storageInfo[i].storageID == storageID)
{
break;
}
}
if (i == g_mtp.storageList->storageCount)
{
/* invalid storage ID */
dataInfo->code = MTP_RESPONSE_INVALID_STORAGE_ID;
return;
}
/* build destination path */
if (newParentObj == 0U)
{
USB_DeviceGetRootPath(&g_mtp, storageID, (uint8_t *)&destPath[0]);
}
else
{
if ((newParentObj >= g_mtp.nextHandleID) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, newParentObj, &objHandleStruct) != kStatus_USB_Success) ||
((objHandleStruct.flag & MTP_OBJECT_DIR) == 0U) ||
(USB_DeviceBuildPath(&g_mtp, objHandleStruct.storageID, newParentObj, (uint8_t *)&destPath[0]) !=
kStatus_USB_Success))
{
/* invalid parent object */
dataInfo->code = MTP_RESPONSE_INVALID_PARENT_OBJECT;
return;
}
}
/* build source path */
if ((objHandle >= g_mtp.nextHandleID) || (objHandle == 0U) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success) ||
(USB_DeviceBuildPath(&g_mtp, objHandleStruct.storageID, objHandle, g_mtp.path) != kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
/* append file name to the path */
result = USB_DeviceAppendNameToPath(&destPath[0], (const uint16_t *)&objHandleStruct.name[0]);
/* Move obejct */
if (result == kStatus_USB_Success)
{
result = USB_DeviceMtpRename((uint16_t *)g_mtp.path, (uint16_t *)&destPath[0]);
}
if (result != kStatus_USB_Success)
{
dataInfo->code = MTP_RESPONSE_GENERAL_ERROR;
}
else
{
/* replace parent handle with new parent handle */
objHandleStruct.idUnion.parentID = newParentObj;
USB_DeviceMtpObjHandleWrite(objHandleStruct.handleID, &objHandleStruct);
dataInfo->code = MTP_RESPONSE_OK;
}
}
void USB_DeviceCmdCopyObj(void *param)
{
usb_device_mtp_cmd_data_struct_t *dataInfo = (usb_device_mtp_cmd_data_struct_t *)param;
uint32_t objHandle = dataInfo->param[0];
uint32_t storageID = dataInfo->param[1];
uint32_t newParentObj = dataInfo->param[2];
usb_mtp_obj_handle_t objHandleStruct;
uint16_t destPath[MTP_PATH_MAX_LEN >> 1U];
uint16_t srcPath[MTP_PATH_MAX_LEN >> 1U];
usb_device_mtp_file_info_t fno;
usb_status_t result;
uint8_t i;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
uint32_t offset = 0U;
#endif
if (dataInfo->curPhase == USB_DEVICE_MTP_PHASE_CANCELLATION)
{
return;
}
dataInfo->curSize = 0; /* the number of the response parameter */
for (i = 0; i < g_mtp.storageList->storageCount; i++)
{
if (g_mtp.storageList->storageInfo[i].storageID == storageID)
{
break;
}
}
if (i == g_mtp.storageList->storageCount)
{
/* invalid storage ID */
dataInfo->code = MTP_RESPONSE_INVALID_STORAGE_ID;
return;
}
/* build destination path */
if (newParentObj == 0U)
{
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
offset = USB_DeviceGetRootPath(&g_mtp, storageID, (uint8_t *)&destPath[0]);
#else
(void)USB_DeviceGetRootPath(&g_mtp, storageID, (uint8_t *)&destPath[0]);
#endif
}
else
{
if ((newParentObj >= g_mtp.nextHandleID) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, newParentObj, &objHandleStruct) != kStatus_USB_Success) ||
((objHandleStruct.flag & MTP_OBJECT_DIR) == 0U) ||
(USB_DeviceBuildPath(&g_mtp, objHandleStruct.storageID, newParentObj, (uint8_t *)&destPath[0]) !=
kStatus_USB_Success))
{
/* invalid parent object */
dataInfo->code = MTP_RESPONSE_INVALID_PARENT_OBJECT;
return;
}
}
/* build source path */
if ((objHandle >= g_mtp.nextHandleID) || (objHandle == 0U) ||
(USB_DeviceGetObjHandleInfo(&g_mtp, objHandle, &objHandleStruct) != kStatus_USB_Success) ||
(USB_DeviceBuildPath(&g_mtp, objHandleStruct.storageID, objHandle, (uint8_t *)&srcPath[0]) !=
kStatus_USB_Success))
{
/* invalid object handle */
dataInfo->code = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
return;
}
if ((objHandleStruct.flag & MTP_OBJECT_DIR) != 0U)
{
result = USB_DeviceCopyDir((uint8_t *)destPath, (uint8_t *)&srcPath[0]);
if (result == kStatus_USB_Success)
{
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success !=
USB_DeviceAppendNameToPath(&destPath[0], (const uint16_t *)&objHandleStruct.name[0]))
{
return;
}
#else
(void)USB_DeviceAppendNameToPath(&destPath[0], (const uint16_t *)&objHandleStruct.name[0]);
#endif
}
}
else
{
/* append file name to the path */
result = USB_DeviceAppendNameToPath(&destPath[0], (const uint16_t *)&objHandleStruct.name[0]);
if (result == kStatus_USB_Success)
{
result = USB_DeviceCopyFile((uint8_t *)destPath, (uint8_t *)&srcPath[0]);
}
}
if (result != kStatus_USB_Success)
{
dataInfo->code = MTP_RESPONSE_GENERAL_ERROR;
}
else
{
/* get date and time */
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success != USB_DeviceMtpFstat((const uint16_t *)&destPath[0], &fno))
{
return;
}
#else
(void)USB_DeviceMtpFstat((const uint16_t *)&destPath[0], &fno);
#endif
objHandleStruct.handleID = g_mtp.nextHandleID;
g_mtp.nextHandleID++;
objHandleStruct.idUnion.parentID = newParentObj;
objHandleStruct.storageID = storageID;
objHandleStruct.dateUnion.date = fno.dateUnion.date;
objHandleStruct.timeUnion.time = fno.timeUnion.time;
objHandleStruct.flag &= ~MTP_OBJECT_ALREADY_GET;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success != USB_DeviceMtpObjHandleWrite(objHandleStruct.handleID, &objHandleStruct))
{
return;
}
#else
(void)USB_DeviceMtpObjHandleWrite(objHandleStruct.handleID, &objHandleStruct);
#endif
dataInfo->code = MTP_RESPONSE_OK;
dataInfo->curSize = 1;
dataInfo->param[0] = objHandleStruct.handleID;
}
}