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 /src | |
| parent | f8397717ea3f476c810ae3ce27ec4c866b305506 (diff) | |
implement send object command, able to create new file
Diffstat (limited to 'src')
| -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 |
3 files changed, 29 insertions, 162 deletions
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 |
