summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2025-09-25 17:43:25 +0700
committerhathach <[email protected]>2025-09-25 17:47:50 +0700
commitc9a8330081b59c05b901889d405ed7b9648c0947 (patch)
tree3b04636e06912d14ee5b7440e5ca5f6adca7933a /src
parentf8397717ea3f476c810ae3ce27ec4c866b305506 (diff)
implement send object command, able to create new file
Diffstat (limited to 'src')
-rw-r--r--src/class/mtp/mtp.h6
-rw-r--r--src/class/mtp/mtp_device.c183
-rw-r--r--src/class/mtp/mtp_device.h2
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