diff options
| author | hathach <[email protected]> | 2025-09-25 17:43:25 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2025-09-25 17:47:50 +0700 |
| commit | c9a8330081b59c05b901889d405ed7b9648c0947 (patch) | |
| tree | 3b04636e06912d14ee5b7440e5ca5f6adca7933a | |
| parent | f8397717ea3f476c810ae3ce27ec4c866b305506 (diff) | |
implement send object command, able to create new file
| -rw-r--r-- | examples/device/mtp/src/mtp_fs_example.c | 332 | ||||
| -rw-r--r-- | src/class/mtp/mtp.h | 6 | ||||
| -rw-r--r-- | src/class/mtp/mtp_device.c | 183 | ||||
| -rw-r--r-- | src/class/mtp/mtp_device.h | 2 |
4 files changed, 158 insertions, 365 deletions
diff --git a/examples/device/mtp/src/mtp_fs_example.c b/examples/device/mtp/src/mtp_fs_example.c index d6d7f1907..468fc9146 100644 --- a/examples/device/mtp/src/mtp_fs_example.c +++ b/examples/device/mtp/src/mtp_fs_example.c @@ -176,107 +176,6 @@ static inline uint8_t* fs_malloc(size_t size) { //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ -int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data) { - const mtp_container_command_t* command = cb_data->command_container; - mtp_container_info_t* resp = &cb_data->io_container; - switch (command->code) { - case MTP_OP_SEND_OBJECT_INFO: { - fs_file_t* f = fs_get_file(send_obj_handle); - if (f == NULL) { - resp->header->code = MTP_RESP_GENERAL_ERROR; - break; - } - // parameter is: storage id, parent handle, new handle - mtp_container_add_uint32(resp, SUPPORTED_STORAGE_ID); - mtp_container_add_uint32(resp, f->parent); - mtp_container_add_uint32(resp, send_obj_handle); - resp->header->code = MTP_RESP_OK; - break; - } - - default: - resp->header->code = (cb_data->xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR; - break; - } - tud_mtp_response_send(resp); - return 0; -} - -int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data) { - (void) cb_data; - return 0; // nothing to do -} - -int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data) { - const mtp_container_command_t* command = cb_data->command_container; - mtp_container_info_t* io_container = &cb_data->io_container; - uint32_t resp_code = 0; - switch (command->code) { - case MTP_OP_GET_OBJECT: { - // File contents span over multiple xfers - const uint32_t obj_handle = command->params[0]; - fs_file_t* f = fs_get_file(obj_handle); - if (f == NULL) { - resp_code = MTP_RESP_INVALID_OBJECT_HANDLE; - } else { - // file contents offset is xferred byte minus header size - const uint32_t offset = cb_data->xferred_bytes - sizeof(mtp_container_header_t); - const uint32_t xact_len = tu_min32(f->size - offset, io_container->payload_size); - memcpy(io_container->payload, f->data + offset, xact_len); - tud_mtp_data_send(&cb_data->io_container); - } - break; - } - - case MTP_OP_SEND_OBJECT_INFO: { - mtp_object_info_header_t* obj_info = (mtp_object_info_header_t*) io_container->payload; - if (obj_info->storage_id != 0 && obj_info->storage_id != SUPPORTED_STORAGE_ID) { - resp_code = MTP_RESP_INVALID_STORAGE_ID; - break; - } - - if (obj_info->parent_object) { - fs_file_t* parent = fs_get_file(obj_info->parent_object); - if (parent == NULL || !parent->association_type) { - resp_code = MTP_RESP_INVALID_PARENT_OBJECT; - break; - } - } - - fs_file_t* f = fs_create_file(); - f->object_format = obj_info->object_format; - f->protection_status = obj_info->protection_status; - f->image_pix_width = obj_info->image_pix_width; - f->image_pix_height = obj_info->image_pix_height; - f->image_bit_depth = obj_info->image_bit_depth; - f->parent = obj_info->parent_object; - f->association_type = obj_info->association_type; - f->size = obj_info->object_compressed_size; - f->data = fs_malloc(f->size); - if (f->data == NULL) { - resp_code = MTP_RESP_STORE_FULL; - break; - } - uint8_t* buf = io_container->payload + sizeof(mtp_object_info_header_t); - mtp_container_get_string(buf,f->name); - // ignore date created/modified/keywords - break; - } - - default: - resp_code = MTP_RESP_OPERATION_NOT_SUPPORTED; - break; - } - - // send response if needed - if (resp_code != 0) { - io_container->header->code = resp_code; - tud_mtp_response_send(io_container); - } - - return 0; // 0 mean data/response is sent already -} - int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) { const mtp_container_command_t* command = cb_data->command_container; mtp_container_info_t* io_container = &cb_data->io_container; @@ -425,13 +324,13 @@ int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) { case MTP_OP_GET_OBJECT: { const uint32_t obj_handle = command->params[0]; - fs_file_t* obj = fs_get_file(obj_handle); - if (obj == NULL) { + fs_file_t* f = fs_get_file(obj_handle); + if (f == NULL) { resp_code = MTP_RESP_INVALID_OBJECT_HANDLE; } else { // If file contents is larger than CFG_TUD_MTP_EP_BUFSIZE, only partial data is added here // the rest will be sent in tud_mtp_data_more_cb - mtp_container_add_raw(io_container, obj->data, obj->size); + mtp_container_add_raw(io_container, f->data, f->size); tud_mtp_data_send(io_container); } break; @@ -450,8 +349,16 @@ int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) { break; } - case MTP_OP_SEND_OBJECT: + case MTP_OP_SEND_OBJECT: { + fs_file_t* f = fs_get_file(send_obj_handle); + if (f == NULL) { + resp_code = MTP_RESP_INVALID_OBJECT_HANDLE; + } else { + io_container->header->len += f->size; + tud_mtp_data_receive(io_container); + } break; + } default: resp_code = MTP_RESP_OPERATION_NOT_SUPPORTED; @@ -467,124 +374,143 @@ int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) { return 0; } -//--------------------------------------------------------------------+ -// API -//--------------------------------------------------------------------+ -#if 0 -mtp_response_t tud_mtp_storage_format(uint32_t storage_id) { - if (_fs_operation.session_id == 0) { - TU_LOG1("ERR: Session not open\r\n"); - return MTP_RESP_SESSION_NOT_OPEN; - } - if (storage_id != SUPPORTED_STORAGE_ID) { - TU_LOG1("ERR: Unexpected storage id %ld\r\n", storage_id); - return MTP_RESP_INVALID_STORAGE_ID; - } +int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data) { + const mtp_container_command_t* command = cb_data->command_container; + mtp_container_info_t* io_container = &cb_data->io_container; + uint32_t resp_code = 0; + switch (command->code) { + case MTP_OP_GET_OBJECT: { + // File contents span over multiple xfers + const uint32_t obj_handle = command->params[0]; + fs_file_t* f = fs_get_file(obj_handle); + if (f == NULL) { + resp_code = MTP_RESP_INVALID_OBJECT_HANDLE; + } else { + // file contents offset is xferred byte minus header size + const uint32_t offset = cb_data->total_xferred_bytes - sizeof(mtp_container_header_t); + const uint32_t xact_len = tu_min32(f->size - offset, io_container->payload_bytes); + memcpy(io_container->payload, f->data + offset, xact_len); + tud_mtp_data_send(io_container); + } + break; + } - // Simply deallocate all entries - for (unsigned int i = 0; i < FS_MAX_NODES; i++) - fs_objects[i].allocated = false; - TU_LOG1("Format completed\r\n"); - return MTP_RESP_OK; -} + case MTP_OP_SEND_OBJECT_INFO: { + mtp_object_info_header_t* obj_info = (mtp_object_info_header_t*) io_container->payload; + if (obj_info->storage_id != 0 && obj_info->storage_id != SUPPORTED_STORAGE_ID) { + resp_code = MTP_RESP_INVALID_STORAGE_ID; + break; + } -mtp_response_t tud_mtp_storage_object_write_info(uint32_t storage_id, uint32_t parent_object, - uint32_t* new_object_handle, const mtp_object_info_header_t* info) { - fs_file_t* obj = NULL; + if (obj_info->parent_object) { + fs_file_t* parent = fs_get_file(obj_info->parent_object); + if (parent == NULL || !parent->association_type) { + resp_code = MTP_RESP_INVALID_PARENT_OBJECT; + break; + } + } - if (_fs_operation.session_id == 0) { - TU_LOG1("ERR: Session not open\r\n"); - return MTP_RESP_SESSION_NOT_OPEN; - } - // Accept command on default storage - if (storage_id != 0xFFFFFFFF && storage_id != SUPPORTED_STORAGE_ID) { - TU_LOG1("ERR: Unexpected storage id %ld\r\n", storage_id); - return MTP_RESP_INVALID_STORAGE_ID; + fs_file_t* f = fs_create_file(); + f->object_format = obj_info->object_format; + f->protection_status = obj_info->protection_status; + f->image_pix_width = obj_info->image_pix_width; + f->image_pix_height = obj_info->image_pix_height; + f->image_bit_depth = obj_info->image_bit_depth; + f->parent = obj_info->parent_object; + f->association_type = obj_info->association_type; + f->size = obj_info->object_compressed_size; + f->data = fs_malloc(f->size); + if (f->data == NULL) { + resp_code = MTP_RESP_STORE_FULL; + break; + } + uint8_t* buf = io_container->payload + sizeof(mtp_object_info_header_t); + mtp_container_get_string(buf, f->name); + // ignore date created/modified/keywords + break; + } + + case MTP_OP_SEND_OBJECT: { + fs_file_t* f = fs_get_file(send_obj_handle); + if (f == NULL) { + resp_code = MTP_RESP_INVALID_OBJECT_HANDLE; + } else { + // file contents offset is total xferred minus header size minus last received chunk + const uint32_t offset = cb_data->total_xferred_bytes - sizeof(mtp_container_header_t) - io_container->payload_bytes; + memcpy(f->data + offset, io_container->payload, io_container->payload_bytes); + tud_mtp_data_receive(io_container); // receive more data if needed + } + break; + } + + default: + resp_code = MTP_RESP_OPERATION_NOT_SUPPORTED; + break; } - if (info->object_compressed_size > FS_MAX_NODE_BYTES) { - TU_LOG1("Object size %ld is more than maximum %ld\r\n", info->object_compressed_size, FS_MAX_NODE_BYTES); - return MTP_RESP_STORE_FULL; + // send response if needed + if (resp_code != 0) { + io_container->header->code = resp_code; + tud_mtp_response_send(io_container); } - // Request for objects with no parent (0xFFFFFFFF) are considered root objects - if (parent_object == 0xFFFFFFFF) - parent_object = 0; + return 0; // 0 mean data/response is sent already +} - // Ensure we are not creating an orphaned object outside root - if (parent_object != 0) { - obj = fs_get_file(parent_object); - if (obj == NULL) { - TU_LOG1("Parent %ld does not exist\r\n", parent_object); - return MTP_RESP_INVALID_PARENT_OBJECT; - } - if (!obj->association_type) { - TU_LOG1("Parent %ld is not an association\r\n", parent_object); - return MTP_RESP_INVALID_PARENT_OBJECT; +int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data) { + const mtp_container_command_t* command = cb_data->command_container; + mtp_container_info_t* resp = &cb_data->io_container; + switch (command->code) { + case MTP_OP_SEND_OBJECT_INFO: { + fs_file_t* f = fs_get_file(send_obj_handle); + if (f == NULL) { + resp->header->code = MTP_RESP_GENERAL_ERROR; + break; + } + // parameter is: storage id, parent handle, new handle + mtp_container_add_uint32(resp, SUPPORTED_STORAGE_ID); + mtp_container_add_uint32(resp, f->parent); + mtp_container_add_uint32(resp, send_obj_handle); + resp->header->code = MTP_RESP_OK; + break; } - } - // Search for first free object - for (unsigned int i = 0; i < FS_MAX_NODES; i++) { - if (!fs_objects[i].allocated) { - obj = &fs_objects[i]; + case MTP_OP_SEND_OBJECT: + resp->header->code = (cb_data->xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR; break; - } - } - if (obj == NULL) { - TU_LOG1("No space left on device\r\n"); - return MTP_RESP_STORE_FULL; + default: + resp->header->code = (cb_data->xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR; + break; } - // Fill-in structure - obj->allocated = true; - obj->handle = ++_fs_operation.last_handle; - obj->parent = parent_object; - obj->size = info->object_compressed_size; - obj->association_type = info->object_format == MTP_OBJ_FORMAT_ASSOCIATION; - - // Extract variable data - uint16_t offset_data = sizeof(mtp_object_info_header_t); - mtpd_gct_get_string(&offset_data, obj->name, FS_MAX_NODE_NAME_LEN); - mtpd_gct_get_string(&offset_data, obj->created, FS_ISODATETIME_LEN); - mtpd_gct_get_string(&offset_data, obj->modified, FS_ISODATETIME_LEN); - - TU_LOG1("Create %s %s with handle %ld, parent %ld and size %ld\r\n", - obj->association_type ? "association" : "object", - obj->name, obj->handle, obj->parent, obj->size); - *new_object_handle = obj->handle; - // Initialize operation - _fs_operation.write_handle = obj->handle; - _fs_operation.write_pos = 0; - return MTP_RESP_OK; + tud_mtp_response_send(resp); + return 0; } -mtp_response_t tud_mtp_storage_object_write(uint32_t object_handle, const uint8_t* buffer, uint32_t size) { - fs_file_t* obj; +int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data) { + (void) cb_data; + return 0; // nothing to do +} - obj = fs_get_file(object_handle); - if (obj == NULL) { - TU_LOG1("ERR: Object with handle %ld does not exist\r\n", object_handle); - return MTP_RESP_INVALID_OBJECT_HANDLE; +//--------------------------------------------------------------------+ +// API +//--------------------------------------------------------------------+ +#if 0 +mtp_response_t tud_mtp_storage_format(uint32_t storage_id) { + if (_fs_operation.session_id == 0) { + TU_LOG1("ERR: Session not open\r\n"); + return MTP_RESP_SESSION_NOT_OPEN; } - // It's a requirement that this command is preceded by a write info - if (object_handle != _fs_operation.write_handle) { - TU_LOG1("ERR: Object %ld not open for write\r\n", object_handle); - return MTP_RESP_NO_VALID_OBJECTINFO; + if (storage_id != SUPPORTED_STORAGE_ID) { + TU_LOG1("ERR: Unexpected storage id %ld\r\n", storage_id); + return MTP_RESP_INVALID_STORAGE_ID; } - TU_LOG1("Write object %ld: data chunk at %ld/%ld bytes at offset %ld\r\n", object_handle, _fs_operation.write_pos, - obj->size, size); - TU_ASSERT(obj->size >= _fs_operation.write_pos + size, MTP_RESP_INCOMPLETE_TRANSFER); - if (_fs_operation.write_pos + size < FS_MAX_NODE_BYTES) - memcpy(&obj->data[_fs_operation.write_pos], buffer, size); - _fs_operation.write_pos += size; - // Write operation completed - if (_fs_operation.write_pos == obj->size) { - _fs_operation.write_handle = 0; - _fs_operation.write_pos = 0; - } + // Simply deallocate all entries + for (unsigned int i = 0; i < FS_MAX_NODES; i++) + fs_objects[i].allocated = false; + TU_LOG1("Format completed\r\n"); return MTP_RESP_OK; } diff --git a/src/class/mtp/mtp.h b/src/class/mtp/mtp.h index e713d5c23..15cf1bfc6 100644 --- a/src/class/mtp/mtp.h +++ b/src/class/mtp/mtp.h @@ -59,8 +59,6 @@ typedef enum { MTP_PHASE_IDLE = 0, MTP_PHASE_COMMAND, MTP_PHASE_DATA, - MTP_PHASE_DATA_IN, - MTP_PHASE_DATA_OUT, MTP_PHASE_RESPONSE, MTP_PHASE_RESPONSE_QUEUED, MTP_PHASE_ERROR, @@ -690,7 +688,7 @@ typedef struct { uint16_t* payload16; uint32_t* payload32; }; - uint32_t payload_size; + uint32_t payload_bytes; // available bytes for read/write } mtp_container_info_t; #define mtp_string_t(_nchars) \ @@ -899,7 +897,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint32(mtp_conta //--------------------------------------------------------------------+ TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_get_string(uint8_t* buf, uint16_t utf16[]) { uint8_t nchars = *buf++; - memcpy(buf, utf16, nchars * 2); + memcpy(utf16, buf, 2 * nchars); return 1 + nchars * 2; } diff --git a/src/class/mtp/mtp_device.c b/src/class/mtp/mtp_device.c index db562d0c7..6d1c7b29b 100644 --- a/src/class/mtp/mtp_device.c +++ b/src/class/mtp/mtp_device.c @@ -266,7 +266,8 @@ static bool mtpd_data_xfer(mtp_container_info_t* p_container, uint8_t ep_addr) { p_container->header->transaction_id = p_mtp->command.transaction_id; p_mtp->io_header = *p_container->header; // save header for subsequent data } else { - p_mtp->total_len = CFG_TUD_MTP_EP_BUFSIZE; + // OUT transfer: total length is at least max packet size + p_mtp->total_len = tu_max32(p_container->header->len, CFG_TUD_MTP_EP_BUFSIZE); } } else { // subsequent data block: payload only @@ -274,7 +275,10 @@ static bool mtpd_data_xfer(mtp_container_info_t* p_container, uint8_t ep_addr) { } const uint16_t xact_len = tu_min32(p_mtp->total_len - p_mtp->xferred_len, CFG_TUD_MTP_EP_BUFSIZE); - TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, _mtpd_epbuf.buf, xact_len)); + if (xact_len) { + // already transferred all bytes in header's length. Application make an unnecessary extra call + TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, _mtpd_epbuf.buf, xact_len)); + } return true; } @@ -310,13 +314,23 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t TU_LOG_DRV(" MTP %s phase = %u\r\n", (const char *) tu_lookup_find(&_mtp_op_table, p_mtp->command.code), p_mtp->phase); #endif + const mtp_container_info_t headered_packet = { + .header = &p_container->header, + .payload32 = p_container->data, + .payload_bytes = CFG_TUD_MTP_EP_BUFSIZE - sizeof(mtp_container_header_t) + }; + + const mtp_container_info_t headerless_packet = { + .header = &p_mtp->io_header, + .payload = _mtpd_epbuf.buf, + .payload_bytes = CFG_TUD_MTP_EP_BUFSIZE + }; + tud_mtp_cb_data_t cb_data; cb_data.idx = 0; cb_data.command_container = &p_mtp->command; - cb_data.io_container.header = &p_container->header; - cb_data.io_container.payload32 = p_container->data; - cb_data.io_container.payload_size = CFG_TUD_MTP_EP_BUFSIZE - sizeof(mtp_container_header_t); - cb_data.xferred_bytes = 0; + cb_data.io_container = headered_packet; + cb_data.total_xferred_bytes = 0; cb_data.xfer_result = event; switch (p_mtp->phase) { @@ -339,7 +353,7 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t case MTP_PHASE_DATA: { const uint16_t bulk_mps = (tud_speed_get() == TUSB_SPEED_HIGH) ? 512 : 64; p_mtp->xferred_len += xferred_bytes; - cb_data.xferred_bytes = p_mtp->xferred_len; + cb_data.total_xferred_bytes = p_mtp->xferred_len; bool is_complete = false; // complete if ZLP or short packet or overflow @@ -349,12 +363,6 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t is_complete = true; } - const mtp_container_info_t headerless_packet = { - .header = &p_mtp->io_header, - .payload = _mtpd_epbuf.buf, - .payload_size = CFG_TUD_MTP_EP_BUFSIZE - }; - if (ep_addr == p_mtp->ep_in) { // Data In if (is_complete) { @@ -370,12 +378,17 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if (p_mtp->xferred_len == xferred_bytes) { // 1st OUT packet: header + payload p_mtp->io_header = p_container->header; // save header for subsequent transaction + cb_data.io_container.payload_bytes = xferred_bytes - sizeof(mtp_container_header_t); } else { // 2nd+ packet: payload only cb_data.io_container = headerless_packet; + cb_data.io_container.payload_bytes = xferred_bytes; } tud_mtp_data_xfer_cb(&cb_data); + if (is_complete) { + // back to header + payload for response + cb_data.io_container = headered_packet; cb_data.io_container.header->len = sizeof(mtp_container_header_t); tud_mtp_data_complete_cb(&cb_data); } @@ -383,80 +396,6 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t break; } -#if 0 - case MTP_PHASE_DATA_IN: - p_mtp->xferred_len += xferred_bytes; - p_mtp->handled_len = p_mtp->xferred_len; - - // Check if transfer completed TODO check ZLP with FS/HS bulk size - if (p_mtp->xferred_len >= p_mtp->total_len && (xferred_bytes == 0 || (xferred_bytes % CFG_MTP_EP_SIZE) != 0)) { - p_mtp->phase = MTP_PHASE_RESPONSE; - p_container->code = MTP_RESP_OK; - p_container->len = MTP_CONTAINER_HEADER_LENGTH; - if (p_mtp->session_id != 0) { // is this needed ? - p_container->data[0] = p_mtp->session_id; - p_container->len += sizeof(uint32_t); - } - } else { - // Send next block of DATA - if (p_mtp->xferred_len == p_mtp->total_len) { - // send Zero-Length Packet - TU_ASSERT(usbd_edpt_xfer(rhport, p_mtp->ep_in, NULL, 0 )); - } else { - p_mtp->phase = mtpd_handle_data(); - if (p_mtp->phase == MTP_PHASE_DATA_IN) { - TU_ASSERT(usbd_edpt_xfer(rhport, p_mtp->ep_in, ((uint8_t *)(&p_container->data)), (uint16_t)p_mtp->queued_len)); - } - } - } - break; - - case MTP_PHASE_DATA_OUT: - // First block of data - if (p_mtp->xferred_len == 0) { - p_mtp->total_len = p_container->len; - p_mtp->handled_len = 0; - p_mtp->xfer_completed = false; - TU_ASSERT(p_container->type == MTP_CONTAINER_TYPE_DATA_BLOCK); - } - p_mtp->xferred_len += xferred_bytes; - - // A zero-length or a short packet termination - if (xferred_bytes < CFG_MTP_EP_SIZE) { - p_mtp->xfer_completed = true; - // Handle data block - p_mtp->phase = mtpd_handle_data(); - if (p_mtp->phase == MTP_PHASE_DATA_OUT) { - TU_ASSERT(usbd_edpt_xfer(rhport, p_mtp->ep_out, (uint8_t*) p_container, sizeof(mtp_generic_container_t)), 0); - p_mtp->xferred_len = 0; - p_mtp->xfer_completed = false; - } - } else { - // Handle data block when container is full - if (p_mtp->xferred_len - p_mtp->handled_len >= MTP_MAX_PACKET_SIZE - CFG_MTP_EP_SIZE) { - p_mtp->phase = mtpd_handle_data(); - p_mtp->handled_len = p_mtp->xferred_len; - } - // Transfer completed: wait for zero-length packet - // Some platforms may not respect EP size and xferred_bytes may be more than CFG_MTP_EP_SIZE if - // the OUT EP is waiting for more data. Ensure we are not waiting for more than CFG_MTP_EP_SIZE. - if (p_mtp->total_len == p_mtp->xferred_len) { - TU_ASSERT(usbd_edpt_xfer(rhport, p_mtp->ep_out, ((uint8_t *)(&p_container->data)), CFG_MTP_EP_SIZE), 0); - } else if (p_mtp->handled_len == 0) { - // First data block includes container header + container data - TU_ASSERT(usbd_edpt_xfer(rhport, p_mtp->ep_out, - (uint8_t*) p_container + p_mtp->xferred_len, - (uint16_t)TU_MIN(p_mtp->total_len - p_mtp->xferred_len, CFG_MTP_EP_SIZE))); - } else { - // Successive data block includes only container data - TU_ASSERT(usbd_edpt_xfer(rhport, p_mtp->ep_out, - ((uint8_t *)(&p_container->data)) + p_mtp->xferred_len - p_mtp->handled_len, - (uint16_t)TU_MIN(p_mtp->total_len - p_mtp->xferred_len, CFG_MTP_EP_SIZE))); - } - } - break; -#endif - case MTP_PHASE_RESPONSE_QUEUED: // response phase is complete -> prepare for new command TU_ASSERT(ep_addr == p_mtp->ep_in); @@ -574,76 +513,6 @@ mtp_phase_type_t mtpd_handle_cmd_delete_object(void) return MTP_PHASE_RESPONSE; } -mtp_phase_type_t mtpd_handle_cmd_send_object_info(void) -{ - mtp_generic_container_t* p_container = &_mtpd_epbuf.buf; - _mtpd_soi.storage_id = p_container->data[0]; - _mtpd_soi.parent_object_handle = (p_container->data[1] == 0xFFFFFFFF ? 0 : p_container->data[1]); - - // Enter OUT phase and wait for DATA BLOCK - return MTP_PHASE_DATA_OUT; -} - -mtp_phase_type_t mtpd_handle_dto_send_object_info(void) -{ - mtp_generic_container_t* p_container = &_mtpd_epbuf.buf; - uint32_t new_object_handle = 0; - mtp_response_t res = tud_mtp_storage_object_write_info(_mtpd_soi.storage_id, _mtpd_soi.parent_object_handle, &new_object_handle, (mtp_object_info_header_t *)p_container->data); - mtp_phase_type_t phase; - if ((phase = mtpd_chk_generic(__func__, (res != MTP_RESP_OK), res, "")) != MTP_PHASE_NONE) return phase; - - // Save send_object_info - _mtpd_soi.object_handle = new_object_handle; - - // Response - p_container->len = MTP_CONTAINER_HEADER_LENGTH + 3 * sizeof(uint32_t); - p_container->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK; - p_container->code = MTP_RESP_OK; - p_container->data[0] = _mtpd_soi.storage_id; - p_container->data[1] = _mtpd_soi.parent_object_handle; - p_container->data[2] = _mtpd_soi.object_handle; - return MTP_PHASE_RESPONSE; -} - -mtp_phase_type_t mtpd_handle_cmd_send_object(void) -{ - // Enter OUT phase and wait for DATA BLOCK - return MTP_PHASE_DATA_OUT; -} - -mtp_phase_type_t mtpd_handle_dto_send_object(void) -{ - mtp_generic_container_t* p_container = &_mtpd_epbuf.buf; - uint8_t *buffer = (uint8_t *)&p_container->data; - uint32_t buffer_size = _mtpd_itf.xferred_len - _mtpd_itf.handled_len; - // First block of DATA - if (_mtpd_itf.handled_len == 0) - { - buffer_size -= MTP_CONTAINER_HEADER_LENGTH; - } - - if (buffer_size > 0) - { - mtp_response_t res = tud_mtp_storage_object_write(_mtpd_soi.object_handle, buffer, buffer_size); - mtp_phase_type_t phase; - if ((phase = mtpd_chk_generic(__func__, (res != MTP_RESP_OK), res, "")) != MTP_PHASE_NONE) return phase; - } - - if (!_mtpd_itf.xfer_completed) - { - // Continue with next DATA BLOCK - return MTP_PHASE_DATA_OUT; - } - - // Send completed - tud_mtp_storage_object_done(); - - p_container->len = MTP_CONTAINER_HEADER_LENGTH; - p_container->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK; - p_container->code = MTP_RESP_OK; - return MTP_PHASE_RESPONSE; -} - mtp_phase_type_t mtpd_handle_cmd_format_store(void) { mtp_generic_container_t* p_container = &_mtpd_epbuf.buf; diff --git a/src/class/mtp/mtp_device.h b/src/class/mtp/mtp_device.h index 7b6ae9e0f..d0c894742 100644 --- a/src/class/mtp/mtp_device.h +++ b/src/class/mtp/mtp_device.h @@ -42,7 +42,7 @@ typedef struct { mtp_container_info_t io_container; tusb_xfer_result_t xfer_result; - uint32_t xferred_bytes; // number of bytes transferred so far in this phase + uint32_t total_xferred_bytes; // number of bytes transferred so far in this phase } tud_mtp_cb_data_t; // Number of supported operations, events, device properties, capture formats, playback formats |
